diff --git a/HttpClientInterface.php b/HttpClientInterface.php
index dac97ba..a7c8737 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
@@ -68,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
];
@@ -91,5 +90,10 @@ 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(ResponseInterface|iterable $responses, ?float $timeout = null): ResponseStreamInterface;
+
+ /**
+ * Returns a new instance of the client with new default options.
+ */
+ public function withOptions(array $options): static;
}
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.
diff --git a/ResponseInterface.php b/ResponseInterface.php
index 7c84a98..44611cd 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;
@@ -37,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
@@ -105,5 +104,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/Fixtures/web/index.php b/Test/Fixtures/web/index.php
index db4d551..399f8bd 100644
--- a/Test/Fixtures/web/index.php
+++ b/Test/Fixtures/web/index.php
@@ -30,7 +30,7 @@
}
foreach ($_SERVER as $k => $v) {
- if (0 === strpos($k, 'HTTP_')) {
+ if (str_starts_with($k, 'HTTP_')) {
$vars[$k] = $v;
}
}
@@ -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;
@@ -198,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);
diff --git a/Test/HttpClientTestCase.php b/Test/HttpClientTestCase.php
index 08825f7..9a528f6 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;
@@ -25,7 +26,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.');
}
@@ -145,7 +146,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);
@@ -236,13 +237,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());
@@ -256,7 +257,7 @@ public function testClientError()
$this->assertTrue($chunk->isFirst());
}
$this->fail(ClientExceptionInterface::class.' expected');
- } catch (ClientExceptionInterface $e) {
+ } catch (ClientExceptionInterface) {
}
}
@@ -276,14 +277,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);
}
@@ -293,7 +294,7 @@ public function testDnsError()
foreach ($client->stream($response) as $r => $chunk) {
}
$this->fail(TransportExceptionInterface::class.' expected');
- } catch (TransportExceptionInterface $e) {
+ } catch (TransportExceptionInterface) {
$this->addToAssertionCount(1);
}
@@ -447,7 +448,7 @@ public function testMaxRedirects()
try {
$response->getHeaders();
$this->fail(RedirectionExceptionInterface::class.' expected');
- } catch (RedirectionExceptionInterface $e) {
+ } catch (RedirectionExceptionInterface) {
}
$this->assertSame(302, $response->getStatusCode());
@@ -881,7 +882,7 @@ public function testTimeoutOnInitialize()
try {
$response->getContent();
$this->fail(TransportExceptionInterface::class.' expected');
- } catch (TransportExceptionInterface $e) {
+ } catch (TransportExceptionInterface) {
}
}
$responses = [];
@@ -914,7 +915,7 @@ public function testTimeoutOnDestruct()
try {
unset($response);
$this->fail(TransportExceptionInterface::class.' expected');
- } catch (TransportExceptionInterface $e) {
+ } catch (TransportExceptionInterface) {
}
}
@@ -1025,6 +1026,7 @@ public function testNoProxy()
/**
* @requires extension zlib
*/
+ #[RequiresPhpExtension('zlib')]
public function testAutoEncodingRequest()
{
$client = $this->getHttpClient(__FUNCTION__);
@@ -1098,6 +1100,7 @@ public function testInformationalResponseStream()
/**
* @requires extension zlib
*/
+ #[RequiresPhpExtension('zlib')]
public function testUserlandEncodingRequest()
{
$client = $this->getHttpClient(__FUNCTION__);
@@ -1120,6 +1123,7 @@ public function testUserlandEncodingRequest()
/**
* @requires extension zlib
*/
+ #[RequiresPhpExtension('zlib')]
public function testGzipBroken()
{
$client = $this->getHttpClient(__FUNCTION__);
@@ -1140,7 +1144,7 @@ public function testMaxDuration()
try {
$response->getContent();
- } catch (TransportExceptionInterface $e) {
+ } catch (TransportExceptionInterface) {
$this->addToAssertionCount(1);
}
@@ -1152,14 +1156,10 @@ 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);
- $this->assertSame(\get_class($client), \get_class($client2));
+ $this->assertSame($client::class, $client2::class);
$response = $client2->request('GET', '/');
$this->assertSame(200, $response->getStatusCode());
diff --git a/Test/TestHttpServer.php b/Test/TestHttpServer.php
index 0bea6de..ec47050 100644
--- a/Test/TestHttpServer.php
+++ b/Test/TestHttpServer.php
@@ -16,13 +16,15 @@
class TestHttpServer
{
- private static $process = [];
+ private static array $process = [];
/**
- * @return Process
+ * @param string|null $workingDirectory
*/
- public static function start(int $port = 8057)
+ public static function start(int $port = 8057/* , ?string $workingDirectory = null */): Process
{
+ $workingDirectory = \func_get_args()[1] ?? __DIR__.'/Fixtures/web';
+
if (0 > $port) {
$port = -$port;
$ip = '[::1]';
@@ -40,7 +42,7 @@ 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', $ip.':'.$port]));
- $process->setWorkingDirectory(__DIR__.'/Fixtures/web');
+ $process->setWorkingDirectory($workingDirectory);
$process->start();
self::$process[$port] = $process;
diff --git a/composer.json b/composer.json
index b76cab8..a67a753 100644
--- a/composer.json
+++ b/composer.json
@@ -16,18 +16,18 @@
}
],
"require": {
- "php": ">=7.2.5"
- },
- "suggest": {
- "symfony/http-client-implementation": ""
+ "php": ">=8.1"
},
"autoload": {
- "psr-4": { "Symfony\\Contracts\\HttpClient\\": "" }
+ "psr-4": { "Symfony\\Contracts\\HttpClient\\": "" },
+ "exclude-from-classmap": [
+ "/Test/"
+ ]
},
"minimum-stability": "dev",
"extra": {
"branch-alias": {
- "dev-main": "2.5-dev"
+ "dev-main": "3.6-dev"
},
"thanks": {
"name": "symfony/contracts",
pFad - Phonifier reborn
Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies:
Alternative Proxy
pFad Proxy
pFad v3 Proxy
pFad v4 Proxy