Skip to content

Commit 6aba1a1

Browse files
[HttpClient] Add HttpClientInterface::withOptions()
1 parent e872db4 commit 6aba1a1

22 files changed

+150
-41
lines changed

composer.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@
188188
"url": "src/Symfony/Contracts",
189189
"options": {
190190
"versions": {
191-
"symfony/contracts": "2.3.x-dev"
191+
"symfony/contracts": "2.4.x-dev"
192192
}
193193
}
194194
}

src/Symfony/Component/HttpClient/AsyncDecoratorTrait.php

+11
Original file line numberDiff line numberDiff line change
@@ -51,4 +51,15 @@ public function stream($responses, float $timeout = null): ResponseStreamInterfa
5151

5252
return new ResponseStream(AsyncResponse::stream($responses, $timeout, static::class));
5353
}
54+
55+
/**
56+
* {@inheritdoc}
57+
*/
58+
public function withOptions(array $options): self
59+
{
60+
$clone = clone $this;
61+
$clone->client = $this->client->withOptions($options);
62+
63+
return $clone;
64+
}
5465
}

src/Symfony/Component/HttpClient/CHANGELOG.md

+5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
CHANGELOG
22
=========
33

4+
5.3
5+
---
6+
7+
* Implement `HttpClientInterface::withOptions()` from `symfony/contracts` v2.4
8+
49
5.2.0
510
-----
611

src/Symfony/Component/HttpClient/CurlHttpClient.php

+3-25
Original file line numberDiff line numberDiff line change
@@ -341,30 +341,8 @@ public function stream($responses, float $timeout = null): ResponseStreamInterfa
341341

342342
public function reset()
343343
{
344-
if ($this->logger) {
345-
foreach ($this->multi->pushedResponses as $url => $response) {
346-
$this->logger->debug(sprintf('Unused pushed response: "%s"', $url));
347-
}
348-
}
349-
350-
$this->multi->pushedResponses = [];
351-
$this->multi->dnsCache->evictions = $this->multi->dnsCache->evictions ?: $this->multi->dnsCache->removals;
352-
$this->multi->dnsCache->removals = $this->multi->dnsCache->hostnames = [];
353-
354-
if (\is_resource($this->multi->handle) || $this->multi->handle instanceof \CurlMultiHandle) {
355-
if (\defined('CURLMOPT_PUSHFUNCTION')) {
356-
curl_multi_setopt($this->multi->handle, \CURLMOPT_PUSHFUNCTION, null);
357-
}
358-
359-
$active = 0;
360-
while (\CURLM_CALL_MULTI_PERFORM === curl_multi_exec($this->multi->handle, $active));
361-
}
362-
363-
foreach ($this->multi->openHandles as [$ch]) {
364-
if (\is_resource($ch) || $ch instanceof \CurlHandle) {
365-
curl_setopt($ch, \CURLOPT_VERBOSE, false);
366-
}
367-
}
344+
$this->multi->logger = $this->logger;
345+
$this->multi->reset();
368346
}
369347

370348
public function __sleep()
@@ -379,7 +357,7 @@ public function __wakeup()
379357

380358
public function __destruct()
381359
{
382-
$this->reset();
360+
$this->multi->logger = $this->logger;
383361
}
384362

385363
private function handlePush($parent, $pushed, array $requestHeaders, int $maxPendingPushes): int

src/Symfony/Component/HttpClient/EventSourceHttpClient.php

