From c6c99a4fb15302a5d62999009cbbd3ec887c66b9 Mon Sep 17 00:00:00 2001 From: Matthew Weier O'Phinney Date: Tue, 2 May 2023 15:55:24 -0500 Subject: [PATCH 1/3] refactor: remove marshalUriFromSapi function Marked for removal for 3.0.0, so this patch removes it. It also removes tests in `ServerRequestFactoryTest` that exercised it, as these had been largely moved to the `UriFactoryTest` already. One test method was found that had not, and was moved to that factory. Signed-off-by: Matthew Weier O'Phinney --- composer.json | 1 - psalm-baseline.xml | 46 ---- src/functions/marshal_uri_from_sapi.php | 233 ---------------- test/ServerRequestFactoryTest.php | 309 ---------------------- test/UriFactoryTest.php | 13 + test/functions/MarshalUriFromSapiTest.php | 108 -------- 6 files changed, 13 insertions(+), 697 deletions(-) delete mode 100644 src/functions/marshal_uri_from_sapi.php delete mode 100644 test/functions/MarshalUriFromSapiTest.php diff --git a/composer.json b/composer.json index e64c99a9..86351d58 100644 --- a/composer.json +++ b/composer.json @@ -60,7 +60,6 @@ "src/functions/marshal_headers_from_sapi.php", "src/functions/marshal_method_from_sapi.php", "src/functions/marshal_protocol_version_from_sapi.php", - "src/functions/marshal_uri_from_sapi.php", "src/functions/normalize_server.php", "src/functions/normalize_uploaded_files.php", "src/functions/parse_cookie_header.php" diff --git a/psalm-baseline.xml b/psalm-baseline.xml index 90d56ad1..97aaecc5 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -305,52 +305,6 @@ - - - $default - $host - $https - - - static function ($host) { - static function (string $name, array $headers, $default = null) { - - - - $host - $host - $host - $host - $port - $requestUri - - - - $headers[$header] - $host - - - $host - $iisUrlRewritten - $origPathInfo - $unencodedUrl - - - array - string - - - - - - $defaults - $origPathInfo - $unencodedUrl - - - - - diff --git a/src/functions/marshal_uri_from_sapi.php b/src/functions/marshal_uri_from_sapi.php deleted file mode 100644 index 186d6d9a..00000000 --- a/src/functions/marshal_uri_from_sapi.php +++ /dev/null @@ -1,233 +0,0 @@ -withScheme($scheme); - - // Set the host - [$host, $port] = $marshalHostAndPort($headers, $server); - if (! empty($host)) { - $uri = $uri->withHost($host); - if (! empty($port)) { - $uri = $uri->withPort($port); - } - } - - // URI path - $path = $marshalRequestPath($server); - - // Strip query string - $path = explode('?', $path, 2)[0]; - - // URI query - $query = ''; - if (isset($server['QUERY_STRING'])) { - $query = ltrim($server['QUERY_STRING'], '?'); - } - - // URI fragment - $fragment = ''; - if (str_contains($path, '#')) { - $parts = explode('#', $path, 2); - assert(count($parts) >= 2); - [$path, $fragment] = $parts; - } - - return $uri - ->withPath($path) - ->withFragment($fragment) - ->withQuery($query); -} diff --git a/test/ServerRequestFactoryTest.php b/test/ServerRequestFactoryTest.php index 2bdddfe5..83259cb8 100644 --- a/test/ServerRequestFactoryTest.php +++ b/test/ServerRequestFactoryTest.php @@ -9,21 +9,15 @@ use Laminas\Diactoros\ServerRequestFilter\DoNotFilter; use Laminas\Diactoros\ServerRequestFilter\FilterServerRequestInterface; use Laminas\Diactoros\UploadedFile; -use Laminas\Diactoros\Uri; use PHPUnit\Framework\TestCase; use Psr\Http\Message\ServerRequestInterface; use UnexpectedValueException; -use function array_shift; use function Laminas\Diactoros\marshalHeadersFromSapi; use function Laminas\Diactoros\marshalProtocolVersionFromSapi; -use function Laminas\Diactoros\marshalUriFromSapi; use function Laminas\Diactoros\normalizeServer; use function Laminas\Diactoros\normalizeUploadedFiles; -use function sprintf; -use function str_contains; use function str_replace; -use function strtolower; final class ServerRequestFactoryTest extends TestCase { @@ -95,296 +89,6 @@ public function testMarshalsVariablesPrefixedByApacheFromServerArray(): void $this->assertEquals($expected, marshalHeadersFromSapi($server)); } - public function testMarshalRequestUriUsesIISUnencodedUrlValueIfPresentAndUrlWasRewritten(): void - { - $server = [ - 'IIS_WasUrlRewritten' => '1', - 'UNENCODED_URL' => '/foo/bar', - ]; - - $uri = marshalUriFromSapi($server, []); - - $this->assertSame($server['UNENCODED_URL'], $uri->getPath()); - } - - public function testMarshalRequestUriStripsSchemeHostAndPortInformationWhenPresent(): void - { - $server = [ - 'REQUEST_URI' => 'http://example.com:8000/foo/bar', - ]; - - $uri = marshalUriFromSapi($server, []); - - $this->assertSame('/foo/bar', $uri->getPath()); - } - - public function testMarshalRequestUriUsesOrigPathInfoIfPresent(): void - { - $server = [ - 'ORIG_PATH_INFO' => '/foo/bar', - ]; - - $uri = marshalUriFromSapi($server, []); - - $this->assertSame('/foo/bar', $uri->getPath()); - } - - public function testMarshalRequestUriFallsBackToRoot(): void - { - $server = []; - - $uri = marshalUriFromSapi($server, []); - - $this->assertSame('/', $uri->getPath()); - } - - public function testMarshalHostAndPortUsesHostHeaderWhenPresent(): void - { - $request = new ServerRequest(); - $request = $request->withUri(new Uri('http://example.com/')); - $request = $request->withMethod('GET'); - $request = $request->withHeader('Host', 'example.com'); - - $uri = marshalUriFromSapi([], $request->getHeaders()); - - $this->assertSame('example.com', $uri->getHost()); - $this->assertNull($uri->getPort()); - } - - public function testMarshalHostAndPortWillDetectPortInHostHeaderWhenPresent(): void - { - $request = new ServerRequest(); - $request = $request->withUri(new Uri('http://example.com:8000/')); - $request = $request->withMethod('GET'); - $request = $request->withHeader('Host', 'example.com:8000'); - - $uri = marshalUriFromSapi([], $request->getHeaders()); - - $this->assertSame('example.com', $uri->getHost()); - $this->assertSame(8000, $uri->getPort()); - } - - public function testMarshalHostAndPortReturnsEmptyValuesIfNoHostHeaderAndNoServerName(): void - { - $request = new ServerRequest(); - $request = $request->withUri(new Uri()); - - $uri = marshalUriFromSapi([], $request->getHeaders()); - - $this->assertSame('', $uri->getHost()); - $this->assertNull($uri->getPort()); - } - - public function testMarshalHostAndPortReturnsServerNameForHostWhenPresent(): void - { - $request = new ServerRequest(); - $request = $request->withUri(new Uri('http://example.com/')); - - $server = [ - 'SERVER_NAME' => 'example.com', - ]; - - $uri = marshalUriFromSapi($server, $request->getHeaders()); - - $this->assertSame('example.com', $uri->getHost()); - $this->assertNull($uri->getPort()); - } - - public function testMarshalHostAndPortReturnsServerPortForPortWhenPresentWithServerName(): void - { - $request = new ServerRequest(); - $request = $request->withUri(new Uri()); - - $server = [ - 'SERVER_NAME' => 'example.com', - 'SERVER_PORT' => 8000, - ]; - - $uri = marshalUriFromSapi($server, $request->getHeaders()); - - $this->assertSame('example.com', $uri->getHost()); - $this->assertSame(8000, $uri->getPort()); - } - - public function testMarshalHostAndPortReturnsServerNameForHostIfServerAddrPresentButHostIsNotIpv6Address(): void - { - $request = new ServerRequest(); - $request = $request->withUri(new Uri('http://example.com/')); - - $server = [ - 'SERVER_ADDR' => '127.0.0.1', - 'SERVER_NAME' => 'example.com', - ]; - - $uri = marshalUriFromSapi($server, $request->getHeaders()); - - $this->assertSame('example.com', $uri->getHost()); - } - - public function testMarshalHostAndPortReturnsServerAddrForHostIfPresentAndHostIsIpv6Address(): void - { - $request = new ServerRequest(); - $request = $request->withUri(new Uri()); - - $server = [ - 'SERVER_ADDR' => 'FE80::0202:B3FF:FE1E:8329', - 'SERVER_NAME' => '[FE80::0202:B3FF:FE1E:8329]', - 'SERVER_PORT' => 8000, - ]; - - $uri = marshalUriFromSapi($server, $request->getHeaders()); - - $this->assertSame(strtolower('[FE80::0202:B3FF:FE1E:8329]'), $uri->getHost()); - $this->assertSame(8000, $uri->getPort()); - } - - public function testMarshalHostAndPortWillDetectPortInIpv6StyleHost(): void - { - $request = new ServerRequest(); - $request = $request->withUri(new Uri()); - - $server = [ - 'SERVER_ADDR' => 'FE80::0202:B3FF:FE1E:8329', - 'SERVER_NAME' => '[FE80::0202:B3FF:FE1E:8329:80]', - ]; - - $uri = marshalUriFromSapi($server, $request->getHeaders()); - - $this->assertSame(strtolower('[FE80::0202:B3FF:FE1E:8329]'), $uri->getHost()); - $this->assertNull($uri->getPort()); - } - - /** @return non-empty-array */ - public function httpsParamProvider(): array - { - return [ - 'lowercase' => ['https'], - 'uppercase' => ['HTTPS'], - ]; - } - - /** - * @dataProvider httpsParamProvider - * @param non-empty-string $param - */ - public function testMarshalUriDetectsHttpsSchemeFromServerValue(string $param): void - { - $request = new ServerRequest(); - $request = $request->withUri(new Uri('http://example.com/')); - $request = $request->withHeader('Host', 'example.com'); - - $server = [ - $param => 'on', - ]; - - $uri = marshalUriFromSapi($server, $request->getHeaders()); - - $this->assertInstanceOf(Uri::class, $uri); - $this->assertSame('https', $uri->getScheme()); - } - - /** @return iterable */ - public function httpsDisableParamProvider(): iterable - { - foreach ($this->httpsParamProvider() as $key => $data) { - $param = array_shift($data); - foreach (['lowercase-off', 'uppercase-off'] as $type) { - $key = sprintf('%s-%s', $key, $type); - $value = str_contains($type, 'lowercase') ? 'off' : 'OFF'; - yield $key => [$param, $value]; - } - } - } - - /** - * @dataProvider httpsDisableParamProvider - * @param non-empty-string $param - * @param 'off'|'OFF' $value - */ - public function testMarshalUriUsesHttpSchemeIfHttpsServerValueEqualsOff(string $param, string $value): void - { - $request = new ServerRequest(); - $request = $request->withUri(new Uri('http://example.com/')); - $request = $request->withHeader('Host', 'example.com'); - - $server = [ - $param => $value, - ]; - - $uri = marshalUriFromSapi($server, $request->getHeaders()); - - $this->assertInstanceOf(Uri::class, $uri); - $this->assertSame('http', $uri->getScheme()); - } - - /** - * @dataProvider httpsParamProvider - * @param non-empty-string $xForwardedProto - */ - public function testMarshalUriDetectsHttpsSchemeFromXForwardedProtoValue(string $xForwardedProto): void - { - $request = new ServerRequest(); - $request = $request->withUri(new Uri('http://example.com/')); - $request = $request->withHeader('Host', 'example.com'); - $request = $request->withHeader('X-Forwarded-Proto', $xForwardedProto); - - $server = []; - - $uri = marshalUriFromSapi($server, $request->getHeaders()); - - $this->assertInstanceOf(Uri::class, $uri); - $this->assertSame('https', $uri->getScheme()); - } - - public function testMarshalUriStripsQueryStringFromRequestUri(): void - { - $request = new ServerRequest(); - $request = $request->withUri(new Uri('http://example.com/')); - $request = $request->withHeader('Host', 'example.com'); - - $server = [ - 'REQUEST_URI' => '/foo/bar?foo=bar', - ]; - - $uri = marshalUriFromSapi($server, $request->getHeaders()); - - $this->assertInstanceOf(Uri::class, $uri); - $this->assertSame('/foo/bar', $uri->getPath()); - } - - public function testMarshalUriInjectsQueryStringFromServer(): void - { - $request = new ServerRequest(); - $request = $request->withUri(new Uri('http://example.com/')); - $request = $request->withHeader('Host', 'example.com'); - - $server = [ - 'REQUEST_URI' => '/foo/bar?foo=bar', - 'QUERY_STRING' => 'bar=baz', - ]; - - $uri = marshalUriFromSapi($server, $request->getHeaders()); - - $this->assertInstanceOf(Uri::class, $uri); - $this->assertSame('bar=baz', $uri->getQuery()); - } - - public function testMarshalUriInjectsFragmentFromServer(): void - { - $request = new ServerRequest(); - $request = $request->withUri(new Uri('http://example.com/')); - $request = $request->withHeader('Host', 'example.com'); - - $server = [ - 'REQUEST_URI' => '/foo/bar#foo', - ]; - - $uri = marshalUriFromSapi($server, $request->getHeaders()); - - $this->assertInstanceOf(Uri::class, $uri); - $this->assertSame('foo', $uri->getFragment()); - } - public function testCanCreateServerRequestViaFromGlobalsMethod(): void { $server = [ @@ -603,19 +307,6 @@ public function marshalProtocolVersionProvider(): array ]; } - public function testMarshalRequestUriPrefersRequestUriServerParamWhenXOriginalUrlButNoXRewriteUrlPresent(): void - { - $headers = [ - 'X-Original-URL' => '/hijack-attempt', - ]; - $server = [ - 'REQUEST_URI' => 'https://example.com/requested/path', - ]; - - $uri = marshalUriFromSapi($server, $headers); - $this->assertSame('/requested/path', $uri->getPath()); - } - public function testServerRequestFactoryHasAWritableEmptyBody(): void { $factory = new ServerRequestFactory(); diff --git a/test/UriFactoryTest.php b/test/UriFactoryTest.php index 786686e1..1701ca74 100644 --- a/test/UriFactoryTest.php +++ b/test/UriFactoryTest.php @@ -253,4 +253,17 @@ public function testMarshalUriInjectsFragmentFromServer(): void $this->assertInstanceOf(Uri::class, $uri); $this->assertSame('foo', $uri->getFragment()); } + + public function testMarshalRequestUriPrefersRequestUriServerParamWhenXOriginalUrlButNoXRewriteUrlPresent(): void + { + $headers = [ + 'X-Original-URL' => '/hijack-attempt', + ]; + $server = [ + 'REQUEST_URI' => 'https://example.com/requested/path', + ]; + + $uri = UriFactory::createFromSapi($server, $headers); + $this->assertSame('/requested/path', $uri->getPath()); + } } diff --git a/test/functions/MarshalUriFromSapiTest.php b/test/functions/MarshalUriFromSapiTest.php deleted file mode 100644 index c78d459a..00000000 --- a/test/functions/MarshalUriFromSapiTest.php +++ /dev/null @@ -1,108 +0,0 @@ - $httpsValue, - 'SERVER_NAME' => 'localhost', - 'SERVER_PORT' => '80', - 'SERVER_ADDR' => '172.22.0.4', - 'REMOTE_PORT' => '36852', - 'REMOTE_ADDR' => '172.22.0.1', - 'SERVER_SOFTWARE' => 'nginx/1.11.8', - 'GATEWAY_INTERFACE' => 'CGI/1.1', - 'SERVER_PROTOCOL' => 'HTTP/1.1', - 'DOCUMENT_ROOT' => '/var/www/public', - 'DOCUMENT_URI' => '/index.php', - 'REQUEST_URI' => '/api/messagebox-schema', - 'PATH_TRANSLATED' => '/var/www/public', - 'PATH_INFO' => '', - 'SCRIPT_NAME' => '/index.php', - 'CONTENT_LENGTH' => '', - 'CONTENT_TYPE' => '', - 'REQUEST_METHOD' => 'GET', - 'QUERY_STRING' => '', - 'SCRIPT_FILENAME' => '/var/www/public/index.php', - 'FCGI_ROLE' => 'RESPONDER', - 'PHP_SELF' => '/index.php', - ]; - - $headers = [ - 'HTTP_COOKIE' => '', - 'HTTP_ACCEPT_LANGUAGE' => 'de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7', - 'HTTP_ACCEPT_ENCODING' => 'gzip, deflate, br', - 'HTTP_REFERER' => 'http://localhost:8080/index.html', - 'HTTP_USER_AGENT' => 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko)', - 'HTTP_ACCEPT' => 'application/json,*/*', - 'HTTP_CONNECTION' => 'keep-alive', - 'HTTP_HOST' => 'localhost:8080', - ]; - - $url = marshalUriFromSapi($server, $headers); - - self::assertSame($expectedScheme, $url->getScheme()); - } - - /** @return array */ - public function returnsUrlWithCorrectHttpSchemeFromArraysProvider(): array - { - return [ - 'on-lowercase' => ['on', 'https'], - 'on-uppercase' => ['ON', 'https'], - 'off-lowercase' => ['off', 'http'], - 'off-mixed-case' => ['oFf', 'http'], - 'neither-on-nor-off' => ['foo', 'http'], - '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()); - } - - /** @return array, array}> */ - 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', 'Host' => 'localhost'], - ], - ]; - } -} From 8accacfd1839fb24069c0ffb718b33c0ca9a01af Mon Sep 17 00:00:00 2001 From: Matthew Weier O'Phinney Date: Tue, 2 May 2023 15:59:31 -0500 Subject: [PATCH 2/3] docs: update docs to note removal of marshalUriFromSapi - adds a migration note - removes reference from API documentation Signed-off-by: Matthew Weier O'Phinney --- docs/book/v3/api.md | 3 --- docs/book/v3/migration.md | 6 ++++++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/docs/book/v3/api.md b/docs/book/v3/api.md index e255b3f3..f49ef106 100644 --- a/docs/book/v3/api.md +++ b/docs/book/v3/api.md @@ -153,9 +153,6 @@ and even the `Cookie` header. These include: when under Apache) - `Laminas\Diactoros\marshalProtocolVersionFromSapi(array $server) : string` - `Laminas\Diactoros\marshalMethodFromSapi(array $server) : string`. -- `Laminas\Diactoros\marshalUriFromSapi(array $server, array $headers) : Uri`. - Please note: **this function is deprecated as of version 2.11.1**, and no longer used in `ServerRequestFactory::fromGlobals()`. - Use `ServerRequestFactory::fromGlobals()` instead. - `Laminas\Diactoros\marshalHeadersFromSapi(array $server) : array` - `Laminas\Diactoros\parseCookieHeader(string $header) : array` - `Laminas\Diactoros\createUploadedFile(array $spec) : UploadedFile` (creates the diff --git a/docs/book/v3/migration.md b/docs/book/v3/migration.md index f54c3077..047f6004 100644 --- a/docs/book/v3/migration.md +++ b/docs/book/v3/migration.md @@ -12,3 +12,9 @@ With the update in PHP 8.0 to usage of opaque resource types for all GD resource As such, we have removed the feature entirely. If you need to stream an image, the recommendation is to use the functionality in the GD extension to write the image to a temporary file (e.g., `php://temp`), and then to pass that to `Laminas\Diactoros\Stream`. + +### marshalUriFromSapi function + +The `Laminas\Diactoros\marshalUriFromSapi()` function was deprecated starting in version 2.11.0, and now removed. +The functionality that was present in it was moved to `Laminas\Diactoros\UriFactory::createFromSapi()`. +If you were using the function previously, use this static method instead. From 62b55c0a654de894dd671a54c764414c05e7c69e Mon Sep 17 00:00:00 2001 From: Matthew Weier O'Phinney Date: Tue, 2 May 2023 16:41:00 -0500 Subject: [PATCH 3/3] qa: remove psalm issue suppressions Removes issue suppressions for marshalUriFromSapi and GdImage from Psalm config. Signed-off-by: Matthew Weier O'Phinney --- psalm.xml.dist | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/psalm.xml.dist b/psalm.xml.dist index 9b1e8dbe..28ed3276 100644 --- a/psalm.xml.dist +++ b/psalm.xml.dist @@ -22,12 +22,6 @@ - - - - - - @@ -44,12 +38,6 @@ - - - - - -