From f5559e2598f6bf3690ab563d45a7f3f5d7efc147 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Maximilian=20B=C3=B6sing?=
 <2189546+boesing@users.noreply.github.com>
Date: Tue, 5 Nov 2019 19:53:41 +0100
Subject: [PATCH 01/10] Added failing unit test for `X-Forwarded-Host`

---
 test/functions/MarshalUriFromSapiTest.php | 32 +++++++++++++++++++++++
 1 file changed, 32 insertions(+)

diff --git a/test/functions/MarshalUriFromSapiTest.php b/test/functions/MarshalUriFromSapiTest.php
index 94fab436..9a44bfa3 100644
--- a/test/functions/MarshalUriFromSapiTest.php
+++ b/test/functions/MarshalUriFromSapiTest.php
@@ -74,4 +74,36 @@ public function returnsUrlWithCorrectHttpSchemeFromArraysProvider() : array
             'empty' => ['', 'http'],
         ];
     }
+
+    /**
+     * @dataProvider returnsUrlWithCorrectSchemeAndHostFromArrays
+     */
+    public function testReturnsUrlWithCorrectSchemeAndHostFromArrays(string $expectedScheme, string $expectedHost, array $server, array $headers) : void
+    {
+        $uri = marshalUriFromSapi($server, $headers);
+        self::assertSame($expectedScheme, $uri->getScheme());
+        self::assertSame($expectedHost, $uri->getHost());
+    }
+
+    public function returnsUrlWithCorrectSchemeAndHostFromArrays() : array
+    {
+        return [
+            'x-forwarded-proto' => [
+                'https',
+                'localhost',
+                [
+                    'SERVER_NAME' => 'localhost',
+                ],
+                ['X-Forwarded-Proto' => 'https'],
+            ],
+            'x-forwarded-host' => [
+                'http',
+                'example.org',
+                [
+                    'SERVER_NAME' => 'localhost',
+                ],
+                ['X-Forwarded-Host' => 'example.org'],
+            ],
+        ];
+    }
 }

From c7599174965cd50e00287fe7b34987ef95fa7239 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Maximilian=20B=C3=B6sing?=
 <2189546+boesing@users.noreply.github.com>
Date: Tue, 5 Nov 2019 19:59:11 +0100
Subject: [PATCH 02/10] Just to make sure there is no fallback to `Host`

---
 test/functions/MarshalUriFromSapiTest.php | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/test/functions/MarshalUriFromSapiTest.php b/test/functions/MarshalUriFromSapiTest.php
index 9a44bfa3..8da8899c 100644
--- a/test/functions/MarshalUriFromSapiTest.php
+++ b/test/functions/MarshalUriFromSapiTest.php
@@ -102,7 +102,7 @@ public function returnsUrlWithCorrectSchemeAndHostFromArrays() : array
                 [
                     'SERVER_NAME' => 'localhost',
                 ],
-                ['X-Forwarded-Host' => 'example.org'],
+                ['X-Forwarded-Host' => 'example.org', 'Host' => 'localhost'],
             ],
         ];
     }

From 603d4a8084c3a9d190dc802179f7b232415c5b93 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Maximilian=20B=C3=B6sing?=
 <2189546+boesing@users.noreply.github.com>
Date: Wed, 6 Nov 2019 11:36:04 +0100
Subject: [PATCH 03/10] Added `X-Forwarded-Host` header awareness and prefer it
 over `Host`

---
 src/functions/marshal_uri_from_sapi.php | 14 ++++++++++----
 1 file changed, 10 insertions(+), 4 deletions(-)

diff --git a/src/functions/marshal_uri_from_sapi.php b/src/functions/marshal_uri_from_sapi.php
index 9d4de236..bc6545c7 100644
--- a/src/functions/marshal_uri_from_sapi.php
+++ b/src/functions/marshal_uri_from_sapi.php
@@ -80,7 +80,7 @@ function marshalUriFromSapi(array $server, array $headers) : Uri
         * @return array Array of two items, host and port, in that order (can be
         *     passed to a list() operation).
         */