+3-2
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,9 @@
2626
*/
2727
final class EventSourceHttpClient implements HttpClientInterface
2828
{
29-
use AsyncDecoratorTrait;
30-
use HttpClientTrait;
29+
use AsyncDecoratorTrait, HttpClientTrait {
30+
AsyncDecoratorTrait::withOptions insteadof HttpClientTrait;
31+
}
3132

3233
private $reconnectionTime;
3334

src/Symfony/Component/HttpClient/HttpClientTrait.php

+12-1
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,25 @@
1717
/**
1818
* Provides the common logic from writing HttpClientInterface implementations.
1919
*
20-
* All methods are static to prevent implementers from creating memory leaks via circular references.
20+
* All private methods are static to prevent implementers from creating memory leaks via circular references.
2121
*
2222
* @author Nicolas Grekas <p@tchwork.com>
2323
*/
2424
trait HttpClientTrait
2525
{
2626
private static $CHUNK_SIZE = 16372;
2727

28+
/**
29+
* {@inheritdoc}
30+
*/
31+
public function withOptions(array $options): self
32+
{
33+
$clone = clone $this;
34+
$clone->defaultOptions = self::mergeDefaultOptions($options, $this->defaultOptions);
35+
36+
return $clone;
37+
}
38+
2839
/**
2940
* Validates and normalizes method, URL and options, and merges them with defaults.
3041
*

src/Symfony/Component/HttpClient/Internal/CurlClientState.php

+47
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111

1212
namespace Symfony\Component\HttpClient\Internal;
1313

14+
use Psr\Log\LoggerInterface;
15+
1416
/**
1517
* Internal representation of the cURL client's state.
1618
*
@@ -29,10 +31,55 @@ final class CurlClientState extends ClientState
2931
/** @var float[] */
3032
public $pauseExpiries = [];
3133
public $execCounter = \PHP_INT_MIN;
34+
/** @var LoggerInterface|null */
35+
public $logger;
3236

3337
public function __construct()
3438
{
3539
$this->handle = curl_multi_init();
3640
$this->dnsCache = new DnsCache();
3741
}
42+
43+
public function reset()
44+
{
45+
if ($this->logger) {
46+
foreach ($this->pushedResponses as $url => $response) {
47+
$this->logger->debug(sprintf('Unused pushed response: "%s"', $url));
48+
}
49+
}
50+
51+
$this->pushedResponses = [];
52+
$this->dnsCache->evictions = $this->dnsCache->evictions ?: $this->dnsCache->removals;
53+
$this->dnsCache->removals = $this->dnsCache->hostnames = [];
54+
55+
if (\is_resource($this->handle) || $this->handle instanceof \CurlMultiHandle) {
56+
if (\defined('CURLMOPT_PUSHFUNCTION')) {
57+
curl_multi_setopt($this->handle, \CURLMOPT_PUSHFUNCTION, null);
58+
}
59+
60+
$active = 0;
61+
while (\CURLM_CALL_MULTI_PERFORM === curl_multi_exec($this->handle, $active));
62+
}
63+
64+
foreach ($this->openHandles as [$ch]) {
65+
if (\is_resource($ch) || $ch instanceof \CurlHandle) {
66+
curl_setopt($ch, \CURLOPT_VERBOSE, false);
67+
}
68+
}
69+
}
70+
71+
public function __sleep()
72+
{
73+
throw new \BadMethodCallException('Cannot serialize '.__CLASS__);
74+
}
75+
76+
public function __wakeup()
77+
{
78+
throw new \BadMethodCallException('Cannot unserialize '.__CLASS__);
79+
}
80+
81+
public function __destruct()
82+
{
83+
$this->reset();
84+
}
3885
}

src/Symfony/Component/HttpClient/MockHttpClient.php

+3-3
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ class MockHttpClient implements HttpClientInterface
2828
use HttpClientTrait;
2929

3030
private $responseFactory;
31-
private $baseUri;
3231
private $requestsCount = 0;
32+
private $defaultOptions = self::OPTIONS_DEFAULTS;
3333

3434
/**
3535
* @param callable|callable[]|ResponseInterface|ResponseInterface[]|iterable|null $responseFactory
@@ -47,15 +47,15 @@ public function __construct($responseFactory = null, string $baseUri = null)
4747
}
4848

4949
$this->responseFactory = $responseFactory;
50-
$this->baseUri = $baseUri;
50+
$this->defaultOptions['base_uri'] = $baseUri;
5151
}
5252

5353
/**
5454
* {@inheritdoc}
5555
*/
5656
public function request(string $method, string $url, array $options = []): ResponseInterface
5757
{
58-
[$url, $options] = $this->prepareRequest($method, $url, $options, ['base_uri' => $this->baseUri], true);
58+
[$url, $options] = $this->prepareRequest($method, $url, $options, $this->defaultOptions, true);
5959
$url = implode('', $url);
6060

6161
if (null === $this->responseFactory) {

src/Symfony/Component/HttpClient/NoPrivateNetworkHttpClient.php

+11
Original file line numberDiff line numberDiff line change
@@ -110,4 +110,15 @@ public function setLogger(LoggerInterface $logger): void
110110
$this->client->setLogger($logger);
111111
}
112112
}
113+
114+
/**
115+
* {@inheritdoc}
116+
*/
117+
public function withOptions(array $options): self
118+
{
119+
$clone = clone $this;
120+
$clone->client = $this->client->withOptions($options);
121+
122+
return $clone;
123+
}
113124
}

src/Symfony/Component/HttpClient/ScopingHttpClient.php

+11
Original file line numberDiff line numberDiff line change
@@ -110,4 +110,15 @@ public function setLogger(LoggerInterface $logger): void
110110
$this->client->setLogger($logger);
111111
}
112112
}
113+
114+
/**
115+
* {@inheritdoc}
116+
*/
117+
public function withOptions(array $options): self
118+
{
119+
$clone = clone $this;
120+
$clone->client = $this->client->withOptions($options);
121+
122+
return $clone;
123+
}
113124
}

src/Symfony/Component/HttpClient/TraceableHttpClient.php

