From 87d9959fdc257c277744c84d48d19870fc4fea0d Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Fri, 1 Jan 2021 10:24:35 +0100 Subject: [PATCH 01/70] Bump license year --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index 69d925b..2358414 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2018-2020 Fabien Potencier +Copyright (c) 2018-2021 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From 586d46f7f676653a9b606056048403d6601c4e58 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Mon, 4 Jan 2021 15:15:06 +0100 Subject: [PATCH 02/70] fix code style --- Test/Fixtures/web/index.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Test/Fixtures/web/index.php b/Test/Fixtures/web/index.php index 68406e6..30a7049 100644 --- a/Test/Fixtures/web/index.php +++ b/Test/Fixtures/web/index.php @@ -29,7 +29,7 @@ } } -$json = json_encode($vars, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE); +$json = json_encode($vars, \JSON_PRETTY_PRINT | \JSON_UNESCAPED_SLASHES | \JSON_UNESCAPED_UNICODE); switch ($vars['REQUEST_URI']) { default: @@ -111,7 +111,7 @@ break; case '/post': - $output = json_encode($_POST + ['REQUEST_METHOD' => $vars['REQUEST_METHOD']], JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE); + $output = json_encode($_POST + ['REQUEST_METHOD' => $vars['REQUEST_METHOD']], \JSON_PRETTY_PRINT | \JSON_UNESCAPED_SLASHES | \JSON_UNESCAPED_UNICODE); header('Content-Type: application/json', true); header('Content-Length: '.strlen($output)); echo $output; From ba8176613f462eb756211cacbd61a243fed1f26b Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Wed, 27 Jan 2021 14:48:15 +0100 Subject: [PATCH 03/70] Replace "branch-version" by "versions" in composer.json --- composer.json | 1 - 1 file changed, 1 deletion(-) diff --git a/composer.json b/composer.json index f4bcfb2..b567097 100644 --- a/composer.json +++ b/composer.json @@ -32,7 +32,6 @@ } }, "extra": { - "branch-version": "1.1", "branch-alias": { "dev-main": "1.1-dev" } From 30f609f8b988cfe6f1d6f99f9951f35c86714b0d Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 11 Feb 2021 13:34:09 +0100 Subject: [PATCH 04/70] [Contracts] fix branch-aliases --- composer.json | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/composer.json b/composer.json index b567097..2464d08 100644 --- a/composer.json +++ b/composer.json @@ -26,14 +26,12 @@ }, "minimum-stability": "dev", "extra": { + "branch-alias": { + "dev-main": "1.1-dev" + }, "thanks": { "name": "symfony/contracts", "url": "https://github.com/symfony/contracts" } - }, - "extra": { - "branch-alias": { - "dev-main": "1.1-dev" - } } } From ad87ba5134e681ecb269424156545ded1c954249 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 25 Feb 2021 16:41:26 +0100 Subject: [PATCH 05/70] [HttpClient] Add `HttpClientInterface::withOptions()` --- HttpClientInterface.php | 2 ++ Test/HttpClientTestCase.php | 16 ++++++++++++++++ composer.json | 2 +- 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/HttpClientInterface.php b/HttpClientInterface.php index 4388eb8..ea793ba 100644 --- a/HttpClientInterface.php +++ b/HttpClientInterface.php @@ -19,6 +19,8 @@ * * @see HttpClientTestCase for a reference test suite * + * @method static withOptions(array $options) Returns a new instance of the client with new default options + * * @author Nicolas Grekas */ interface HttpClientInterface diff --git a/Test/HttpClientTestCase.php b/Test/HttpClientTestCase.php index 74997ea..38b8454 100644 --- a/Test/HttpClientTestCase.php +++ b/Test/HttpClientTestCase.php @@ -1038,4 +1038,20 @@ public function testMaxDuration() $this->assertLessThan(10, $duration); } + + public function testWithOptions() + { + $client = $this->getHttpClient(__FUNCTION__); + if (!method_exists($client, 'withOptions')) { + $this->markTestSkipped(sprintf('Not implementing "%s::withOptions()" is deprecated.', get_debug_type($client))); + } + + $client2 = $client->withOptions(['base_uri' => 'http://localhost:8057/']); + + $this->assertNotSame($client, $client2); + $this->assertSame(\get_class($client), \get_class($client2)); + + $response = $client2->request('GET', '/'); + $this->assertSame(200, $response->getStatusCode()); + } } diff --git a/composer.json b/composer.json index 9ab9eaf..2633785 100644 --- a/composer.json +++ b/composer.json @@ -27,7 +27,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-main": "2.3-dev" + "dev-main": "2.4-dev" }, "thanks": { "name": "symfony/contracts", From 468a7fad73645d92497a04a46487b924372b120a Mon Sep 17 00:00:00 2001 From: Robin Chalas Date: Tue, 23 Mar 2021 16:25:38 +0100 Subject: [PATCH 06/70] [Contracts] Fix branch name in README.md links --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 01f8118..03b3a69 100644 --- a/README.md +++ b/README.md @@ -6,4 +6,4 @@ A set of abstractions extracted out of the Symfony components. Can be used to build on semantics that the Symfony components proved useful - and that already have battle tested implementations. -See https://github.com/symfony/contracts/blob/master/README.md for more information. +See https://github.com/symfony/contracts/blob/main/README.md for more information. From e861cc57a3a5007081fcacb707eef780653f12f9 Mon Sep 17 00:00:00 2001 From: Robin Chalas Date: Wed, 24 Mar 2021 00:28:01 +0100 Subject: [PATCH 07/70] minor [Contracts] Fix branch name in README.md links --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e984777..7932e26 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,4 +2,4 @@ CHANGELOG ========= The changelog is maintained for all Symfony contracts at the following URL: -https://github.com/symfony/contracts/blob/master/CHANGELOG.md +https://github.com/symfony/contracts/blob/main/CHANGELOG.md From a320d097db173d4588604178bb333e0c8f058d79 Mon Sep 17 00:00:00 2001 From: Thomas Calvet Date: Wed, 7 Apr 2021 18:12:22 +0200 Subject: [PATCH 08/70] [PHPDoc] Fix some union type cases --- ResponseInterface.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ResponseInterface.php b/ResponseInterface.php index b9917ac..dfd457a 100644 --- a/ResponseInterface.php +++ b/ResponseInterface.php @@ -97,15 +97,15 @@ public function cancel(): void; * - response_headers (array) - an array modelled after the special $http_response_header variable * - start_time (float) - the time when the request was sent or 0.0 when it's pending * - url (string) - the last effective URL of the request - * - user_data (mixed|null) - the value of the "user_data" request option, null if not set + * - user_data (mixed) - the value of the "user_data" request option, null if not set * * When the "capture_peer_cert_chain" option is true, the "peer_certificate_chain" * attribute SHOULD list the peer certificates as an array of OpenSSL X.509 resources. * * Other info SHOULD be named after curl_getinfo()'s associative return value. * - * @return array|mixed|null An array of all available info, or one of them when $type is - * provided, or null when an unsupported type is requested + * @return array|mixed An array of all available info, or one of them when $type is + * provided, or null when an unsupported type is requested */ public function getInfo(string $type = null); } From 0f21b4a442eca24668df75208ce56dd5cb9cbf33 Mon Sep 17 00:00:00 2001 From: Thomas Calvet Date: Sun, 11 Apr 2021 17:25:07 +0200 Subject: [PATCH 09/70] [HttpClient][PHPDoc] Fix 2 remaining return mixed --- ResponseInterface.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ResponseInterface.php b/ResponseInterface.php index dfd457a..ad4a468 100644 --- a/ResponseInterface.php +++ b/ResponseInterface.php @@ -104,8 +104,8 @@ public function cancel(): void; * * Other info SHOULD be named after curl_getinfo()'s associative return value. * - * @return array|mixed An array of all available info, or one of them when $type is - * provided, or null when an unsupported type is requested + * @return mixed An array of all available info, or one of them when $type is + * provided, or null when an unsupported type is requested */ public function getInfo(string $type = null); } From c11bedd145f24707900d9426055bd8e7deef67b4 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Wed, 19 May 2021 15:18:37 +0200 Subject: [PATCH 10/70] Bump Symfony 6 to PHP 8 --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 2633785..42646e6 100644 --- a/composer.json +++ b/composer.json @@ -16,7 +16,7 @@ } ], "require": { - "php": ">=7.2.5" + "php": ">=8.0.2" }, "suggest": { "symfony/http-client-implementation": "" From 5c9d3cca44c483470c3977b848f4a60382bf29fb Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 7 Jun 2021 11:04:09 +0200 Subject: [PATCH 11/70] Fix tests (bis) --- Test/Fixtures/web/index.php | 5 +++-- Test/HttpClientTestCase.php | 14 +++++++++----- Test/TestHttpServer.php | 5 +++-- 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/Test/Fixtures/web/index.php b/Test/Fixtures/web/index.php index 30a7049..a5cf236 100644 --- a/Test/Fixtures/web/index.php +++ b/Test/Fixtures/web/index.php @@ -30,6 +30,7 @@ } $json = json_encode($vars, \JSON_PRETTY_PRINT | \JSON_UNESCAPED_SLASHES | \JSON_UNESCAPED_UNICODE); +$localhost = gethostbyname('localhost'); switch ($vars['REQUEST_URI']) { default: @@ -41,7 +42,7 @@ case '/': case '/?a=a&b=b': - case 'http://127.0.0.1:8057/': + case "http://$localhost:8057/": case 'http://localhost:8057/': ob_start('ob_gzhandler'); break; @@ -74,7 +75,7 @@ case '/301': if ('Basic Zm9vOmJhcg==' === $vars['HTTP_AUTHORIZATION']) { - header('Location: http://127.0.0.1:8057/302', true, 301); + header("Location: http://$localhost:8057/302", true, 301); } break; diff --git a/Test/HttpClientTestCase.php b/Test/HttpClientTestCase.php index f3e75c9..af19e38 100644 --- a/Test/HttpClientTestCase.php +++ b/Test/HttpClientTestCase.php @@ -335,6 +335,7 @@ public function test304() public function testRedirects() { $client = $this->getHttpClient(__FUNCTION__); + $localhost = gethostbyname('localhost'); $response = $client->request('POST', 'http://localhost:8057/301', [ 'auth_basic' => 'foo:bar', 'body' => function () { @@ -352,7 +353,7 @@ public function testRedirects() $expected = [ 'HTTP/1.1 301 Moved Permanently', - 'Location: http://127.0.0.1:8057/302', + "Location: http://$localhost:8057/302", 'Content-Type: application/json', 'HTTP/1.1 302 Found', 'Location: http://localhost:8057/', @@ -425,6 +426,7 @@ public function testRedirect307() public function testMaxRedirects() { $client = $this->getHttpClient(__FUNCTION__); + $localhost = gethostbyname('localhost'); $response = $client->request('GET', 'http://localhost:8057/301', [ 'max_redirects' => 1, 'auth_basic' => 'foo:bar', @@ -442,7 +444,7 @@ public function testMaxRedirects() $expected = [ 'HTTP/1.1 301 Moved Permanently', - 'Location: http://127.0.0.1:8057/302', + "Location: http://$localhost:8057/302", 'Content-Type: application/json', 'HTTP/1.1 302 Found', 'Location: http://localhost:8057/', @@ -691,8 +693,9 @@ public function testOnProgressError() public function testResolve() { $client = $this->getHttpClient(__FUNCTION__); + $localhost = gethostbyname('localhost'); $response = $client->request('GET', 'http://symfony.com:8057/', [ - 'resolve' => ['symfony.com' => '127.0.0.1'], + 'resolve' => ['symfony.com' => $localhost], ]); $this->assertSame(200, $response->getStatusCode()); @@ -706,15 +709,16 @@ public function testResolve() public function testIdnResolve() { $client = $this->getHttpClient(__FUNCTION__); + $localhost = gethostbyname('localhost'); $response = $client->request('GET', 'http://0-------------------------------------------------------------0.com:8057/', [ - 'resolve' => ['0-------------------------------------------------------------0.com' => '127.0.0.1'], + 'resolve' => ['0-------------------------------------------------------------0.com' => $localhost], ]); $this->assertSame(200, $response->getStatusCode()); $response = $client->request('GET', 'http://Bücher.example:8057/', [ - 'resolve' => ['xn--bcher-kva.example' => '127.0.0.1'], + 'resolve' => ['xn--bcher-kva.example' => $localhost], ]); $this->assertSame(200, $response->getStatusCode()); diff --git a/Test/TestHttpServer.php b/Test/TestHttpServer.php index 06a1144..a521a96 100644 --- a/Test/TestHttpServer.php +++ b/Test/TestHttpServer.php @@ -31,15 +31,16 @@ public static function start(int $port = 8057) }); } + $localhost = gethostbyname('localhost'); $finder = new PhpExecutableFinder(); - $process = new Process(array_merge([$finder->find(false)], $finder->findArguments(), ['-dopcache.enable=0', '-dvariables_order=EGPCS', '-S', '127.0.0.1:'.$port])); + $process = new Process(array_merge([$finder->find(false)], $finder->findArguments(), ['-dopcache.enable=0', '-dvariables_order=EGPCS', '-S', "$localhost:$port"])); $process->setWorkingDirectory(__DIR__.'/Fixtures/web'); $process->start(); self::$process[$port] = $process; do { usleep(50000); - } while (!@fopen('http://127.0.0.1:'.$port, 'r')); + } while (!@fopen("http://$localhost:$port", 'r')); return $process; } From c1b365201b94d8a0aa30999cd385d1453e6853e1 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 7 Jun 2021 15:37:24 +0200 Subject: [PATCH 12/70] fix tests (ter) --- Test/HttpClientTestCase.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Test/HttpClientTestCase.php b/Test/HttpClientTestCase.php index af19e38..77329af 100644 --- a/Test/HttpClientTestCase.php +++ b/Test/HttpClientTestCase.php @@ -860,7 +860,7 @@ public function testProxy() $body = $response->toArray(); $this->assertSame('localhost:8057', $body['HTTP_HOST']); - $this->assertMatchesRegularExpression('#^http://(localhost|127\.0\.0\.1):8057/$#', $body['REQUEST_URI']); + $this->assertMatchesRegularExpression('#^http://(localhost|127\.0\.\d+\.1):8057/$#', $body['REQUEST_URI']); $response = $client->request('GET', 'http://localhost:8057/', [ 'proxy' => 'http://foo:b%3Dar@localhost:8057', From 9b344619c9bcc9bbee8ca524df6adf94f755a980 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 7 Jun 2021 20:50:09 +0200 Subject: [PATCH 13/70] fix tests (quinter) --- Test/Fixtures/web/index.php | 5 ++--- Test/HttpClientTestCase.php | 16 ++++++---------- Test/TestHttpServer.php | 5 ++--- 3 files changed, 10 insertions(+), 16 deletions(-) diff --git a/Test/Fixtures/web/index.php b/Test/Fixtures/web/index.php index a5cf236..30a7049 100644 --- a/Test/Fixtures/web/index.php +++ b/Test/Fixtures/web/index.php @@ -30,7 +30,6 @@ } $json = json_encode($vars, \JSON_PRETTY_PRINT | \JSON_UNESCAPED_SLASHES | \JSON_UNESCAPED_UNICODE); -$localhost = gethostbyname('localhost'); switch ($vars['REQUEST_URI']) { default: @@ -42,7 +41,7 @@ case '/': case '/?a=a&b=b': - case "http://$localhost:8057/": + case 'http://127.0.0.1:8057/': case 'http://localhost:8057/': ob_start('ob_gzhandler'); break; @@ -75,7 +74,7 @@ case '/301': if ('Basic Zm9vOmJhcg==' === $vars['HTTP_AUTHORIZATION']) { - header("Location: http://$localhost:8057/302", true, 301); + header('Location: http://127.0.0.1:8057/302', true, 301); } break; diff --git a/Test/HttpClientTestCase.php b/Test/HttpClientTestCase.php index 77329af..f3e75c9 100644 --- a/Test/HttpClientTestCase.php +++ b/Test/HttpClientTestCase.php @@ -335,7 +335,6 @@ public function test304() public function testRedirects() { $client = $this->getHttpClient(__FUNCTION__); - $localhost = gethostbyname('localhost'); $response = $client->request('POST', 'http://localhost:8057/301', [ 'auth_basic' => 'foo:bar', 'body' => function () { @@ -353,7 +352,7 @@ public function testRedirects() $expected = [ 'HTTP/1.1 301 Moved Permanently', - "Location: http://$localhost:8057/302", + 'Location: http://127.0.0.1:8057/302', 'Content-Type: application/json', 'HTTP/1.1 302 Found', 'Location: http://localhost:8057/', @@ -426,7 +425,6 @@ public function testRedirect307() public function testMaxRedirects() { $client = $this->getHttpClient(__FUNCTION__); - $localhost = gethostbyname('localhost'); $response = $client->request('GET', 'http://localhost:8057/301', [ 'max_redirects' => 1, 'auth_basic' => 'foo:bar', @@ -444,7 +442,7 @@ public function testMaxRedirects() $expected = [ 'HTTP/1.1 301 Moved Permanently', - "Location: http://$localhost:8057/302", + 'Location: http://127.0.0.1:8057/302', 'Content-Type: application/json', 'HTTP/1.1 302 Found', 'Location: http://localhost:8057/', @@ -693,9 +691,8 @@ public function testOnProgressError() public function testResolve() { $client = $this->getHttpClient(__FUNCTION__); - $localhost = gethostbyname('localhost'); $response = $client->request('GET', 'http://symfony.com:8057/', [ - 'resolve' => ['symfony.com' => $localhost], + 'resolve' => ['symfony.com' => '127.0.0.1'], ]); $this->assertSame(200, $response->getStatusCode()); @@ -709,16 +706,15 @@ public function testResolve() public function testIdnResolve() { $client = $this->getHttpClient(__FUNCTION__); - $localhost = gethostbyname('localhost'); $response = $client->request('GET', 'http://0-------------------------------------------------------------0.com:8057/', [ - 'resolve' => ['0-------------------------------------------------------------0.com' => $localhost], + 'resolve' => ['0-------------------------------------------------------------0.com' => '127.0.0.1'], ]); $this->assertSame(200, $response->getStatusCode()); $response = $client->request('GET', 'http://Bücher.example:8057/', [ - 'resolve' => ['xn--bcher-kva.example' => $localhost], + 'resolve' => ['xn--bcher-kva.example' => '127.0.0.1'], ]); $this->assertSame(200, $response->getStatusCode()); @@ -860,7 +856,7 @@ public function testProxy() $body = $response->toArray(); $this->assertSame('localhost:8057', $body['HTTP_HOST']); - $this->assertMatchesRegularExpression('#^http://(localhost|127\.0\.\d+\.1):8057/$#', $body['REQUEST_URI']); + $this->assertMatchesRegularExpression('#^http://(localhost|127\.0\.0\.1):8057/$#', $body['REQUEST_URI']); $response = $client->request('GET', 'http://localhost:8057/', [ 'proxy' => 'http://foo:b%3Dar@localhost:8057', diff --git a/Test/TestHttpServer.php b/Test/TestHttpServer.php index a521a96..06a1144 100644 --- a/Test/TestHttpServer.php +++ b/Test/TestHttpServer.php @@ -31,16 +31,15 @@ public static function start(int $port = 8057) }); } - $localhost = gethostbyname('localhost'); $finder = new PhpExecutableFinder(); - $process = new Process(array_merge([$finder->find(false)], $finder->findArguments(), ['-dopcache.enable=0', '-dvariables_order=EGPCS', '-S', "$localhost:$port"])); + $process = new Process(array_merge([$finder->find(false)], $finder->findArguments(), ['-dopcache.enable=0', '-dvariables_order=EGPCS', '-S', '127.0.0.1:'.$port])); $process->setWorkingDirectory(__DIR__.'/Fixtures/web'); $process->start(); self::$process[$port] = $process; do { usleep(50000); - } while (!@fopen("http://$localhost:$port", 'r')); + } while (!@fopen('http://127.0.0.1:'.$port, 'r')); return $process; } From f1d979c4dd24ac8bbe50a76f96bcf238e10acc0f Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Wed, 9 Jun 2021 12:09:37 +0200 Subject: [PATCH 14/70] Bump Contracts to 2.5 --- HttpClientInterface.php | 2 +- composer.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/HttpClientInterface.php b/HttpClientInterface.php index ea793ba..386b394 100644 --- a/HttpClientInterface.php +++ b/HttpClientInterface.php @@ -91,5 +91,5 @@ public function request(string $method, string $url, array $options = []): Respo * @param ResponseInterface|ResponseInterface[]|iterable $responses One or more responses created by the current HTTP client * @param float|null $timeout The idle timeout before yielding timeout chunks */ - public function stream($responses, float $timeout = null): ResponseStreamInterface; + public function stream(ResponseInterface|iterable $responses, float $timeout = null): ResponseStreamInterface; } diff --git a/composer.json b/composer.json index 42646e6..c6e3bc8 100644 --- a/composer.json +++ b/composer.json @@ -27,7 +27,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-main": "2.4-dev" + "dev-main": "2.5-dev" }, "thanks": { "name": "symfony/contracts", From 5101dc0f6fbd0b29c70f67d92e5c41c9dc32c084 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 12 Jul 2021 16:48:14 +0200 Subject: [PATCH 15/70] [Contracts] Bump to 2.5 on branch 5.4 --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 2633785..b76cab8 100644 --- a/composer.json +++ b/composer.json @@ -27,7 +27,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-main": "2.4-dev" + "dev-main": "2.5-dev" }, "thanks": { "name": "symfony/contracts", From 58d26ed1523b94be10a5c606d4e9dd9dd8349775 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 13 Jul 2021 11:33:38 +0200 Subject: [PATCH 16/70] [Contracts] Add missing `@return` annotations --- Test/TestHttpServer.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Test/TestHttpServer.php b/Test/TestHttpServer.php index 06a1144..a1fcc59 100644 --- a/Test/TestHttpServer.php +++ b/Test/TestHttpServer.php @@ -21,6 +21,9 @@ class TestHttpServer { private static $process = []; + /** + * @return Process + */ public static function start(int $port = 8057) { if (isset(self::$process[$port])) { From 8225fbadd6c411b1d867975d3b1335ecd49de672 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 13 Jul 2021 13:47:05 +0200 Subject: [PATCH 17/70] [Contracts] add return types and bump to v3 --- ResponseInterface.php | 2 +- Test/TestHttpServer.php | 5 +---- composer.json | 2 +- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/ResponseInterface.php b/ResponseInterface.php index df71488..62d0f8f 100644 --- a/ResponseInterface.php +++ b/ResponseInterface.php @@ -105,5 +105,5 @@ public function cancel(): void; * @return mixed An array of all available info, or one of them when $type is * provided, or null when an unsupported type is requested */ - public function getInfo(string $type = null); + public function getInfo(string $type = null): mixed; } diff --git a/Test/TestHttpServer.php b/Test/TestHttpServer.php index 55a744a..086d907 100644 --- a/Test/TestHttpServer.php +++ b/Test/TestHttpServer.php @@ -18,10 +18,7 @@ class TestHttpServer { private static $process = []; - /** - * @return Process - */ - public static function start(int $port = 8057) + public static function start(int $port = 8057): Process { if (isset(self::$process[$port])) { self::$process[$port]->stop(); diff --git a/composer.json b/composer.json index c6e3bc8..a26300f 100644 --- a/composer.json +++ b/composer.json @@ -27,7 +27,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-main": "2.5-dev" + "dev-main": "3.0-dev" }, "thanks": { "name": "symfony/contracts", From 8a497ee1712c2507eaccd31aca00dd603f93d25d Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Fri, 3 Sep 2021 18:53:21 +0200 Subject: [PATCH 18/70] [HttpClient] Fix handling timeouts when responses are destructed --- Test/HttpClientTestCase.php | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/Test/HttpClientTestCase.php b/Test/HttpClientTestCase.php index f3e75c9..1062c7c 100644 --- a/Test/HttpClientTestCase.php +++ b/Test/HttpClientTestCase.php @@ -810,6 +810,38 @@ public function testTimeoutWithActiveConcurrentStream() } } + public function testTimeoutOnDestruct() + { + $p1 = TestHttpServer::start(8067); + $p2 = TestHttpServer::start(8077); + + $client = $this->getHttpClient(__FUNCTION__); + $start = microtime(true); + $responses = []; + + $responses[] = $client->request('GET', 'http://localhost:8067/timeout-header', ['timeout' => 0.25]); + $responses[] = $client->request('GET', 'http://localhost:8077/timeout-header', ['timeout' => 0.25]); + $responses[] = $client->request('GET', 'http://localhost:8067/timeout-header', ['timeout' => 0.25]); + $responses[] = $client->request('GET', 'http://localhost:8077/timeout-header', ['timeout' => 0.25]); + + try { + while ($response = array_shift($responses)) { + try { + unset($response); + $this->fail(TransportExceptionInterface::class.' expected'); + } catch (TransportExceptionInterface $e) { + } + } + + $duration = microtime(true) - $start; + + $this->assertLessThan(1.0, $duration); + } finally { + $p1->stop(); + $p2->stop(); + } + } + public function testDestruct() { $client = $this->getHttpClient(__FUNCTION__); From 9dd0b1a6c8c25afe93c968704daa8753a84bebe5 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 7 Sep 2021 14:27:46 +0200 Subject: [PATCH 19/70] Turn `@method` annotations into real method declarations --- HttpClientInterface.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/HttpClientInterface.php b/HttpClientInterface.php index 386b394..5ad0880 100644 --- a/HttpClientInterface.php +++ b/HttpClientInterface.php @@ -19,8 +19,6 @@ * * @see HttpClientTestCase for a reference test suite * - * @method static withOptions(array $options) Returns a new instance of the client with new default options - * * @author Nicolas Grekas */ interface HttpClientInterface @@ -92,4 +90,9 @@ public function request(string $method, string $url, array $options = []): Respo * @param float|null $timeout The idle timeout before yielding timeout chunks */ public function stream(ResponseInterface|iterable $responses, float $timeout = null): ResponseStreamInterface; + + /** + * Returns a new instance of the client with new default options. + */ + public function withOptions(array $options): static; } From c2a2d20d4db6045aba4a6f3b0c80c1d89d1c4bda Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 7 Sep 2021 15:39:06 +0200 Subject: [PATCH 20/70] Remove deprecated code paths --- Test/HttpClientTestCase.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Test/HttpClientTestCase.php b/Test/HttpClientTestCase.php index da21de4..2bcffcd 100644 --- a/Test/HttpClientTestCase.php +++ b/Test/HttpClientTestCase.php @@ -1074,10 +1074,6 @@ public function testMaxDuration() public function testWithOptions() { $client = $this->getHttpClient(__FUNCTION__); - if (!method_exists($client, 'withOptions')) { - $this->markTestSkipped(sprintf('Not implementing "%s::withOptions()" is deprecated.', get_debug_type($client))); - } - $client2 = $client->withOptions(['base_uri' => 'http://localhost:8057/']); $this->assertNotSame($client, $client2); From ec82e57b5b714dbb69300d348bd840b345e24166 Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" Date: Wed, 3 Nov 2021 10:24:47 +0100 Subject: [PATCH 21/70] Add generic types to traversable implementations --- HttpClientInterface.php | 4 ++-- ResponseStreamInterface.php | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/HttpClientInterface.php b/HttpClientInterface.php index ea793ba..158c1a7 100644 --- a/HttpClientInterface.php +++ b/HttpClientInterface.php @@ -88,8 +88,8 @@ public function request(string $method, string $url, array $options = []): Respo /** * Yields responses chunk by chunk as they complete. * - * @param ResponseInterface|ResponseInterface[]|iterable $responses One or more responses created by the current HTTP client - * @param float|null $timeout The idle timeout before yielding timeout chunks + * @param ResponseInterface|iterable $responses One or more responses created by the current HTTP client + * @param float|null $timeout The idle timeout before yielding timeout chunks */ public function stream($responses, float $timeout = null): ResponseStreamInterface; } diff --git a/ResponseStreamInterface.php b/ResponseStreamInterface.php index febe5d1..fa3e5db 100644 --- a/ResponseStreamInterface.php +++ b/ResponseStreamInterface.php @@ -15,6 +15,8 @@ * Yields response chunks, returned by HttpClientInterface::stream(). * * @author Nicolas Grekas + * + * @extends \Iterator */ interface ResponseStreamInterface extends \Iterator { From 8958f34021e7c89a0cb887216b94503ecf4cd612 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 29 Nov 2021 19:10:03 +0100 Subject: [PATCH 22/70] [Contracts] update branch-alias --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index a26300f..5cea336 100644 --- a/composer.json +++ b/composer.json @@ -27,7 +27,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-main": "3.0-dev" + "dev-main": "3.1-dev" }, "thanks": { "name": "symfony/contracts", From 9ac1554b0da2c488bb32fc41db8236dc22c427fe Mon Sep 17 00:00:00 2001 From: Thomas Calvet Date: Wed, 8 Dec 2021 14:13:04 +0100 Subject: [PATCH 23/70] Leverage str_starts_with(), str_ends_with() and str_contains() --- Test/Fixtures/web/index.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Test/Fixtures/web/index.php b/Test/Fixtures/web/index.php index 30a7049..2c7af6d 100644 --- a/Test/Fixtures/web/index.php +++ b/Test/Fixtures/web/index.php @@ -15,7 +15,7 @@ foreach ($_SERVER as $k => $v) { switch ($k) { default: - if (0 !== strpos($k, 'HTTP_')) { + if (!str_starts_with($k, 'HTTP_')) { continue 2; } // no break From 627eaa1a48c2f53ef706a845a628c44825ab9d95 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sat, 11 Dec 2021 17:29:22 +0100 Subject: [PATCH 24/70] [HttpClient] Don't reset timeout counter when initializing requests --- Test/HttpClientTestCase.php | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/Test/HttpClientTestCase.php b/Test/HttpClientTestCase.php index 1062c7c..7ebf055 100644 --- a/Test/HttpClientTestCase.php +++ b/Test/HttpClientTestCase.php @@ -810,6 +810,39 @@ public function testTimeoutWithActiveConcurrentStream() } } + public function testTimeoutOnInitialize() + { + $p1 = TestHttpServer::start(8067); + $p2 = TestHttpServer::start(8077); + + $client = $this->getHttpClient(__FUNCTION__); + $start = microtime(true); + $responses = []; + + $responses[] = $client->request('GET', 'http://localhost:8067/timeout-header', ['timeout' => 0.25]); + $responses[] = $client->request('GET', 'http://localhost:8077/timeout-header', ['timeout' => 0.25]); + $responses[] = $client->request('GET', 'http://localhost:8067/timeout-header', ['timeout' => 0.25]); + $responses[] = $client->request('GET', 'http://localhost:8077/timeout-header', ['timeout' => 0.25]); + + try { + foreach ($responses as $response) { + try { + $response->getContent(); + $this->fail(TransportExceptionInterface::class.' expected'); + } catch (TransportExceptionInterface $e) { + } + } + $responses = []; + + $duration = microtime(true) - $start; + + $this->assertLessThan(1.0, $duration); + } finally { + $p1->stop(); + $p2->stop(); + } + } + public function testTimeoutOnDestruct() { $p1 = TestHttpServer::start(8067); From e7e85b3a7c93255e84e0ad5cdeffcaac4e5037ca Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Wed, 15 Dec 2021 11:32:07 +0100 Subject: [PATCH 25/70] Try making tests a bit less transient --- Test/HttpClientTestCase.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Test/HttpClientTestCase.php b/Test/HttpClientTestCase.php index 7ebf055..fd7ea1a 100644 --- a/Test/HttpClientTestCase.php +++ b/Test/HttpClientTestCase.php @@ -813,16 +813,16 @@ public function testTimeoutWithActiveConcurrentStream() public function testTimeoutOnInitialize() { $p1 = TestHttpServer::start(8067); - $p2 = TestHttpServer::start(8077); + $p2 = TestHttpServer::start(8078); $client = $this->getHttpClient(__FUNCTION__); $start = microtime(true); $responses = []; $responses[] = $client->request('GET', 'http://localhost:8067/timeout-header', ['timeout' => 0.25]); - $responses[] = $client->request('GET', 'http://localhost:8077/timeout-header', ['timeout' => 0.25]); + $responses[] = $client->request('GET', 'http://localhost:8078/timeout-header', ['timeout' => 0.25]); $responses[] = $client->request('GET', 'http://localhost:8067/timeout-header', ['timeout' => 0.25]); - $responses[] = $client->request('GET', 'http://localhost:8077/timeout-header', ['timeout' => 0.25]); + $responses[] = $client->request('GET', 'http://localhost:8078/timeout-header', ['timeout' => 0.25]); try { foreach ($responses as $response) { @@ -846,16 +846,16 @@ public function testTimeoutOnInitialize() public function testTimeoutOnDestruct() { $p1 = TestHttpServer::start(8067); - $p2 = TestHttpServer::start(8077); + $p2 = TestHttpServer::start(8078); $client = $this->getHttpClient(__FUNCTION__); $start = microtime(true); $responses = []; $responses[] = $client->request('GET', 'http://localhost:8067/timeout-header', ['timeout' => 0.25]); - $responses[] = $client->request('GET', 'http://localhost:8077/timeout-header', ['timeout' => 0.25]); + $responses[] = $client->request('GET', 'http://localhost:8078/timeout-header', ['timeout' => 0.25]); $responses[] = $client->request('GET', 'http://localhost:8067/timeout-header', ['timeout' => 0.25]); - $responses[] = $client->request('GET', 'http://localhost:8077/timeout-header', ['timeout' => 0.25]); + $responses[] = $client->request('GET', 'http://localhost:8078/timeout-header', ['timeout' => 0.25]); try { while ($response = array_shift($responses)) { From f4b3b68570727e5b77c38ae32b86cf830f9a1f1a Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Wed, 15 Dec 2021 14:33:45 +0100 Subject: [PATCH 26/70] Skip transient tests on macos --- Test/HttpClientTestCase.php | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/Test/HttpClientTestCase.php b/Test/HttpClientTestCase.php index fd7ea1a..648c917 100644 --- a/Test/HttpClientTestCase.php +++ b/Test/HttpClientTestCase.php @@ -810,19 +810,22 @@ public function testTimeoutWithActiveConcurrentStream() } } + /** + * @group transient-on-macos + */ public function testTimeoutOnInitialize() { $p1 = TestHttpServer::start(8067); - $p2 = TestHttpServer::start(8078); + $p2 = TestHttpServer::start(8077); $client = $this->getHttpClient(__FUNCTION__); $start = microtime(true); $responses = []; $responses[] = $client->request('GET', 'http://localhost:8067/timeout-header', ['timeout' => 0.25]); - $responses[] = $client->request('GET', 'http://localhost:8078/timeout-header', ['timeout' => 0.25]); + $responses[] = $client->request('GET', 'http://localhost:8077/timeout-header', ['timeout' => 0.25]); $responses[] = $client->request('GET', 'http://localhost:8067/timeout-header', ['timeout' => 0.25]); - $responses[] = $client->request('GET', 'http://localhost:8078/timeout-header', ['timeout' => 0.25]); + $responses[] = $client->request('GET', 'http://localhost:8077/timeout-header', ['timeout' => 0.25]); try { foreach ($responses as $response) { @@ -843,19 +846,22 @@ public function testTimeoutOnInitialize() } } + /** + * @group transient-on-macos + */ public function testTimeoutOnDestruct() { $p1 = TestHttpServer::start(8067); - $p2 = TestHttpServer::start(8078); + $p2 = TestHttpServer::start(8077); $client = $this->getHttpClient(__FUNCTION__); $start = microtime(true); $responses = []; $responses[] = $client->request('GET', 'http://localhost:8067/timeout-header', ['timeout' => 0.25]); - $responses[] = $client->request('GET', 'http://localhost:8078/timeout-header', ['timeout' => 0.25]); + $responses[] = $client->request('GET', 'http://localhost:8077/timeout-header', ['timeout' => 0.25]); $responses[] = $client->request('GET', 'http://localhost:8067/timeout-header', ['timeout' => 0.25]); - $responses[] = $client->request('GET', 'http://localhost:8078/timeout-header', ['timeout' => 0.25]); + $responses[] = $client->request('GET', 'http://localhost:8077/timeout-header', ['timeout' => 0.25]); try { while ($response = array_shift($responses)) { From 0d41683615e45d10be4891d5bf1e6d086176d16c Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Wed, 29 Dec 2021 10:28:53 +0100 Subject: [PATCH 27/70] [CI] Remove macOS jobs --- Test/HttpClientTestCase.php | 6 ------ 1 file changed, 6 deletions(-) diff --git a/Test/HttpClientTestCase.php b/Test/HttpClientTestCase.php index 648c917..7ebf055 100644 --- a/Test/HttpClientTestCase.php +++ b/Test/HttpClientTestCase.php @@ -810,9 +810,6 @@ public function testTimeoutWithActiveConcurrentStream() } } - /** - * @group transient-on-macos - */ public function testTimeoutOnInitialize() { $p1 = TestHttpServer::start(8067); @@ -846,9 +843,6 @@ public function testTimeoutOnInitialize() } } - /** - * @group transient-on-macos - */ public function testTimeoutOnDestruct() { $p1 = TestHttpServer::start(8067); From 8094b1eeb50a5474826fb390935ce6f27525a71a Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sun, 2 Jan 2022 10:41:36 +0100 Subject: [PATCH 28/70] Bump license year --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index 2358414..74cdc2d 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2018-2021 Fabien Potencier +Copyright (c) 2018-2022 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From 48a4e363ebd6dbc713eac768def2d2a2bc643d18 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Wed, 9 Feb 2022 15:00:38 +0100 Subject: [PATCH 29/70] Bump minimum version of PHP to 8.1 --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 5cea336..4e877e5 100644 --- a/composer.json +++ b/composer.json @@ -16,7 +16,7 @@ } ], "require": { - "php": ">=8.0.2" + "php": ">=8.1" }, "suggest": { "symfony/http-client-implementation": "" From 89e01dc0f8677ee843b7c46f12624cac7fe4292b Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 8 Mar 2022 19:37:06 +0100 Subject: [PATCH 30/70] [HttpClient] Fix reading proxy settings from dotenv when curl is used --- Test/HttpClientTestCase.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Test/HttpClientTestCase.php b/Test/HttpClientTestCase.php index 7ebf055..ddc5324 100644 --- a/Test/HttpClientTestCase.php +++ b/Test/HttpClientTestCase.php @@ -929,6 +929,16 @@ public function testProxy() $body = $response->toArray(); $this->assertSame('Basic Zm9vOmI9YXI=', $body['HTTP_PROXY_AUTHORIZATION']); + + $_SERVER['http_proxy'] = 'http://localhost:8057'; + try { + $response = $client->request('GET', 'http://localhost:8057/'); + $body = $response->toArray(); + $this->assertSame('localhost:8057', $body['HTTP_HOST']); + $this->assertMatchesRegularExpression('#^http://(localhost|127\.0\.0\.1):8057/$#', $body['REQUEST_URI']); + } finally { + unset($_SERVER['http_proxy']); + } } public function testNoProxy() From f0e0bc7511a7a6751b412ee1cb40de3f6cf54972 Mon Sep 17 00:00:00 2001 From: Thomas Calvet Date: Thu, 31 Mar 2022 18:23:12 +0200 Subject: [PATCH 31/70] Leverage non-capturing catches --- Test/HttpClientTestCase.php | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/Test/HttpClientTestCase.php b/Test/HttpClientTestCase.php index 6a042d5..18d851f 100644 --- a/Test/HttpClientTestCase.php +++ b/Test/HttpClientTestCase.php @@ -226,13 +226,13 @@ public function testClientError() try { $response->getHeaders(); $this->fail(ClientExceptionInterface::class.' expected'); - } catch (ClientExceptionInterface $e) { + } catch (ClientExceptionInterface) { } try { $response->getContent(); $this->fail(ClientExceptionInterface::class.' expected'); - } catch (ClientExceptionInterface $e) { + } catch (ClientExceptionInterface) { } $this->assertSame(404, $response->getStatusCode()); @@ -246,7 +246,7 @@ public function testClientError() $this->assertTrue($chunk->isFirst()); } $this->fail(ClientExceptionInterface::class.' expected'); - } catch (ClientExceptionInterface $e) { + } catch (ClientExceptionInterface) { } } @@ -266,14 +266,14 @@ public function testDnsError() try { $response->getStatusCode(); $this->fail(TransportExceptionInterface::class.' expected'); - } catch (TransportExceptionInterface $e) { + } catch (TransportExceptionInterface) { $this->addToAssertionCount(1); } try { $response->getStatusCode(); $this->fail(TransportExceptionInterface::class.' still expected'); - } catch (TransportExceptionInterface $e) { + } catch (TransportExceptionInterface) { $this->addToAssertionCount(1); } @@ -283,7 +283,7 @@ public function testDnsError() foreach ($client->stream($response) as $r => $chunk) { } $this->fail(TransportExceptionInterface::class.' expected'); - } catch (TransportExceptionInterface $e) { + } catch (TransportExceptionInterface) { $this->addToAssertionCount(1); } @@ -432,7 +432,7 @@ public function testMaxRedirects() try { $response->getHeaders(); $this->fail(RedirectionExceptionInterface::class.' expected'); - } catch (RedirectionExceptionInterface $e) { + } catch (RedirectionExceptionInterface) { } $this->assertSame(302, $response->getStatusCode()); @@ -854,7 +854,7 @@ public function testTimeoutOnInitialize() try { $response->getContent(); $this->fail(TransportExceptionInterface::class.' expected'); - } catch (TransportExceptionInterface $e) { + } catch (TransportExceptionInterface) { } } $responses = []; @@ -887,7 +887,7 @@ public function testTimeoutOnDestruct() try { unset($response); $this->fail(TransportExceptionInterface::class.' expected'); - } catch (TransportExceptionInterface $e) { + } catch (TransportExceptionInterface) { } } @@ -1105,7 +1105,7 @@ public function testMaxDuration() try { $response->getContent(); - } catch (TransportExceptionInterface $e) { + } catch (TransportExceptionInterface) { $this->addToAssertionCount(1); } From 59f37624a82635962f04c98f31aed122e539a89e Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 11 Apr 2022 13:29:45 +0200 Subject: [PATCH 32/70] [HttpClient] Fix sending content-length when streaming the body --- Test/HttpClientTestCase.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Test/HttpClientTestCase.php b/Test/HttpClientTestCase.php index ddc5324..bce7a85 100644 --- a/Test/HttpClientTestCase.php +++ b/Test/HttpClientTestCase.php @@ -332,11 +332,16 @@ public function test304() $this->assertSame('', $response->getContent(false)); } - public function testRedirects() + /** + * @testWith [[]] + * [["Content-Length: 7"]] + */ + public function testRedirects(array $headers = []) { $client = $this->getHttpClient(__FUNCTION__); $response = $client->request('POST', 'http://localhost:8057/301', [ 'auth_basic' => 'foo:bar', + 'headers' => $headers, 'body' => function () { yield 'foo=bar'; }, From fd038f08c623ab5d22b26e9ba35afe8c79071800 Mon Sep 17 00:00:00 2001 From: Daniil Gentili Date: Thu, 21 Apr 2022 12:29:03 +0200 Subject: [PATCH 33/70] [HttpClient][Translation][Workflow] [Service] Exclude tests from classmaps --- composer.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 4e877e5..0a99ad5 100644 --- a/composer.json +++ b/composer.json @@ -22,7 +22,10 @@ "symfony/http-client-implementation": "" }, "autoload": { - "psr-4": { "Symfony\\Contracts\\HttpClient\\": "" } + "psr-4": { "Symfony\\Contracts\\HttpClient\\": "" }, + "exclude-from-classmap": [ + "/Test/" + ] }, "minimum-stability": "dev", "extra": { From 7e02144faa4e1d9e3ee3b95d33aefbce8ba1486c Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Fri, 20 May 2022 15:56:22 +0200 Subject: [PATCH 34/70] Update branch alias for contracts --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 0a99ad5..d4176cc 100644 --- a/composer.json +++ b/composer.json @@ -30,7 +30,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-main": "3.1-dev" + "dev-main": "3.2-dev" }, "thanks": { "name": "symfony/contracts", From 0a4b2569820bb9f1644763667683fcf95c859ddc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Anne?= Date: Wed, 27 Jul 2022 15:32:56 +0200 Subject: [PATCH 35/70] Remove .gitignore file from dist package --- .gitattributes | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..3a01b37 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +/.gitattributes export-ignore +/.gitignore export-ignore From 4246c0531ffa941046cc8e98481de210a411d0cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois-Xavier=20de=20Guillebon?= Date: Fri, 26 Aug 2022 16:19:22 +0200 Subject: [PATCH 36/70] Replace get_class() calls by ::class --- Test/HttpClientTestCase.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Test/HttpClientTestCase.php b/Test/HttpClientTestCase.php index 84df706..9489300 100644 --- a/Test/HttpClientTestCase.php +++ b/Test/HttpClientTestCase.php @@ -1125,7 +1125,7 @@ public function testWithOptions() $client2 = $client->withOptions(['base_uri' => 'http://localhost:8057/']); $this->assertNotSame($client, $client2); - $this->assertSame(\get_class($client), \get_class($client2)); + $this->assertSame($client::class, $client2::class); $response = $client2->request('GET', '/'); $this->assertSame(200, $response->getStatusCode()); From c5f587eb445224ddfeb05b5ee703476742d730bf Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Fri, 25 Nov 2022 11:21:52 +0100 Subject: [PATCH 37/70] [Contracts] update branch alias --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index d4176cc..61eac1e 100644 --- a/composer.json +++ b/composer.json @@ -30,7 +30,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-main": "3.2-dev" + "dev-main": "3.3-dev" }, "thanks": { "name": "symfony/contracts", From 699805a02fe5235539b78f0d1d434a6f554c38ce Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sun, 1 Jan 2023 09:32:19 +0100 Subject: [PATCH 38/70] Bump license year to 2023 --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index 74cdc2d..99757d5 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2018-2022 Fabien Potencier +Copyright (c) 2018-2023 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From e409355955c35bc64af520f9853f191e6621d013 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Tue, 24 Jan 2023 15:02:24 +0100 Subject: [PATCH 39/70] Update license years (last time) --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index 99757d5..7536cae 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2018-2023 Fabien Potencier +Copyright (c) 2018-present Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From df2ecd6cb70e73c1080e6478aea85f5f4da2c48b Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Wed, 1 Mar 2023 11:32:47 +0100 Subject: [PATCH 40/70] Fix typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 03b3a69..24d72f5 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ Symfony HttpClient Contracts A set of abstractions extracted out of the Symfony components. -Can be used to build on semantics that the Symfony components proved useful - and +Can be used to build on semantics that the Symfony components proved useful and that already have battle tested implementations. See https://github.com/symfony/contracts/blob/main/README.md for more information. From 330b698dcd40c19117b69df7ff1e95ba52b5c7da Mon Sep 17 00:00:00 2001 From: Hugo Alliaume Date: Tue, 21 Mar 2023 14:46:52 +0100 Subject: [PATCH 41/70] [HttpClient] Add hint about `timeout` and `max_duration` options --- HttpClientInterface.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/HttpClientInterface.php b/HttpClientInterface.php index 158c1a7..9c96629 100644 --- a/HttpClientInterface.php +++ b/HttpClientInterface.php @@ -54,8 +54,8 @@ interface HttpClientInterface 'resolve' => [], // string[] - a map of host to IP address that SHOULD replace DNS resolution 'proxy' => null, // string - by default, the proxy-related env vars handled by curl SHOULD be honored 'no_proxy' => null, // string - a comma separated list of hosts that do not require a proxy to be reached - 'timeout' => null, // float - the idle timeout - defaults to ini_get('default_socket_timeout') - 'max_duration' => 0, // float - the maximum execution time for the request+response as a whole; + 'timeout' => null, // float - the idle timeout (in seconds) - defaults to ini_get('default_socket_timeout') + 'max_duration' => 0, // float - the maximum execution time (in seconds) for the request+response as a whole; // a value lower than or equal to 0 means it is unlimited 'bindto' => '0', // string - the interface or the local socket to bind to 'verify_peer' => true, // see https://php.net/context.ssl for the following options From 44960121df375520a6fe285e8bef06f7469bbeb2 Mon Sep 17 00:00:00 2001 From: Matthias Neid Date: Wed, 12 Apr 2023 16:18:42 +0200 Subject: [PATCH 42/70] [HttpClient] fix proxied redirects in curl client --- Test/Fixtures/web/index.php | 6 ++++++ Test/HttpClientTestCase.php | 8 ++++++++ 2 files changed, 14 insertions(+) diff --git a/Test/Fixtures/web/index.php b/Test/Fixtures/web/index.php index 30a7049..cf947cb 100644 --- a/Test/Fixtures/web/index.php +++ b/Test/Fixtures/web/index.php @@ -86,6 +86,12 @@ header('Location: //?foo=bar', true, 301); break; + case '/301/proxy': + case 'http://localhost:8057/301/proxy': + case 'http://127.0.0.1:8057/301/proxy': + header('Location: http://localhost:8057/', true, 301); + break; + case '/302': if (!isset($vars['HTTP_AUTHORIZATION'])) { header('Location: http://localhost:8057/', true, 302); diff --git a/Test/HttpClientTestCase.php b/Test/HttpClientTestCase.php index 7acd6b7..78b0278 100644 --- a/Test/HttpClientTestCase.php +++ b/Test/HttpClientTestCase.php @@ -969,6 +969,14 @@ public function testProxy() } finally { unset($_SERVER['http_proxy']); } + + $response = $client->request('GET', 'http://localhost:8057/301/proxy', [ + 'proxy' => 'http://localhost:8057', + ]); + + $body = $response->toArray(); + $this->assertSame('localhost:8057', $body['HTTP_HOST']); + $this->assertMatchesRegularExpression('#^http://(localhost|127\.0\.0\.1):8057/$#', $body['REQUEST_URI']); } public function testNoProxy() From bf95f0c0a0fdc7d045a083b28b12fd5b2174e1c7 Mon Sep 17 00:00:00 2001 From: Artyum Petrov <17199757+artyuum@users.noreply.github.com> Date: Thu, 20 Apr 2023 19:24:19 +0400 Subject: [PATCH 43/70] Add "composer require..." in all exception messages when needed --- composer.json | 3 --- 1 file changed, 3 deletions(-) diff --git a/composer.json b/composer.json index 61eac1e..0c2102f 100644 --- a/composer.json +++ b/composer.json @@ -18,9 +18,6 @@ "require": { "php": ">=8.1" }, - "suggest": { - "symfony/http-client-implementation": "" - }, "autoload": { "psr-4": { "Symfony\\Contracts\\HttpClient\\": "" }, "exclude-from-classmap": [ From 847b998a323dd06d3b9350a5590f79d015ba90a4 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 9 May 2023 15:41:26 +0200 Subject: [PATCH 44/70] [HttpClient] Add option `crypto_method` to set the minimum TLS version and make it default to v1.2 --- HttpClientInterface.php | 1 + 1 file changed, 1 insertion(+) diff --git a/HttpClientInterface.php b/HttpClientInterface.php index b148b19..5963625 100644 --- a/HttpClientInterface.php +++ b/HttpClientInterface.php @@ -66,6 +66,7 @@ interface HttpClientInterface 'ciphers' => null, 'peer_fingerprint' => null, 'capture_peer_cert_chain' => false, + 'crypto_method' => \STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT, // STREAM_CRYPTO_METHOD_TLSv*_CLIENT - minimum TLS version 'extra' => [], // array - additional options that can be ignored if unsupported, unlike regular options ]; From 3b66325d0176b4ec826bffab57c9037d759c31fb Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 23 May 2023 16:45:45 +0200 Subject: [PATCH 45/70] Bump contracts to 3.4-dev --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 0c2102f..084d490 100644 --- a/composer.json +++ b/composer.json @@ -27,7 +27,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-main": "3.3-dev" + "dev-main": "3.4-dev" }, "thanks": { "name": "symfony/contracts", From 1f75b718ddd5bf68bc14957e923756d1eb0e2ff4 Mon Sep 17 00:00:00 2001 From: "Roland Franssen :)" Date: Wed, 28 Jun 2023 18:56:50 +0200 Subject: [PATCH 46/70] [HttpClient] Allow custom working directory in TestHttpServer --- Test/TestHttpServer.php | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Test/TestHttpServer.php b/Test/TestHttpServer.php index 086d907..2ec4aa5 100644 --- a/Test/TestHttpServer.php +++ b/Test/TestHttpServer.php @@ -18,8 +18,13 @@ class TestHttpServer { private static $process = []; - public static function start(int $port = 8057): Process + /** + * @param string|null $workingDirectory + */ + public static function start(int $port = 8057/* , string $workingDirectory = null */): Process { + $workingDirectory = \func_get_args()[1] ?? __DIR__.'/Fixtures/web'; + if (isset(self::$process[$port])) { self::$process[$port]->stop(); } else { @@ -30,7 +35,7 @@ public static function start(int $port = 8057): Process $finder = new PhpExecutableFinder(); $process = new Process(array_merge([$finder->find(false)], $finder->findArguments(), ['-dopcache.enable=0', '-dvariables_order=EGPCS', '-S', '127.0.0.1:'.$port])); - $process->setWorkingDirectory(__DIR__.'/Fixtures/web'); + $process->setWorkingDirectory($workingDirectory); $process->start(); self::$process[$port] = $process; From 50800abc34950ccd05f2aa01c0b49f087ff29178 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Fri, 21 Jul 2023 18:41:43 +0200 Subject: [PATCH 47/70] Add types to private and internal properties --- Test/TestHttpServer.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Test/TestHttpServer.php b/Test/TestHttpServer.php index 2ec4aa5..86dfa7d 100644 --- a/Test/TestHttpServer.php +++ b/Test/TestHttpServer.php @@ -16,7 +16,7 @@ class TestHttpServer { - private static $process = []; + private static array $process = []; /** * @param string|null $workingDirectory From 1ee70e699b41909c209a0c930f11034b93578654 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Fri, 28 Jul 2023 15:17:19 +0200 Subject: [PATCH 48/70] More short closures --- Test/HttpClientTestCase.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Test/HttpClientTestCase.php b/Test/HttpClientTestCase.php index 9cfd33f..98838ef 100644 --- a/Test/HttpClientTestCase.php +++ b/Test/HttpClientTestCase.php @@ -135,7 +135,7 @@ public function testConditionalBuffering() $this->assertSame($firstContent, $secondContent); - $response = $client->request('GET', 'http://localhost:8057', ['buffer' => function () { return false; }]); + $response = $client->request('GET', 'http://localhost:8057', ['buffer' => fn () => false]); $response->getContent(); $this->expectException(TransportExceptionInterface::class); From 8a3631bbe86cc07fcf5f3891f4c5552e1a33d9e6 Mon Sep 17 00:00:00 2001 From: Kevin Bond Date: Wed, 20 Dec 2023 13:09:40 -0500 Subject: [PATCH 49/70] [DependencyInjection] Add `ServiceCollectionInterface` --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 084d490..efb146e 100644 --- a/composer.json +++ b/composer.json @@ -27,7 +27,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-main": "3.4-dev" + "dev-main": "3.5-dev" }, "thanks": { "name": "symfony/contracts", From 6f89e7e27032889dfeb11c20acf3799eec1f4cf3 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 23 Jan 2024 14:51:25 +0100 Subject: [PATCH 50/70] Apply php-cs-fixer fix --rules nullable_type_declaration_for_default_null_value --- HttpClientInterface.php | 2 +- ResponseInterface.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/HttpClientInterface.php b/HttpClientInterface.php index 9c96629..73a7cb5 100644 --- a/HttpClientInterface.php +++ b/HttpClientInterface.php @@ -91,5 +91,5 @@ public function request(string $method, string $url, array $options = []): Respo * @param ResponseInterface|iterable $responses One or more responses created by the current HTTP client * @param float|null $timeout The idle timeout before yielding timeout chunks */ - public function stream($responses, float $timeout = null): ResponseStreamInterface; + public function stream($responses, ?float $timeout = null): ResponseStreamInterface; } diff --git a/ResponseInterface.php b/ResponseInterface.php index df71488..7c84a98 100644 --- a/ResponseInterface.php +++ b/ResponseInterface.php @@ -105,5 +105,5 @@ public function cancel(): void; * @return mixed An array of all available info, or one of them when $type is * provided, or null when an unsupported type is requested */ - public function getInfo(string $type = null); + public function getInfo(?string $type = null); } From e5cc97c2b4a4db0ba26bebc154f1426e3fd1d2f1 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Tue, 26 Mar 2024 11:11:58 +0100 Subject: [PATCH 51/70] stop all server processes after tests have run --- Test/HttpClientTestCase.php | 6 ++++++ Test/TestHttpServer.php | 7 +++++++ 2 files changed, 13 insertions(+) diff --git a/Test/HttpClientTestCase.php b/Test/HttpClientTestCase.php index 78b0278..994e926 100644 --- a/Test/HttpClientTestCase.php +++ b/Test/HttpClientTestCase.php @@ -28,6 +28,12 @@ public static function setUpBeforeClass(): void TestHttpServer::start(); } + public static function tearDownAfterClass(): void + { + TestHttpServer::stop(8067); + TestHttpServer::stop(8077); + } + abstract protected function getHttpClient(string $testCase): HttpClientInterface; public function testGetRequest() diff --git a/Test/TestHttpServer.php b/Test/TestHttpServer.php index 55a744a..463b4b7 100644 --- a/Test/TestHttpServer.php +++ b/Test/TestHttpServer.php @@ -43,4 +43,11 @@ public static function start(int $port = 8057) return $process; } + + public static function stop(int $port = 8057) + { + if (isset(self::$process[$port])) { + self::$process[$port]->stop(); + } + } } From 00c735f7f916832142ed5e9743406b8ebd41bf74 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 18 Apr 2024 09:55:03 +0200 Subject: [PATCH 52/70] Auto-close PRs on subtree-splits --- .gitattributes | 1 + .github/PULL_REQUEST_TEMPLATE.md | 8 +++++ .github/workflows/check-subtree-split.yml | 37 +++++++++++++++++++++++ 3 files changed, 46 insertions(+) create mode 100644 .gitattributes create mode 100644 .github/PULL_REQUEST_TEMPLATE.md create mode 100644 .github/workflows/check-subtree-split.yml diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..8253128 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +/.git* export-ignore diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..4689c4d --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,8 @@ +Please do not submit any Pull Requests here. They will be closed. +--- + +Please submit your PR here instead: +https://github.com/symfony/symfony + +This repository is what we call a "subtree split": a read-only subset of that main repository. +We're looking forward to your PR there! diff --git a/.github/workflows/check-subtree-split.yml b/.github/workflows/check-subtree-split.yml new file mode 100644 index 0000000..16be48b --- /dev/null +++ b/.github/workflows/check-subtree-split.yml @@ -0,0 +1,37 @@ +name: Check subtree split + +on: + pull_request_target: + +jobs: + close-pull-request: + runs-on: ubuntu-latest + + steps: + - name: Close pull request + uses: actions/github-script@v6 + with: + script: | + if (context.repo.owner === "symfony") { + github.rest.issues.createComment({ + owner: "symfony", + repo: context.repo.repo, + issue_number: context.issue.number, + body: ` + Thanks for your Pull Request! We love contributions. + + However, you should instead open your PR on the main repository: + https://github.com/symfony/symfony + + This repository is what we call a "subtree split": a read-only subset of that main repository. + We're looking forward to your PR there! + ` + }); + + github.rest.pulls.update({ + owner: "symfony", + repo: context.repo.repo, + pull_number: context.issue.number, + state: "closed" + }); + } From be6b9b7ab20ae8a0c459e3ad2d8550ef57bad9d4 Mon Sep 17 00:00:00 2001 From: sam-bee <130986804+sam-bee@users.noreply.github.com> Date: Mon, 13 May 2024 12:43:33 +0100 Subject: [PATCH 53/70] Because PHP 8.4 is adding deprecation warnings for non-nullable parameters with null default, change typehints --- Test/TestHttpServer.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Test/TestHttpServer.php b/Test/TestHttpServer.php index 2a27847..35bfd45 100644 --- a/Test/TestHttpServer.php +++ b/Test/TestHttpServer.php @@ -21,7 +21,7 @@ class TestHttpServer /** * @param string|null $workingDirectory */ - public static function start(int $port = 8057/* , string $workingDirectory = null */): Process + public static function start(int $port = 8057/* , ?string $workingDirectory = null */): Process { $workingDirectory = \func_get_args()[1] ?? __DIR__.'/Fixtures/web'; From 11519092f670e5884be07fe2122b6b2d303672f9 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Fri, 31 May 2024 16:33:22 +0200 Subject: [PATCH 54/70] Revert "minor #54653 Auto-close PRs on subtree-splits (nicolas-grekas)" This reverts commit 2c9352dd91ebaf37b8a3e3c26fd8e1306df2fb73, reversing changes made to 18c3e87f1512be2cc50e90235b144b13bc347258. --- .gitattributes | 1 - .github/PULL_REQUEST_TEMPLATE.md | 8 ----- .github/workflows/check-subtree-split.yml | 37 ----------------------- 3 files changed, 46 deletions(-) delete mode 100644 .gitattributes delete mode 100644 .github/PULL_REQUEST_TEMPLATE.md delete mode 100644 .github/workflows/check-subtree-split.yml diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index 8253128..0000000 --- a/.gitattributes +++ /dev/null @@ -1 +0,0 @@ -/.git* export-ignore diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md deleted file mode 100644 index 4689c4d..0000000 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ /dev/null @@ -1,8 +0,0 @@ -Please do not submit any Pull Requests here. They will be closed. ---- - -Please submit your PR here instead: -https://github.com/symfony/symfony - -This repository is what we call a "subtree split": a read-only subset of that main repository. -We're looking forward to your PR there! diff --git a/.github/workflows/check-subtree-split.yml b/.github/workflows/check-subtree-split.yml deleted file mode 100644 index 16be48b..0000000 --- a/.github/workflows/check-subtree-split.yml +++ /dev/null @@ -1,37 +0,0 @@ -name: Check subtree split - -on: - pull_request_target: - -jobs: - close-pull-request: - runs-on: ubuntu-latest - - steps: - - name: Close pull request - uses: actions/github-script@v6 - with: - script: | - if (context.repo.owner === "symfony") { - github.rest.issues.createComment({ - owner: "symfony", - repo: context.repo.repo, - issue_number: context.issue.number, - body: ` - Thanks for your Pull Request! We love contributions. - - However, you should instead open your PR on the main repository: - https://github.com/symfony/symfony - - This repository is what we call a "subtree split": a read-only subset of that main repository. - We're looking forward to your PR there! - ` - }); - - github.rest.pulls.update({ - owner: "symfony", - repo: context.repo.repo, - pull_number: context.issue.number, - state: "closed" - }); - } From e0a734540be642c536bd5d2eb420046c695aaa55 Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Tue, 9 Jul 2024 14:08:44 +0200 Subject: [PATCH 55/70] [Contracts][HttpClient] Skip tests when zlib's `ob_gzhandler()` doesn't exist --- Test/HttpClientTestCase.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Test/HttpClientTestCase.php b/Test/HttpClientTestCase.php index 994e926..10c6395 100644 --- a/Test/HttpClientTestCase.php +++ b/Test/HttpClientTestCase.php @@ -25,6 +25,10 @@ abstract class HttpClientTestCase extends TestCase { public static function setUpBeforeClass(): void { + if (!function_exists('ob_gzhandler')) { + static::markTestSkipped('The "ob_gzhandler" function is not available.'); + } + TestHttpServer::start(); } From 114fdefbc093649105b6a40767762edf30a696f6 Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Mon, 5 Aug 2024 09:12:25 +0200 Subject: [PATCH 56/70] Fix multiple CS errors --- Test/HttpClientTestCase.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Test/HttpClientTestCase.php b/Test/HttpClientTestCase.php index 39fd701..12d1c87 100644 --- a/Test/HttpClientTestCase.php +++ b/Test/HttpClientTestCase.php @@ -25,7 +25,7 @@ abstract class HttpClientTestCase extends TestCase { public static function setUpBeforeClass(): void { - if (!function_exists('ob_gzhandler')) { + if (!\function_exists('ob_gzhandler')) { static::markTestSkipped('The "ob_gzhandler" function is not available.'); } From c0ab4b1d5e1fef0aac02ce57517f51cda082753f Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Thu, 5 Sep 2024 11:40:18 +0200 Subject: [PATCH 57/70] make test case classes compatible with PHPUnit 10+ --- Test/HttpClientTestCase.php | 4 ++++ composer.json | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Test/HttpClientTestCase.php b/Test/HttpClientTestCase.php index 12d1c87..14a7c1d 100644 --- a/Test/HttpClientTestCase.php +++ b/Test/HttpClientTestCase.php @@ -11,6 +11,7 @@ namespace Symfony\Contracts\HttpClient\Test; +use PHPUnit\Framework\Attributes\RequiresPhpExtension; use PHPUnit\Framework\TestCase; use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface; use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface; @@ -1013,6 +1014,7 @@ public function testNoProxy() /** * @requires extension zlib */ + #[RequiresPhpExtension('zlib')] public function testAutoEncodingRequest() { $client = $this->getHttpClient(__FUNCTION__); @@ -1086,6 +1088,7 @@ public function testInformationalResponseStream() /** * @requires extension zlib */ + #[RequiresPhpExtension('zlib')] public function testUserlandEncodingRequest() { $client = $this->getHttpClient(__FUNCTION__); @@ -1108,6 +1111,7 @@ public function testUserlandEncodingRequest() /** * @requires extension zlib */ + #[RequiresPhpExtension('zlib')] public function testGzipBroken() { $client = $this->getHttpClient(__FUNCTION__); diff --git a/composer.json b/composer.json index efb146e..a67a753 100644 --- a/composer.json +++ b/composer.json @@ -27,7 +27,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-main": "3.5-dev" + "dev-main": "3.6-dev" }, "thanks": { "name": "symfony/contracts", From 2b2b17054328a37c98392668fdc210911219043a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?= Date: Mon, 23 Sep 2024 11:24:18 +0200 Subject: [PATCH 58/70] Add PR template and auto-close PR on subtree split repositories --- .gitattributes | 1 + .github/PULL_REQUEST_TEMPLATE.md | 8 ++++++++ .github/workflows/close-pull-request.yml | 20 ++++++++++++++++++++ 3 files changed, 29 insertions(+) create mode 100644 .gitattributes create mode 100644 .github/PULL_REQUEST_TEMPLATE.md create mode 100644 .github/workflows/close-pull-request.yml diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..8253128 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +/.git* export-ignore diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..4689c4d --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,8 @@ +Please do not submit any Pull Requests here. They will be closed. +--- + +Please submit your PR here instead: +https://github.com/symfony/symfony + +This repository is what we call a "subtree split": a read-only subset of that main repository. +We're looking forward to your PR there! diff --git a/.github/workflows/close-pull-request.yml b/.github/workflows/close-pull-request.yml new file mode 100644 index 0000000..e55b478 --- /dev/null +++ b/.github/workflows/close-pull-request.yml @@ -0,0 +1,20 @@ +name: Close Pull Request + +on: + pull_request_target: + types: [opened] + +jobs: + run: + runs-on: ubuntu-latest + steps: + - uses: superbrothers/close-pull-request@v3 + with: + comment: | + Thanks for your Pull Request! We love contributions. + + However, you should instead open your PR on the main repository: + https://github.com/symfony/symfony + + This repository is what we call a "subtree split": a read-only subset of that main repository. + We're looking forward to your PR there! From 075fadd18649068440dae4667a0ab98293535235 Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Thu, 26 Sep 2024 10:09:09 +0200 Subject: [PATCH 59/70] Remove unused imports --- ResponseInterface.php | 1 - 1 file changed, 1 deletion(-) diff --git a/ResponseInterface.php b/ResponseInterface.php index 387345c..a425590 100644 --- a/ResponseInterface.php +++ b/ResponseInterface.php @@ -13,7 +13,6 @@ use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface; use Symfony\Contracts\HttpClient\Exception\DecodingExceptionInterface; -use Symfony\Contracts\HttpClient\Exception\ExceptionInterface; use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface; use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface; use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; From 8d249f4580a6dff0451cd23801c794b48c977a87 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Fri, 8 Nov 2024 09:23:38 +0100 Subject: [PATCH 60/70] [HttpClient] Resolve hostnames in NoPrivateNetworkHttpClient --- HttpClientInterface.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/HttpClientInterface.php b/HttpClientInterface.php index 73a7cb5..c0d839f 100644 --- a/HttpClientInterface.php +++ b/HttpClientInterface.php @@ -48,9 +48,11 @@ interface HttpClientInterface 'buffer' => true, // bool|resource|\Closure - whether the content of the response should be buffered or not, // or a stream resource where the response body should be written, // or a closure telling if/where the response should be buffered based on its headers - 'on_progress' => null, // callable(int $dlNow, int $dlSize, array $info) - throwing any exceptions MUST abort - // the request; it MUST be called on DNS resolution, on arrival of headers and on - // completion; it SHOULD be called on upload/download of data and at least 1/s + 'on_progress' => null, // callable(int $dlNow, int $dlSize, array $info, ?Closure $resolve = null) - throwing any + // exceptions MUST abort the request; it MUST be called on connection, on headers and on + // completion; it SHOULD be called on upload/download of data and at least 1/s; + // if passed, $resolve($host) / $resolve($host, $ip) can be called to read / populate + // the DNS cache respectively 'resolve' => [], // string[] - a map of host to IP address that SHOULD replace DNS resolution 'proxy' => null, // string - by default, the proxy-related env vars handled by curl SHOULD be honored 'no_proxy' => null, // string - a comma separated list of hosts that do not require a proxy to be reached From bc7bed06ff4bad379a0f880eb35f1bf38f8aded4 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 12 Nov 2024 11:01:06 +0100 Subject: [PATCH 61/70] Work around parse_url() bug (bis) --- Test/Fixtures/web/index.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Test/Fixtures/web/index.php b/Test/Fixtures/web/index.php index cf947cb..b532601 100644 --- a/Test/Fixtures/web/index.php +++ b/Test/Fixtures/web/index.php @@ -98,6 +98,12 @@ } break; + case '/302-no-scheme': + if (!isset($vars['HTTP_AUTHORIZATION'])) { + header('Location: localhost:8067', true, 302); + } + break; + case '/302/relative': header('Location: ..', true, 302); break; From f8a74a45743303a63dd930a5f018c53f7d998d77 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Wed, 13 Nov 2024 18:52:25 +0100 Subject: [PATCH 62/70] [HttpClient] Fix catching some invalid Location headers --- Test/Fixtures/web/index.php | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/Test/Fixtures/web/index.php b/Test/Fixtures/web/index.php index b532601..fafab19 100644 --- a/Test/Fixtures/web/index.php +++ b/Test/Fixtures/web/index.php @@ -31,7 +31,7 @@ $json = json_encode($vars, \JSON_PRETTY_PRINT | \JSON_UNESCAPED_SLASHES | \JSON_UNESCAPED_UNICODE); -switch ($vars['REQUEST_URI']) { +switch (parse_url($vars['REQUEST_URI'], \PHP_URL_PATH)) { default: exit; @@ -94,13 +94,8 @@ case '/302': if (!isset($vars['HTTP_AUTHORIZATION'])) { - header('Location: http://localhost:8057/', true, 302); - } - break; - - case '/302-no-scheme': - if (!isset($vars['HTTP_AUTHORIZATION'])) { - header('Location: localhost:8067', true, 302); + $location = $_GET['location'] ?? 'http://localhost:8057/'; + header('Location: '.$location, true, 302); } break; From af1a3f284c8b1b6883c175775d47223e60002b11 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 18 Nov 2024 17:08:46 +0100 Subject: [PATCH 63/70] [HttpClient] Fix option "bindto" with IPv6 addresses --- Test/Fixtures/web/index.php | 32 +++++++++++++++++++------------- Test/HttpClientTestCase.php | 27 +++++++++++++++++++++++++++ Test/TestHttpServer.php | 6 +++--- 3 files changed, 49 insertions(+), 16 deletions(-) diff --git a/Test/Fixtures/web/index.php b/Test/Fixtures/web/index.php index fafab19..db4d551 100644 --- a/Test/Fixtures/web/index.php +++ b/Test/Fixtures/web/index.php @@ -12,20 +12,26 @@ $_POST['content-type'] = $_SERVER['HTTP_CONTENT_TYPE'] ?? '?'; } +$headers = [ + 'SERVER_PROTOCOL', + 'SERVER_NAME', + 'REQUEST_URI', + 'REQUEST_METHOD', + 'PHP_AUTH_USER', + 'PHP_AUTH_PW', + 'REMOTE_ADDR', + 'REMOTE_PORT', +]; + +foreach ($headers as $k) { + if (isset($_SERVER[$k])) { + $vars[$k] = $_SERVER[$k]; + } +} + foreach ($_SERVER as $k => $v) { - switch ($k) { - default: - if (0 !== strpos($k, 'HTTP_')) { - continue 2; - } - // no break - case 'SERVER_NAME': - case 'SERVER_PROTOCOL': - case 'REQUEST_URI': - case 'REQUEST_METHOD': - case 'PHP_AUTH_USER': - case 'PHP_AUTH_PW': - $vars[$k] = $v; + if (0 === strpos($k, 'HTTP_')) { + $vars[$k] = $v; } } diff --git a/Test/HttpClientTestCase.php b/Test/HttpClientTestCase.php index 10c6395..eb10dbe 100644 --- a/Test/HttpClientTestCase.php +++ b/Test/HttpClientTestCase.php @@ -36,6 +36,7 @@ public static function tearDownAfterClass(): void { TestHttpServer::stop(8067); TestHttpServer::stop(8077); + TestHttpServer::stop(8087); } abstract protected function getHttpClient(string $testCase): HttpClientInterface; @@ -1152,4 +1153,30 @@ public function testWithOptions() $response = $client2->request('GET', '/'); $this->assertSame(200, $response->getStatusCode()); } + + public function testBindToPort() + { + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('GET', 'http://localhost:8057', ['bindto' => '127.0.0.1:9876']); + $response->getStatusCode(); + + $vars = $response->toArray(); + + self::assertSame('127.0.0.1', $vars['REMOTE_ADDR']); + self::assertSame('9876', $vars['REMOTE_PORT']); + } + + public function testBindToPortV6() + { + TestHttpServer::start(8087, '[::1]'); + + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('GET', 'http://[::1]:8087', ['bindto' => '[::1]:9876']); + $response->getStatusCode(); + + $vars = $response->toArray(); + + self::assertSame('::1', $vars['REMOTE_ADDR']); + self::assertSame('9876', $vars['REMOTE_PORT']); + } } diff --git a/Test/TestHttpServer.php b/Test/TestHttpServer.php index 463b4b7..d8b828c 100644 --- a/Test/TestHttpServer.php +++ b/Test/TestHttpServer.php @@ -21,7 +21,7 @@ class TestHttpServer /** * @return Process */ - public static function start(int $port = 8057) + public static function start(int $port = 8057, $ip = '127.0.0.1') { if (isset(self::$process[$port])) { self::$process[$port]->stop(); @@ -32,14 +32,14 @@ public static function start(int $port = 8057) } $finder = new PhpExecutableFinder(); - $process = new Process(array_merge([$finder->find(false)], $finder->findArguments(), ['-dopcache.enable=0', '-dvariables_order=EGPCS', '-S', '127.0.0.1:'.$port])); + $process = new Process(array_merge([$finder->find(false)], $finder->findArguments(), ['-dopcache.enable=0', '-dvariables_order=EGPCS', '-S', $ip.':'.$port])); $process->setWorkingDirectory(__DIR__.'/Fixtures/web'); $process->start(); self::$process[$port] = $process; do { usleep(50000); - } while (!@fopen('http://127.0.0.1:'.$port, 'r')); + } while (!@fopen('http://'.$ip.':'.$port, 'r')); return $process; } From e3f235072d7c52d2e406ef704c8f89051e769341 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 18 Nov 2024 18:21:26 +0100 Subject: [PATCH 64/70] [HttpClient] Fix option "resolve" with IPv6 addresses --- Test/HttpClientTestCase.php | 19 +++++++++++++++++-- Test/TestHttpServer.php | 9 ++++++++- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/Test/HttpClientTestCase.php b/Test/HttpClientTestCase.php index eb10dbe..3ec7854 100644 --- a/Test/HttpClientTestCase.php +++ b/Test/HttpClientTestCase.php @@ -735,6 +735,18 @@ public function testIdnResolve() $this->assertSame(200, $response->getStatusCode()); } + public function testIPv6Resolve() + { + TestHttpServer::start(-8087, '[::1]'); + + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('GET', 'http://symfony.com:8087/', [ + 'resolve' => ['symfony.com' => '::1'], + ]); + + $this->assertSame(200, $response->getStatusCode()); + } + public function testNotATimeout() { $client = $this->getHttpClient(__FUNCTION__); @@ -1168,7 +1180,7 @@ public function testBindToPort() public function testBindToPortV6() { - TestHttpServer::start(8087, '[::1]'); + TestHttpServer::start(-8087); $client = $this->getHttpClient(__FUNCTION__); $response = $client->request('GET', 'http://[::1]:8087', ['bindto' => '[::1]:9876']); @@ -1177,6 +1189,9 @@ public function testBindToPortV6() $vars = $response->toArray(); self::assertSame('::1', $vars['REMOTE_ADDR']); - self::assertSame('9876', $vars['REMOTE_PORT']); + + if ('\\' !== \DIRECTORY_SEPARATOR) { + self::assertSame('9876', $vars['REMOTE_PORT']); + } } } diff --git a/Test/TestHttpServer.php b/Test/TestHttpServer.php index d8b828c..0bea6de 100644 --- a/Test/TestHttpServer.php +++ b/Test/TestHttpServer.php @@ -21,8 +21,15 @@ class TestHttpServer /** * @return Process */ - public static function start(int $port = 8057, $ip = '127.0.0.1') + public static function start(int $port = 8057) { + if (0 > $port) { + $port = -$port; + $ip = '[::1]'; + } else { + $ip = '127.0.0.1'; + } + if (isset(self::$process[$port])) { self::$process[$port]->stop(); } else { From b7f97c82741cc30b941abe8ab395e10e1802891c Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 19 Nov 2024 11:11:14 +0100 Subject: [PATCH 65/70] Fix typo --- Test/HttpClientTestCase.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Test/HttpClientTestCase.php b/Test/HttpClientTestCase.php index 3ec7854..2a70ea6 100644 --- a/Test/HttpClientTestCase.php +++ b/Test/HttpClientTestCase.php @@ -737,7 +737,7 @@ public function testIdnResolve() public function testIPv6Resolve() { - TestHttpServer::start(-8087, '[::1]'); + TestHttpServer::start(-8087); $client = $this->getHttpClient(__FUNCTION__); $response = $client->request('GET', 'http://symfony.com:8087/', [ From fbfd73095ae958935396cf2243c47b01c677750c Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Fri, 22 Nov 2024 15:14:45 +0100 Subject: [PATCH 66/70] [HttpClient] Various cleanups after recent changes --- HttpClientInterface.php | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/HttpClientInterface.php b/HttpClientInterface.php index c0d839f..dac97ba 100644 --- a/HttpClientInterface.php +++ b/HttpClientInterface.php @@ -48,11 +48,9 @@ interface HttpClientInterface 'buffer' => true, // bool|resource|\Closure - whether the content of the response should be buffered or not, // or a stream resource where the response body should be written, // or a closure telling if/where the response should be buffered based on its headers - 'on_progress' => null, // callable(int $dlNow, int $dlSize, array $info, ?Closure $resolve = null) - throwing any - // exceptions MUST abort the request; it MUST be called on connection, on headers and on - // completion; it SHOULD be called on upload/download of data and at least 1/s; - // if passed, $resolve($host) / $resolve($host, $ip) can be called to read / populate - // the DNS cache respectively + 'on_progress' => null, // callable(int $dlNow, int $dlSize, array $info) - throwing any exceptions MUST abort the + // request; it MUST be called on connection, on headers and on completion; it SHOULD be + // called on upload/download of data and at least 1/s 'resolve' => [], // string[] - a map of host to IP address that SHOULD replace DNS resolution 'proxy' => null, // string - by default, the proxy-related env vars handled by curl SHOULD be honored 'no_proxy' => null, // string - a comma separated list of hosts that do not require a proxy to be reached From 48ef1d0a082885877b664332b9427662065a360c Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 28 Nov 2024 08:55:08 +0100 Subject: [PATCH 67/70] [HttpClient] Fix streaming and redirecting with NoPrivateNetworkHttpClient --- Test/HttpClientTestCase.php | 1 - 1 file changed, 1 deletion(-) diff --git a/Test/HttpClientTestCase.php b/Test/HttpClientTestCase.php index 2a70ea6..08825f7 100644 --- a/Test/HttpClientTestCase.php +++ b/Test/HttpClientTestCase.php @@ -36,7 +36,6 @@ public static function tearDownAfterClass(): void { TestHttpServer::stop(8067); TestHttpServer::stop(8077); - TestHttpServer::stop(8087); } abstract protected function getHttpClient(string $testCase): HttpClientInterface; From c2ecd5833d09e718343e315051398f8e76e0f36e Mon Sep 17 00:00:00 2001 From: Kurt Thiemann Date: Mon, 2 Dec 2024 12:18:11 +0100 Subject: [PATCH 68/70] [HttpClient] Always set CURLOPT_CUSTOMREQUEST to the correct HTTP method in CurlHttpClient --- Test/Fixtures/web/index.php | 1 + 1 file changed, 1 insertion(+) diff --git a/Test/Fixtures/web/index.php b/Test/Fixtures/web/index.php index a750017..59033d5 100644 --- a/Test/Fixtures/web/index.php +++ b/Test/Fixtures/web/index.php @@ -42,6 +42,7 @@ exit; case '/head': + header('X-Request-Vars: '.json_encode($vars, \JSON_UNESCAPED_SLASHES | \JSON_UNESCAPED_UNICODE)); header('Content-Length: '.strlen($json), true); break; From a9ba2374583cf6cb157aca5e3b1f10ec83e5d814 Mon Sep 17 00:00:00 2001 From: Kurt Thiemann Date: Thu, 5 Dec 2024 14:35:19 +0100 Subject: [PATCH 69/70] [HttpClient] Test POST to GET redirects --- Test/Fixtures/web/index.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Test/Fixtures/web/index.php b/Test/Fixtures/web/index.php index 59033d5..399f8bd 100644 --- a/Test/Fixtures/web/index.php +++ b/Test/Fixtures/web/index.php @@ -199,6 +199,16 @@ ]); exit; + + case '/custom': + if (isset($_GET['status'])) { + http_response_code((int) $_GET['status']); + } + if (isset($_GET['headers']) && is_array($_GET['headers'])) { + foreach ($_GET['headers'] as $header) { + header($header); + } + } } header('Content-Type: application/json', true); From 75d7043853a42837e68111812f4d964b01e5101c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dalibor=20Karlovi=C4=87?= Date: Mon, 28 Apr 2025 17:14:25 +0200 Subject: [PATCH 70/70] align the type to the one in the human description --- ResponseInterface.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ResponseInterface.php b/ResponseInterface.php index a425590..44611cd 100644 --- a/ResponseInterface.php +++ b/ResponseInterface.php @@ -36,7 +36,7 @@ public function getStatusCode(): int; * * @param bool $throw Whether an exception should be thrown on 3/4/5xx status codes * - * @return string[][] The headers of the response keyed by header names in lowercase + * @return array> The headers of the response keyed by header names in lowercase * * @throws TransportExceptionInterface When a network error occurs * @throws RedirectionExceptionInterface On a 3xx when $throw is true and the "max_redirects" option has been reached