-        $marshalIpv6HostAndPort = function (array $server, string $host, ?int $port) : array {
+        $marshalIpv6HostAndPort = function (array $server, ?int $port) : array {
             $host = '[' . $server['SERVER_ADDR'] . ']';
             $port = $port ?: 80;
             if ($port . ']' === substr($host, strrpos($host, ':') + 1)) {
@@ -93,8 +93,14 @@ function marshalUriFromSapi(array $server, array $headers) : Uri
 
         static $defaults = ['', null];
 
-        if ($getHeaderFromArray('host', $headers, false)) {
-            return $marshalHostAndPortFromHeader($getHeaderFromArray('host', $headers));
+        $forwardedHost = $getHeaderFromArray('x-forwarded-host', $headers, false);
+        if ($forwardedHost !== false) {
+            return $marshalHostAndPortFromHeader($forwardedHost);
+        }
+
+        $host = $getHeaderFromArray('host', $headers, false);
+        if ($host !== false) {
+            return $marshalHostAndPortFromHeader($host);
         }
 
         if (! isset($server['SERVER_NAME'])) {
@@ -112,7 +118,7 @@ function marshalUriFromSapi(array $server, array $headers) : Uri
 
         // Misinterpreted IPv6-Address
         // Reported for Safari on Windows
-        return $marshalIpv6HostAndPort($server, $host, $port);
+        return $marshalIpv6HostAndPort($server, $port);
     };
 
     /**

From 6f68fc4ecd260b66865eedd84876aebf23d669ae Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Maximilian=20B=C3=B6sing?=
 <2189546+boesing@users.noreply.github.com>
Date: Wed, 6 Nov 2019 11:38:51 +0100
Subject: [PATCH 04/10] Fixed codestyle issue with >120 chars per line

---
 test/functions/MarshalUriFromSapiTest.php | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/test/functions/MarshalUriFromSapiTest.php b/test/functions/MarshalUriFromSapiTest.php
index 8da8899c..bb3ed8b6 100644
--- a/test/functions/MarshalUriFromSapiTest.php
+++ b/test/functions/MarshalUriFromSapiTest.php
@@ -78,8 +78,12 @@ public function returnsUrlWithCorrectHttpSchemeFromArraysProvider() : array
     /**
      * @dataProvider returnsUrlWithCorrectSchemeAndHostFromArrays
      */
-    public function testReturnsUrlWithCorrectSchemeAndHostFromArrays(string $expectedScheme, string $expectedHost, array $server, array $headers) : void
-    {
+    public function testReturnsUrlWithCorrectSchemeAndHostFromArrays(
+        string $expectedScheme,
+        string $expectedHost,
+        array $server,
+        array $headers
+    ) : void {
         $uri = marshalUriFromSapi($server, $headers);
         self::assertSame($expectedScheme, $uri->getScheme());
         self::assertSame($expectedHost, $uri->getHost());

From 8db5e632c59191c586b99e85949b3386aedfdab6 Mon Sep 17 00:00:00 2001
From: Matthew Weier O'Phinney <matthew@weierophinney.net>
Date: Tue, 12 Nov 2019 11:13:39 -0600
Subject: [PATCH 05/10] docs: adds CHANGELOG entry for #376

---
 CHANGELOG.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4c3a581c..4d9a5f5a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,7 +6,7 @@ All notable changes to this project will be documented in this file, in reverse
 
 ### Added
 
-- Nothing.
+- [#376](https://github.com/zendframework/zend-diactoros/pull/376) adds support for using the X-Forwarded-Host header for determining the originally requested host name when marshaling the server request.
 
 ### Changed
 

From bfe7a22944fe876ba3bc7648301c3c184f5be229 Mon Sep 17 00:00:00 2001
From: "Matthew J. Sahagian" <matthew.sahagian@gmail.com>
Date: Fri, 8 Nov 2019 11:36:38 -0800
Subject: [PATCH 06/10] Making UploadedFile extend SplFileInfo

---
 src/UploadedFile.php | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/src/UploadedFile.php b/src/UploadedFile.php
index 2f4d87f1..a28b7af5 100644
--- a/src/UploadedFile.php
+++ b/src/UploadedFile.php
@@ -9,6 +9,7 @@
 
 namespace Zend\Diactoros;
 
+use SplFileInfo;
 use Psr\Http\Message\StreamInterface;
 use Psr\Http\Message\UploadedFileInterface;
 
@@ -35,7 +36,7 @@
 use const UPLOAD_ERR_OK;
 use const UPLOAD_ERR_PARTIAL;
 
-class UploadedFile implements UploadedFileInterface
+class UploadedFile extends SplFileInfo implements UploadedFileInterface
 {
     const ERROR_MESSAGES = [
         UPLOAD_ERR_OK         => 'There is no error, the file uploaded with success',
@@ -102,9 +103,13 @@ public function __construct(
         if ($errorStatus === UPLOAD_ERR_OK) {
             if (is_string($streamOrFile)) {
                 $this->file = $streamOrFile;
+
+                parent::__construct($this->file);
             }
             if (is_resource($streamOrFile)) {
                 $this->stream = new Stream($streamOrFile);
+
+                parent::__construct($this->stream->getMetaData('uri'));
             }
 
             if (! $this->file && ! $this->stream) {

From d4dec997b473e880f6d43b11dc8445db0217cac1 Mon Sep 17 00:00:00 2001
From: "Matthew J. Sahagian" <matthew.sahagian@gmail.com>
Date: Fri, 8 Nov 2019 11:51:37 -0800
Subject: [PATCH 07/10] Changelog + doc changes

---
 CHANGELOG.md        | 26 ++++++++++++++++++++++++--
 docs/book/v2/api.md |  2 ++
 2 files changed, 26 insertions(+), 2 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4d9a5f5a..86654312 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,7 +2,7 @@
 
 All notable changes to this project will be documented in this file, in reverse chronological order by release.
 
-## 2.2.0 - TBD
+## 2.2.1 - TBD
 
 ### Added
 
@@ -24,6 +24,28 @@ All notable changes to this project will be documented in this file, in reverse
 
 - Nothing.
 
+## 2.2.0  - 2019-11-08
+
+### Added
+
+- [#377](https://github.com/zendframework/zend-diactoros/issues/377) enables UploadedFile to stand in and be used as an SplFileInfo object.
+
+### Changed
+
+- Nothing.
+
+### Deprecated
+
+- Nothing.
+
+### Removed
+
+- Nothing.
+
+### Fixed
+
+- Nothing.
+
 ## 2.1.6 - TBD
 
 ### Added
@@ -641,7 +663,7 @@ All notable changes to this project will be documented in this file, in reverse
 
 - [#293](https://github.com/zendframework/zend-diactoros/pull/293) updates
   `Uri::getHost()` to cast the value via `strtolower()` before returning it.
-  While this represents a change, it is fixing a bug in our implementation: 
+  While this represents a change, it is fixing a bug in our implementation:
   the PSR-7 specification for the method, which follows IETF RFC 3986 section
   3.2.2, requires that the host name be normalized to lowercase.
 
diff --git a/docs/book/v2/api.md b/docs/book/v2/api.md
index a37cfb46..7dd3b2f6 100644
--- a/docs/book/v2/api.md
+++ b/docs/book/v2/api.md
@@ -194,4 +194,6 @@ In most cases, you will not interact with the Stream object directly.
 and provides abstraction around a single uploaded file, including behavior for interacting with it
 as a stream or moving it to a filesystem location.
 
+Additionally, it extends PHP's build in `SplFileInfo` object in order to provide a compatible interface wherever such an object is needed.
+
 In most cases, you will only use the methods defined in the `UploadedFileInterface`.

From f38c319dd284b18fd47f9b83affd41402fba97b2 Mon Sep 17 00:00:00 2001
From: Matthew Weier O'Phinney <matthew@weierophinney.net>
Date: Tue, 12 Nov 2019 11:18:02 -0600
Subject: [PATCH 08/10] qa: adds tests for #378

---
 test/UploadedFileTest.php | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/test/UploadedFileTest.php b/test/UploadedFileTest.php
index 35ab5edb..80e90eb8 100644
--- a/test/UploadedFileTest.php
+++ b/test/UploadedFileTest.php
@@ -13,6 +13,7 @@
 use PHPUnit\Framework\TestCase;
 use ReflectionProperty;
 use RuntimeException;
+use SplFileInfo;
 use Zend\Diactoros\Stream;
 use Zend\Diactoros\UploadedFile;
 
@@ -325,4 +326,13 @@ public function testMoveToRaisesExceptionWithAppropriateMessageWhenUploadErrorDe
         $this->expectExceptionMessage($message);
         $uploadedFile->moveTo('/tmp/foo');
     }
+
+    /**
+     * @see https://github.com/zendframework/zend-diactoros/pull/378
+     */
+    public function testExtendsSplFileInfo()
+    {
+        $uploaded = new UploadedFile(fopen('php://temp', 'wb+'), 0, UPLOAD_ERR_OK);
+        $this->assertInstanceOf(SplFileInfo::class, $uploaded);
+    }
 }

From b6d4ed1d97083bb4d3240a65272bf38748bd6d45 Mon Sep 17 00:00:00 2001
From: Matthew Weier O'Phinney <matthew@weierophinney.net>
Date: Tue, 12 Nov 2019 11:21:38 -0600
Subject: [PATCH 09/10] docs: adds CHANGELOG entry for #378

---
 CHANGELOG.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 86654312..379616ed 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -10,7 +10,7 @@ All notable changes to this project will be documented in this file, in reverse
 
 ### Changed
 
-- Nothing.
+- [#378](https://github.com/zendframework/zend-diactoros/pull/378) updates the `UploadedFile` class to extend `SplFileInfo`, allowing developers to make use of those features in their applications.
 
 ### Deprecated
 

From 15af09fe4a72a3d92c635de7a407b2b03d03bda8 Mon Sep 17 00:00:00 2001
From: Matthew Weier O'Phinney <matthew@weierophinney.net>
Date: Tue, 12 Nov 2019 11:24:06 -0600
Subject: [PATCH 10/10] docs: prepare 2.2.0 CHANGELOG for release

- Renames 2.2.1 changelog entry to 2.2.0 (not sure how it got bumped to 2.2.1!)
- Adds date for 2.2.0 release.
- Removes empty changelog entry for 2.1.6.
---
 CHANGELOG.md | 24 +-----------------------
 1 file changed, 1 insertion(+), 23 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 379616ed..53130e1a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,7 +2,7 @@
 
 All notable changes to this project will be documented in this file, in reverse chronological order by release.
 
-## 2.2.1 - TBD
+## 2.2.0 - 2019-11-12
 
 ### Added
 
@@ -46,28 +46,6 @@ All notable changes to this project will be documented in this file, in reverse
 
 - Nothing.
 
-## 2.1.6 - TBD
-
-### Added
-
-- Nothing.
-
-### Changed
-
-- Nothing.
-
-### Deprecated
-
-- Nothing.
-
-### Removed
-
-- Nothing.
-
-### Fixed
-
-- Nothing.
-
 ## 2.1.5 - 2019-10-10
 
 ### Added