[
  {
    "path": ".gitattributes",
    "content": "* text=auto\n\n/tests export-ignore\n/.gitattributes export-ignore\n/.gitignore export-ignore\n/.travis.yml export-ignore\n/phpunit.xml.dist export-ignore\n/readme.md export-ignore\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/laravel-9-updates.md",
    "content": "---\nname: Laravel 9 Updates\nabout: Inform about Laravel 9 changes\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n<!--\nNOTE: Laravel has incorporated this package into the core of Laravel as of Laravel 9.\n\nDo not use this package in Laravel 9. Details here: https://github.com/fideloper/TrustedProxy/issues/152\n-->\n"
  },
  {
    "path": ".github/workflows/tests.yml",
    "content": "# This is a basic workflow to help you get started with Actions\n\nname: Tests\n\n# Controls when the action will run. \non:\n  push:\n  pull_request:\n\n  # Allows you to run this workflow manually from the Actions tab\n  workflow_dispatch:\n\n# A workflow run is made up of one or more jobs that can run sequentially or in parallel\njobs:\n  # This workflow contains a single job called \"build\"\n  run_tests:\n    # The type of runner that the job will run on\n    runs-on: ubuntu-latest\n    \n    strategy:\n      fail-fast: true\n      matrix:\n        php: [7.2, 7.3, 7.4, 8.0, 8.1]\n   \n    name: PHP ${{ matrix.php }}\n\n    # Steps represent a sequence of tasks that will be executed as part of the job\n    steps:\n      # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it\n      - uses: actions/checkout@v2\n\n      - name: Checkout code\n        uses: actions/checkout@v2\n\n      - name: Setup PHP\n        uses: shivammathur/setup-php@v2\n        with:\n          php-version: ${{ matrix.php }}\n          extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite\n          tools: composer:v2\n          coverage: none\n\n      - name: Install dependencies\n        uses: nick-invision/retry@v1\n        with:\n          timeout_minutes: 5\n          max_attempts: 5\n          command: composer update --prefer-dist --no-interaction --no-progress\n\n      - name: Execute tests\n        run: vendor/bin/phpunit --verbose\n"
  },
  {
    "path": ".gitignore",
    "content": "/.idea\n/vendor\ncomposer.lock\nphpunit.xml\n.phpunit.result.cache\n"
  },
  {
    "path": "LICENSE.md",
    "content": "MIT License\n\nPermission 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:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "composer.json",
    "content": "{\n    \"name\": \"fideloper/proxy\",\n    \"description\": \"Set trusted proxies for Laravel\",\n    \"keywords\": [\"proxy\", \"trusted proxy\", \"load balancing\"],\n    \"license\": \"MIT\",\n    \"authors\": [\n        {\n            \"name\": \"Chris Fidao\",\n            \"email\": \"fideloper@gmail.com\"\n        }\n    ],\n    \"require\": {\n        \"php\": \">=5.4.0\",\n        \"illuminate/contracts\": \"^5.0|^6.0|^7.0|^8.0|^9.0\"\n    },\n    \"require-dev\": {\n        \"illuminate/http\": \"^5.0|^6.0|^7.0|^8.0|^9.0\",\n        \"mockery/mockery\": \"^1.0\",\n        \"phpunit/phpunit\": \"^8.5.8|^9.3.3\"\n    },\n    \"autoload\": {\n        \"psr-4\": {\n            \"Fideloper\\\\Proxy\\\\\": \"src/\"\n        }\n    },\n    \"extra\": {\n        \"laravel\": {\n            \"providers\": [\n                \"Fideloper\\\\Proxy\\\\TrustedProxyServiceProvider\"\n            ]\n        }\n    },\n    \"minimum-stability\": \"dev\",\n    \"prefer-stable\": true\n}\n"
  },
  {
    "path": "config/trustedproxy.php",
    "content": "<?php\n\nreturn [\n\n    /*\n     * Set trusted proxy IP addresses.\n     *\n     * Both IPv4 and IPv6 addresses are\n     * supported, along with CIDR notation.\n     *\n     * The \"*\" character is syntactic sugar\n     * within TrustedProxy to trust any proxy\n     * that connects directly to your server,\n     * a requirement when you cannot know the address\n     * of your proxy (e.g. if using ELB or similar).\n     *\n     */\n    'proxies' => null, // [<ip addresses>,], '*', '<ip addresses>,'\n\n    /*\n     * To trust one or more specific proxies that connect\n     * directly to your server, use an array or a string separated by comma of IP addresses:\n     */\n    // 'proxies' => ['192.168.1.1'],\n    // 'proxies' => '192.168.1.1, 192.168.1.2',\n\n    /*\n     * Or, to trust all proxies that connect\n     * directly to your server, use a \"*\"\n     */\n    // 'proxies' => '*',\n\n    /*\n     * Which headers to use to detect proxy related data (For, Host, Proto, Port)\n     *\n     * Options include:\n     *\n     * - All headers (see below) - Trust all x-forwarded-* headers\n     * - Illuminate\\Http\\Request::HEADER_FORWARDED - Use the FORWARDED header to establish trust\n     * - Illuminate\\Http\\Request::HEADER_X_FORWARDED_AWS_ELB - If you are using AWS Elastic Load Balancer\n     *\n     * @link https://symfony.com/doc/current/deployment/proxies.html\n     */\n    'headers' => Illuminate\\Http\\Request::HEADER_X_FORWARDED_FOR | Illuminate\\Http\\Request::HEADER_X_FORWARDED_HOST | Illuminate\\Http\\Request::HEADER_X_FORWARDED_PORT | Illuminate\\Http\\Request::HEADER_X_FORWARDED_PROTO | Illuminate\\Http\\Request::HEADER_X_FORWARDED_AWS_ELB,\n\n];\n"
  },
  {
    "path": "phpunit.xml.dist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<phpunit backupGlobals=\"false\"\n         backupStaticAttributes=\"false\"\n         beStrictAboutTestsThatDoNotTestAnything=\"false\"\n         bootstrap=\"vendor/autoload.php\"\n         colors=\"true\"\n         convertErrorsToExceptions=\"true\"\n         convertNoticesToExceptions=\"true\"\n         convertWarningsToExceptions=\"true\"\n         processIsolation=\"false\"\n         stopOnError=\"false\"\n         stopOnFailure=\"false\"\n         verbose=\"true\"\n>\n    <testsuites>\n        <testsuite name=\"Trusted Proxy Test Suite\">\n            <directory suffix=\".php\">./tests/</directory>\n        </testsuite>\n    </testsuites>\n</phpunit>\n"
  },
  {
    "path": "readme.md",
    "content": "# Laravel Trusted Proxies\n\n[![Build Status](https://github.com/fideloper/TrustedProxy/workflows/Tests/badge.svg)](https://github.com/fideloper/TrustedProxy/actions) [![Total Downloads](https://poser.pugx.org/fideloper/proxy/downloads.png)](https://packagist.org/packages/fideloper/proxy)\n\n**Setting a trusted proxy allows for correct URL generation, redirecting, session handling and logging in Laravel when behind a reverse proxy such as a load balancer or cache.**\n\n---\n\n## Installation\n\n**Laravel 5.5+ comes with this package**. If you are using Laravel 5.5 or greater, you **do not** need to add this to your project separately.\n\n* [Laravel 5.5](https://laravel.com/docs/5.5/requests#configuring-trusted-proxies) Docs (`fideloper/proxy:~3.3`)\n* [Laravel 5.6](https://laravel.com/docs/5.6/requests#configuring-trusted-proxies) Docs (`fideloper/proxy:^4.0`)\n* [Laravel 5.7](https://laravel.com/docs/5.7/requests#configuring-trusted-proxies) Docs (`fideloper/proxy:^4.0`)\n* [Laravel 5.8](https://laravel.com/docs/5.8/requests#configuring-trusted-proxies) Docs (`fideloper/proxy:^4.0`)\n* [Laravel 6.x](https://laravel.com/docs/6.x/requests#configuring-trusted-proxies) Docs (`fideloper/proxy:^4.0`)\n* [Laravel 7.x](https://laravel.com/docs/7.x/requests#configuring-trusted-proxies) Docs (`fideloper/proxy:^4.2`)\n* [Laravel 8.x](https://laravel.com/docs/8.x/requests#configuring-trusted-proxies) Docs (`fideloper/proxy:^4.3`)\n* [Laravel 9.x](https://laravel.com/docs/9.x/requests#configuring-trusted-proxies) Docs (**Don't use this package**. [Explanation here](https://github.com/fideloper/TrustedProxy/issues/152), [Upgrade docs here](https://laravel.com/docs/9.x/upgrade))\n\n### Laravel 5.0 - 5.4\n\nTo install Trusted Proxy, use:\n\n```\ncomposer require fideloper/proxy:^3.3\n```\n\n### Laravel 4\n\n```\ncomposer require fideloper/proxy:^2.0\n```\n\n## Setup\n\nRefer to the docs above for using Trusted Proxy in Laravel 5.5+. For Laravel 4.0 - 5.4, refer to [the wiki](https://github.com/fideloper/TrustedProxy/wiki).\n\n## What Does This Do?\n\nSetting a trusted proxy allows for correct URL generation, redirecting, session handling and logging in Laravel when behind a reverse proxy.\n\nThis is useful if your web servers sit behind a load balancer (Nginx, HAProxy, Envoy, ELB/ALB, etc), HTTP cache (CloudFlare, Squid, Varnish, etc), or other intermediary (reverse) proxy.\n\n## How Does This Work?\n\nApplications behind a reverse proxy typically read some HTTP headers such as `X-Forwarded`, `X-Forwarded-For`, `X-Forwarded-Proto` (and more) to know about the real end-client making an HTTP request.\n\n> If those headers were not set, then the application code would think every incoming HTTP request would be from the proxy.\n\nLaravel (technically the Symfony HTTP base classes) have a concept of a \"trusted proxy\", where those `X-Forwarded` headers will only be used if the source IP address of the request is known. In other words, it only trusts those headers if the proxy is trusted.\n\nThis package creates an easier interface to that option. You can set the IP addresses of the proxies (that the application would see, so it may be a private network IP address), and the Symfony HTTP classes will know to use the `X-Forwarded` headers if an HTTP requets containing those headers was from the trusted proxy.\n\n## Why Does This Matter?\n\nA very common load balancing approach is to send `https://` requests to a load balancer, but send `http://` requests to the application servers behind the load balancer.\n\nFor example, you may send a request in your browser to `https://example.org`. The load balancer, in turn, might send requests to an application server at `http://192.168.1.23`. \n\nWhat if that server returns a redirect, or generates an asset url? The users's browser would get back a redirect or HTML that includes `http://192.168.1.23` in it, which is clearly wrong.\n\nWhat happens is that the application thinks its hostname is `192.168.1.23` and the schema is `http://`. It doesn't know that the end client used `https://example.org` for its web request.\n\nSo the application needs to know to read the `X-Forwarded` headers to get the correct request details (schema `https://`, host `example.org`).\n\nLaravel/Symfony automatically reads those headers, but only if the trusted proxy configuration is set to \"trust\" the load balancer/reverse proxy.\n\n> Note: Many of us use hosted load balancers/proxies such as AWS ELB/ALB, etc. We don't know the IP address of those reverse proxies, and so you need to trusted **all** proxies in that case. \n> \n> The trade-off there is running the security risk of allowing people to potentially spoof the `X-Forwarded` headers.\n\n## IP Addresses by Service\n\n[This Wiki page](https://github.com/fideloper/TrustedProxy/wiki/IP-Addresses-of-Popular-Services) has a list of popular services and their IP addresses of their servers, if available. Any updates or suggestions are welcome!\n"
  },
  {
    "path": "src/TrustProxies.php",
    "content": "<?php\n\nnamespace Fideloper\\Proxy;\n\nuse Closure;\nuse Illuminate\\Http\\Request;\nuse Illuminate\\Contracts\\Config\\Repository;\n\nclass TrustProxies\n{\n    /**\n     * The config repository instance.\n     *\n     * @var \\Illuminate\\Contracts\\Config\\Repository\n     */\n    protected $config;\n\n    /**\n     * The trusted proxies for the application.\n     *\n     * @var null|string|array\n     */\n    protected $proxies;\n\n    /**\n     * The proxy header mappings.\n     *\n     * @var null|string|int\n     */\n    protected $headers;\n\n    /**\n     * Create a new trusted proxies middleware instance.\n     *\n     * @param \\Illuminate\\Contracts\\Config\\Repository $config\n     */\n    public function __construct(Repository $config)\n    {\n        $this->config = $config;\n    }\n\n    /**\n     * Handle an incoming request.\n     *\n     * @param \\Illuminate\\Http\\Request $request\n     * @param \\Closure                 $next\n     *\n     * @throws \\Symfony\\Component\\HttpKernel\\Exception\\HttpException\n     *\n     * @return mixed\n     */\n    public function handle(Request $request, Closure $next)\n    {\n        $request::setTrustedProxies([], $this->getTrustedHeaderNames()); // Reset trusted proxies between requests\n        $this->setTrustedProxyIpAddresses($request);\n\n        return $next($request);\n    }\n\n    /**\n     * Sets the trusted proxies on the request to the value of trustedproxy.proxies\n     *\n     * @param \\Illuminate\\Http\\Request $request\n     */\n    protected function setTrustedProxyIpAddresses(Request $request)\n    {\n        $trustedIps = $this->proxies ?: $this->config->get('trustedproxy.proxies');\n\n        // Trust any IP address that calls us\n        // `**` for backwards compatibility, but is deprecated\n        if ($trustedIps === '*' || $trustedIps === '**') {\n            return $this->setTrustedProxyIpAddressesToTheCallingIp($request);\n        }\n\n        // Support IPs addresses separated by comma\n        $trustedIps = is_string($trustedIps) ? array_map('trim', explode(',', $trustedIps)) : $trustedIps;\n\n        // Only trust specific IP addresses\n        if (is_array($trustedIps)) {\n            return $this->setTrustedProxyIpAddressesToSpecificIps($request, $trustedIps);\n        }\n    }\n\n    /**\n     * Specify the IP addresses to trust explicitly.\n     *\n     * @param \\Illuminate\\Http\\Request $request\n     * @param array                    $trustedIps\n     */\n    private function setTrustedProxyIpAddressesToSpecificIps(Request $request, $trustedIps)\n    {\n        $request->setTrustedProxies((array) $trustedIps, $this->getTrustedHeaderNames());\n    }\n\n    /**\n     * Set the trusted proxy to be the IP address calling this servers\n     *\n     * @param \\Illuminate\\Http\\Request $request\n     */\n    private function setTrustedProxyIpAddressesToTheCallingIp(Request $request)\n    {\n        $request->setTrustedProxies([$request->server->get('REMOTE_ADDR')], $this->getTrustedHeaderNames());\n    }\n\n    /**\n     * Retrieve trusted header name(s), falling back to defaults if config not set.\n     *\n     * @return int A bit field of Request::HEADER_*, to set which headers to trust from your proxies.\n     */\n    protected function getTrustedHeaderNames()\n    {\n        $headers = $this->headers ?: $this->config->get('trustedproxy.headers');\n        switch ($headers) {\n            case 'HEADER_X_FORWARDED_AWS_ELB':\n            case Request::HEADER_X_FORWARDED_AWS_ELB:\n                return Request::HEADER_X_FORWARDED_AWS_ELB;\n                break;\n            case 'HEADER_FORWARDED':\n            case Request::HEADER_FORWARDED:\n                return Request::HEADER_FORWARDED;\n                break;\n            case 'HEADER_X_FORWARDED_FOR':\n            case Request::HEADER_X_FORWARDED_FOR:\n                return Request::HEADER_X_FORWARDED_FOR;\n                break;\n            case 'HEADER_X_FORWARDED_HOST':\n            case Request::HEADER_X_FORWARDED_HOST:\n                return Request::HEADER_X_FORWARDED_HOST;\n                break;\n            case 'HEADER_X_FORWARDED_PORT':\n            case Request::HEADER_X_FORWARDED_PORT:\n                return Request::HEADER_X_FORWARDED_PORT;\n                break;\n            case 'HEADER_X_FORWARDED_PROTO':\n            case Request::HEADER_X_FORWARDED_PROTO:\n                return Request::HEADER_X_FORWARDED_PROTO;\n                break;\n            default:\n                return Request::HEADER_X_FORWARDED_FOR | Request::HEADER_X_FORWARDED_HOST | Request::HEADER_X_FORWARDED_PORT | Request::HEADER_X_FORWARDED_PROTO | Request::HEADER_X_FORWARDED_AWS_ELB;\n        }\n\n        return $headers;\n    }\n}\n"
  },
  {
    "path": "src/TrustedProxyServiceProvider.php",
    "content": "<?php\n\nnamespace Fideloper\\Proxy;\n\nuse Illuminate\\Foundation\\Application as LaravelApplication;\nuse Illuminate\\Support\\ServiceProvider;\nuse Laravel\\Lumen\\Application as LumenApplication;\n\nclass TrustedProxyServiceProvider extends ServiceProvider\n{\n    /**\n     * Boot the service provider.\n     *\n     * @return void\n     */\n    public function boot()\n    {\n        $source = realpath($raw = __DIR__.'/../config/trustedproxy.php') ?: $raw;\n\n        if ($this->app instanceof LaravelApplication && $this->app->runningInConsole()) {\n            $this->publishes([$source => config_path('trustedproxy.php')]);\n        } elseif ($this->app instanceof LumenApplication) {\n            $this->app->configure('trustedproxy');\n        }\n\n\n        if ($this->app instanceof LaravelApplication && ! $this->app->configurationIsCached()) {\n            $this->mergeConfigFrom($source, 'trustedproxy');\n        }\n    }\n\n    /**\n     * Register the service provider.\n     *\n     * @return void\n     */\n    public function register()\n    {\n        //\n    }\n}\n"
  },
  {
    "path": "tests/TrustedProxyTest.php",
    "content": "<?php\n\nuse Illuminate\\Http\\Request;\nuse PHPUnit\\Framework\\TestCase;\nuse Fideloper\\Proxy\\TrustProxies;\n\nclass TrustedProxyTest extends TestCase\n{\n    private $headerAll = Request::HEADER_X_FORWARDED_FOR | Request::HEADER_X_FORWARDED_HOST | Request::HEADER_X_FORWARDED_PORT | Request::HEADER_X_FORWARDED_PROTO | Request::HEADER_X_FORWARDED_AWS_ELB;\n\n    /**\n     * Test that Symfony does indeed NOT trust X-Forwarded-*\n     * headers when not given trusted proxies\n     *\n     * This re-tests Symfony's Request class, but hopefully provides\n     * some clarify to developers looking at the tests.\n     *\n     * Also, thanks for looking at the tests.\n     */\n    public function test_request_does_not_trust()\n    {\n        $req = $this->createProxiedRequest();\n\n        $this->assertEquals('192.168.10.10', $req->getClientIp(), 'Assert untrusted proxy x-forwarded-for header not used');\n        $this->assertEquals('http', $req->getScheme(), 'Assert untrusted proxy x-forwarded-proto header not used');\n        $this->assertEquals('localhost', $req->getHost(), 'Assert untrusted proxy x-forwarded-host header not used');\n        $this->assertEquals(8888, $req->getPort(), 'Assert untrusted proxy x-forwarded-port header not used');\n    }\n\n    /**\n     * Test that Symfony DOES indeed trust X-Forwarded-*\n     * headers when given trusted proxies\n     *\n     * Again, this re-tests Symfony's Request class.\n     */\n    public function test_does_trust_trusted_proxy()\n    {\n        $req = $this->createProxiedRequest();\n        $req->setTrustedProxies(['192.168.10.10'], $this->headerAll);\n\n        $this->assertEquals('173.174.200.38', $req->getClientIp(), 'Assert trusted proxy x-forwarded-for header used');\n        $this->assertEquals('https', $req->getScheme(), 'Assert trusted proxy x-forwarded-proto header used');\n        $this->assertEquals('serversforhackers.com', $req->getHost(), 'Assert trusted proxy x-forwarded-host header used');\n        $this->assertEquals(443, $req->getPort(), 'Assert trusted proxy x-forwarded-port header used');\n    }\n\n    /**\n     * Test the next most typical usage of TrustedProxies:\n     * Trusted X-Forwarded-For header, wilcard for TrustedProxies\n     */\n    public function test_trusted_proxy_sets_trusted_proxies_with_wildcard()\n    {\n        $trustedProxy = $this->createTrustedProxy($this->headerAll, '*');\n        $request = $this->createProxiedRequest();\n\n        $trustedProxy->handle($request, function ($request) {\n            $this->assertEquals('173.174.200.38', $request->getClientIp(), 'Assert trusted proxy x-forwarded-for header used with wildcard proxy setting');\n        });\n    }\n\n    /**\n     * Test the next most typical usage of TrustedProxies:\n     * Trusted X-Forwarded-For header, wilcard for TrustedProxies\n     */\n    public function test_trusted_proxy_sets_trusted_proxies_with_double_wildcard_for_backwards_compat()\n    {\n        $trustedProxy = $this->createTrustedProxy($this->headerAll, '**');\n        $request = $this->createProxiedRequest();\n\n        $trustedProxy->handle($request, function ($request) {\n            $this->assertEquals('173.174.200.38', $request->getClientIp(), 'Assert trusted proxy x-forwarded-for header used with wildcard proxy setting');\n        });\n    }\n\n    /**\n     * Test the most typical usage of TrustProxies:\n     * Trusted X-Forwarded-For header\n     */\n    public function test_trusted_proxy_sets_trusted_proxies()\n    {\n        $trustedProxy = $this->createTrustedProxy($this->headerAll, ['192.168.10.10']);\n        $request = $this->createProxiedRequest();\n\n        $trustedProxy->handle($request, function ($request) {\n            $this->assertEquals('173.174.200.38', $request->getClientIp(), 'Assert trusted proxy x-forwarded-for header used');\n        });\n    }\n\n    /**\n     * Test X-Forwarded-For header with multiple IP addresses\n     */\n    public function test_get_client_ips()\n    {\n        $trustedProxy = $this->createTrustedProxy($this->headerAll, ['192.168.10.10']);\n\n        $forwardedFor = [\n            '192.0.2.2',\n            '192.0.2.2, 192.0.2.199',\n            '192.0.2.2, 192.0.2.199, 99.99.99.99',\n            '192.0.2.2,192.0.2.199',\n        ];\n\n        foreach($forwardedFor as $forwardedForHeader) {\n            $request = $this->createProxiedRequest(['HTTP_X_FORWARDED_FOR' => $forwardedForHeader]);\n\n            $trustedProxy->handle($request, function ($request) use ($forwardedForHeader) {\n                $ips = $request->getClientIps();\n                $this->assertEquals('192.0.2.2', end($ips), 'Assert sets the '.$forwardedForHeader);\n            });\n        }\n    }\n\n    /**\n     * Test X-Forwarded-For header with multiple IP addresses, with some of those being trusted\n     */\n    public function test_get_client_ip_with_muliple_ip_addresses_some_of_which_are_trusted()\n    {\n        $trustedProxy = $this->createTrustedProxy($this->headerAll, ['192.168.10.10', '192.0.2.199']);\n\n        $forwardedFor = [\n            '192.0.2.2',\n            '192.0.2.2, 192.0.2.199',\n            '99.99.99.99, 192.0.2.2, 192.0.2.199',\n            '192.0.2.2,192.0.2.199',\n        ];\n\n        foreach($forwardedFor as $forwardedForHeader) {\n            $request = $this->createProxiedRequest(['HTTP_X_FORWARDED_FOR' => $forwardedForHeader]);\n\n            $trustedProxy->handle($request, function ($request) use ($forwardedForHeader) {\n                $this->assertEquals('192.0.2.2', $request->getClientIp(), 'Assert sets the '.$forwardedForHeader);\n            });\n        }\n    }\n\n    /**\n     * Test X-Forwarded-For header with multiple IP addresses, with * wildcard trusting of all proxies\n     */\n    public function test_get_client_ip_with_muliple_ip_addresses_all_proxies_are_trusted()\n    {\n        $trustedProxy = $this->createTrustedProxy($this->headerAll, '*');\n\n        $forwardedFor = [\n            '192.0.2.2',\n            '192.0.2.199, 192.0.2.2',\n            '192.0.2.199,192.0.2.2',\n            '99.99.99.99,192.0.2.199,192.0.2.2',\n        ];\n\n        foreach($forwardedFor as $forwardedForHeader) {\n            $request = $this->createProxiedRequest(['HTTP_X_FORWARDED_FOR' => $forwardedForHeader]);\n\n            $trustedProxy->handle($request, function ($request) use ($forwardedForHeader) {\n                $this->assertEquals('192.0.2.2', $request->getClientIp(), 'Assert sets the '.$forwardedForHeader);\n            });\n        }\n    }\n\n    /**\n     * Test distrusting a header.\n     */\n    public function test_can_distrust_headers()\n    {\n        $trustedProxy = $this->createTrustedProxy(Request::HEADER_FORWARDED, ['192.168.10.10']);\n\n        $request = $this->createProxiedRequest([\n            'HTTP_FORWARDED' => 'for=173.174.200.40:443; proto=https; host=serversforhackers.com',\n            'HTTP_X_FORWARDED_FOR' => '173.174.200.38',\n            'HTTP_X_FORWARDED_HOST' => 'svrs4hkrs.com',\n            'HTTP_X_FORWARDED_PORT' => '80',\n            'HTTP_X_FORWARDED_PROTO' => 'http',\n        ]);\n\n        $trustedProxy->handle($request, function ($request) {\n            $this->assertEquals('173.174.200.40', $request->getClientIp(),\n                'Assert trusted proxy used forwarded header for IP');\n            $this->assertEquals('https', $request->getScheme(),\n                'Assert trusted proxy used forwarded header for scheme');\n            $this->assertEquals('serversforhackers.com', $request->getHost(),\n                'Assert trusted proxy used forwarded header for host');\n            $this->assertEquals(443, $request->getPort(), 'Assert trusted proxy used forwarded header for port');\n        });\n    }\n\n    /**\n     * Test that only the X-Forwarded-For header is trusted.\n     */\n    public function test_x_forwarded_for_header_only_trusted()\n    {\n        $trustedProxy = $this->createTrustedProxy(Request::HEADER_X_FORWARDED_FOR, '*');\n\n        $request = $this->createProxiedRequest();\n\n        $trustedProxy->handle($request, function ($request) {\n            $this->assertEquals('173.174.200.38', $request->getClientIp(),\n                'Assert trusted proxy used forwarded header for IP');\n            $this->assertEquals('http', $request->getScheme(),\n                'Assert trusted proxy did not use forwarded header for scheme');\n            $this->assertEquals('localhost', $request->getHost(),\n                'Assert trusted proxy did not use forwarded header for host');\n            $this->assertEquals(8888, $request->getPort(), 'Assert trusted proxy did not use forwarded header for port');\n        });\n    }\n\n    /**\n     * Test that only the X-Forwarded-Host header is trusted.\n     */\n    public function test_x_forwarded_host_header_only_trusted()\n    {\n        $trustedProxy = $this->createTrustedProxy(Request::HEADER_X_FORWARDED_HOST, '*');\n\n        $request = $this->createProxiedRequest(['HTTP_X_FORWARDED_HOST' => 'serversforhackers.com:8888']);\n\n        $trustedProxy->handle($request, function ($request) {\n            $this->assertEquals('192.168.10.10', $request->getClientIp(),\n                'Assert trusted proxy did not use forwarded header for IP');\n            $this->assertEquals('http', $request->getScheme(),\n                'Assert trusted proxy did not use forwarded header for scheme');\n            $this->assertEquals('serversforhackers.com', $request->getHost(),\n                'Assert trusted proxy used forwarded header for host');\n            $this->assertEquals(8888, $request->getPort(), 'Assert trusted proxy did not use forwarded header for port');\n        });\n    }\n\n    /**\n     * Test that only the X-Forwarded-Port header is trusted.\n     */\n    public function test_x_forwarded_port_header_only_trusted()\n    {\n        $trustedProxy = $this->createTrustedProxy(Request::HEADER_X_FORWARDED_PORT, '*');\n\n        $request = $this->createProxiedRequest();\n\n        $trustedProxy->handle($request, function ($request) {\n            $this->assertEquals('192.168.10.10', $request->getClientIp(),\n                'Assert trusted proxy did not use forwarded header for IP');\n            $this->assertEquals('http', $request->getScheme(),\n                'Assert trusted proxy did not use forwarded header for scheme');\n            $this->assertEquals('localhost', $request->getHost(),\n                'Assert trusted proxy did not use forwarded header for host');\n            $this->assertEquals(443, $request->getPort(), 'Assert trusted proxy used forwarded header for port');\n        });\n    }\n\n    /**\n     * Test that only the X-Forwarded-Proto header is trusted.\n     */\n    public function test_x_forwarded_proto_header_only_trusted()\n    {\n        $trustedProxy = $this->createTrustedProxy(Request::HEADER_X_FORWARDED_PROTO, '*');\n\n        $request = $this->createProxiedRequest();\n\n        $trustedProxy->handle($request, function ($request) {\n            $this->assertEquals('192.168.10.10', $request->getClientIp(),\n                'Assert trusted proxy did not use forwarded header for IP');\n            $this->assertEquals('https', $request->getScheme(),\n                'Assert trusted proxy used forwarded header for scheme');\n            $this->assertEquals('localhost', $request->getHost(),\n                'Assert trusted proxy did not use forwarded header for host');\n            $this->assertEquals(8888, $request->getPort(), 'Assert trusted proxy did not use forwarded header for port');\n        });\n    }\n\n    /**\n     * Test a combination of individual X-Forwarded-* headers are trusted.\n     */\n    public function test_x_forwarded_multiple_individual_headers_trusted()\n    {\n        $trustedProxy = $this->createTrustedProxy(\n            Request::HEADER_X_FORWARDED_FOR | Request::HEADER_X_FORWARDED_HOST |\n            Request::HEADER_X_FORWARDED_PORT | Request::HEADER_X_FORWARDED_PROTO,\n            '*'\n        );\n\n        $request = $this->createProxiedRequest();\n\n        $trustedProxy->handle($request, function ($request) {\n            $this->assertEquals('173.174.200.38', $request->getClientIp(),\n                'Assert trusted proxy used forwarded header for IP');\n            $this->assertEquals('https', $request->getScheme(),\n                'Assert trusted proxy used forwarded header for scheme');\n            $this->assertEquals('serversforhackers.com', $request->getHost(),\n                'Assert trusted proxy used forwarded header for host');\n            $this->assertEquals(443, $request->getPort(), 'Assert trusted proxy used forwarded header for port');\n        });\n    }\n\n    /**\n     * Test to ensure it's reading text-based configurations and converting it correctly.\n     */\n    public function test_is_reading_text_based_configurations()\n    {\n        $request = $this->createProxiedRequest();\n\n        // trust *all* \"X-Forwarded-*\" headers\n        $trustedProxy = $this->createTrustedProxy('HEADER_X_FORWARDED_ALL', '192.168.1.1, 192.168.1.2');\n        $trustedProxy->handle($request, function (Request $request) {\n            $this->assertEquals($request->getTrustedHeaderSet(), $this->headerAll,\n                'Assert trusted proxy used all \"X-Forwarded-*\" header');\n\n            $this->assertEquals($request->getTrustedProxies(), ['192.168.1.1', '192.168.1.2'],\n                'Assert trusted proxy using proxies as string separated by comma.');\n        });\n\n        // or, if your proxy instead uses the \"Forwarded\" header\n        $trustedProxy = $this->createTrustedProxy('HEADER_FORWARDED', '192.168.1.1, 192.168.1.2');\n        $trustedProxy->handle($request, function (Request $request) {\n            $this->assertEquals($request->getTrustedHeaderSet(), Request::HEADER_FORWARDED,\n                'Assert trusted proxy used forwarded header');\n\n            $this->assertEquals($request->getTrustedProxies(), ['192.168.1.1', '192.168.1.2'],\n                'Assert trusted proxy using proxies as string separated by comma.');\n        });\n\n        // or, if you're using AWS ELB\n        $trustedProxy = $this->createTrustedProxy('HEADER_X_FORWARDED_AWS_ELB', '192.168.1.1, 192.168.1.2');\n        $trustedProxy->handle($request, function (Request $request) {\n            $this->assertEquals($request->getTrustedHeaderSet(), Request::HEADER_X_FORWARDED_AWS_ELB,\n                'Assert trusted proxy used AWS ELB header');\n\n            $this->assertEquals($request->getTrustedProxies(), ['192.168.1.1', '192.168.1.2'],\n                'Assert trusted proxy using proxies as string separated by comma.');\n        });\n    }\n\n    ################################################################\n    # Utility Functions\n    ################################################################\n\n    /**\n     * Fake an HTTP request by generating a Symfony Request object.\n     *\n     * @param array $serverOverRides\n     *\n     * @return \\Symfony\\Component\\HttpFoundation\\Request\n     */\n    protected function createProxiedRequest($serverOverRides = [])\n    {\n        // Add some X-Forwarded headers and over-ride\n        // defaults, simulating a request made over a proxy\n        $serverOverRides = array_replace([\n            'HTTP_X_FORWARDED_FOR' => '173.174.200.38',         // X-Forwarded-For   -- getClientIp()\n            'HTTP_X_FORWARDED_HOST' => 'serversforhackers.com', // X-Forwarded-Host  -- getHosts()\n            'HTTP_X_FORWARDED_PORT' => '443',                   // X-Forwarded-Port  -- getPort()\n            'HTTP_X_FORWARDED_PROTO' => 'https',                // X-Forwarded-Proto -- getScheme() / isSecure()\n            'SERVER_PORT' => 8888,\n            'HTTP_HOST' => 'localhost',\n            'REMOTE_ADDR' => '192.168.10.10',\n        ], $serverOverRides);\n\n        // Create a fake request made over \"http\", one that we'd get over a proxy\n        // which is likely something like this:\n        $request = Request::create('http://localhost:8888/tag/proxy', 'GET', [], [], [], $serverOverRides, null);\n        // Need to make sure these haven't already been set\n        $request->setTrustedProxies([], $this->headerAll);\n\n        return $request;\n    }\n\n    /**\n     * Retrieve a TrustProxies object, with dependencies mocked.\n     *\n     * @param null|string|int $trustedHeaders\n     * @param null|array|string $trustedProxies\n     *\n     * @return \\Fideloper\\Proxy\\TrustProxies\n     */\n    protected function createTrustedProxy($trustedHeaders, $trustedProxies)\n    {\n        // Mock TrustProxies dependencies and calls for config values\n        $config = Mockery::mock('Illuminate\\Contracts\\Config\\Repository')\n            ->shouldReceive('get')\n            ->with('trustedproxy.headers')\n            ->andReturn($trustedHeaders)\n            ->shouldReceive('get')\n            ->with('trustedproxy.proxies')\n            ->andReturn($trustedProxies)\n            ->getMock();\n\n        return new TrustProxies($config);\n    }\n}\n"
  }
]