+11
Original file line numberDiff line numberDiff line change
@@ -105,4 +105,15 @@ public function setLogger(LoggerInterface $logger): void
105105
$this->client->setLogger($logger);
106106
}
107107
}
108+
109+
/**
110+
* {@inheritdoc}
111+
*/
112+
public function withOptions(array $options): self
113+
{
114+
$clone = clone $this;
115+
$clone->client = $this->client->withOptions($options);
116+
117+
return $clone;
118+
}
108119
}

src/Symfony/Component/HttpClient/composer.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,12 @@
1818
"php-http/async-client-implementation": "*",
1919
"php-http/client-implementation": "*",
2020
"psr/http-client-implementation": "1.0",
21-
"symfony/http-client-implementation": "2.2"
21+
"symfony/http-client-implementation": "2.4"
2222
},
2323
"require": {
2424
"php": ">=7.2.5",
2525
"psr/log": "^1.0",
26-
"symfony/http-client-contracts": "^2.2",
26+
"symfony/http-client-contracts": "^2.4",
2727
"symfony/polyfill-php73": "^1.11",
2828
"symfony/polyfill-php80": "^1.15",
2929
"symfony/service-contracts": "^1.0|^2"

src/Symfony/Contracts/CHANGELOG.md

+5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
CHANGELOG
22
=========
33

4+
2.4
5+
---
6+
7+
* Add `HttpClientInterface::withOptions()`
8+
49
2.3.0
510
-----
611

src/Symfony/Contracts/Cache/composer.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
"minimum-stability": "dev",
2929
"extra": {
3030
"branch-alias": {
31-
"dev-main": "2.3-dev"
31+
"dev-main": "2.4-dev"
3232
},
3333
"thanks": {
3434
"name": "symfony/contracts",

src/Symfony/Contracts/Deprecation/composer.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
"minimum-stability": "dev",
2626
"extra": {
2727
"branch-alias": {
28-
"dev-main": "2.3-dev"
28+
"dev-main": "2.4-dev"
2929
},
3030
"thanks": {
3131
"name": "symfony/contracts",

src/Symfony/Contracts/EventDispatcher/composer.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
"minimum-stability": "dev",
2929
"extra": {
3030
"branch-alias": {
31-
"dev-main": "2.3-dev"
31+
"dev-main": "2.4-dev"
3232
},
3333
"thanks": {
3434
"name": "symfony/contracts",

src/Symfony/Contracts/HttpClient/HttpClientInterface.php

+2
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
*
2020
* @see HttpClientTestCase for a reference test suite
2121
*
22+
* @method static withOptions(array $options) Returns a new instance of the client with new default options
23+
*
2224
* @author Nicolas Grekas <p@tchwork.com>
2325
*/
2426
interface HttpClientInterface

src/Symfony/Contracts/HttpClient/Test/HttpClientTestCase.php

+16
Original file line numberDiff line numberDiff line change
@@ -1038,4 +1038,20 @@ public function testMaxDuration()
10381038

10391039
$this->assertLessThan(10, $duration);
10401040
}
1041+
1042+
public function testWithOptions()
1043+
{
1044+
$client = $this->getHttpClient(__FUNCTION__);
1045+
if (!method_exists($client, 'withOptions')) {
1046+
$this->markTestSkipped(sprintf('Not implementing "%s::withOptions()" is deprecated.', get_debug_type($client)));
1047+
}
1048+
1049+
$client2 = $client->withOptions(['base_uri' => 'http://localhost:8057/']);
1050+
1051+
$this->assertNotSame($client, $client2);
1052+
$this->assertSame(\get_class($client), \get_class($client2));
1053+
1054+
$response = $client2->request('GET', '/');
1055+
$this->assertSame(200, $response->getStatusCode());
1056+
}
10411057
}

src/Symfony/Contracts/HttpClient/composer.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
"minimum-stability": "dev",
2828
"extra": {
2929
"branch-alias": {
30-
"dev-main": "2.3-dev"
30+
"dev-main": "2.4-dev"
3131
},
3232
"thanks": {
3333
"name": "symfony/contracts",

src/Symfony/Contracts/Service/composer.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
"minimum-stability": "dev",
2929
"extra": {
3030
"branch-alias": {
31-
"dev-main": "2.3-dev"
31+
"dev-main": "2.4-dev"
3232
},
3333
"thanks": {
3434
"name": "symfony/contracts",

src/Symfony/Contracts/Translation/composer.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
"minimum-stability": "dev",
2828
"extra": {
2929
"branch-alias": {
30-
"dev-main": "2.3-dev"
30+
"dev-main": "2.4-dev"
3131
},
3232
"thanks": {
3333
"name": "symfony/contracts",

src/Symfony/Contracts/composer.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@
4949
"minimum-stability": "dev",
5050
"extra": {
5151
"branch-alias": {
52-
"dev-main": "2.3-dev"
52+
"dev-main": "2.4-dev"
5353
}
5454
}
5555
}

0 commit comments

Comments
 (0)