Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 50e00e4

Browse filesBrowse files
Merge branch '4.4' into 5.3
* 4.4: [HttpClient] fix resetting DNS/etc when calling CurlHttpClient::reset() Fix invalid guess with enumType
2 parents f1b0537 + 848a70d commit 50e00e4
Copy full SHA for 50e00e4

File tree

4 files changed

+55
-78
lines changed
Filter options

4 files changed

+55
-78
lines changed

‎CurlHttpClient.php

Copy file name to clipboardExpand all lines: CurlHttpClient.php
+3-3Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,6 @@ public function request(string $method, string $url, array $options = []): Respo
171171

172172
if ($resolve && 0x072A00 > CurlClientState::$curlVersion['version_number']) {
173173
// DNS cache removals require curl 7.42 or higher
174-
// On lower versions, we have to create a new multi handle
175174
$this->multi->reset();
176175
}
177176

@@ -288,6 +287,7 @@ public function request(string $method, string $url, array $options = []): Respo
288287
if (!$pushedResponse) {
289288
$ch = curl_init();
290289
$this->logger && $this->logger->info(sprintf('Request: "%s %s"', $method, $url));
290+
$curlopts += [\CURLOPT_SHARE => $this->multi->share];
291291
}
292292

293293
foreach ($curlopts as $opt => $value) {
@@ -311,9 +311,9 @@ public function stream($responses, float $timeout = null): ResponseStreamInterfa
311311
throw new \TypeError(sprintf('"%s()" expects parameter 1 to be an iterable of CurlResponse objects, "%s" given.', __METHOD__, get_debug_type($responses)));
312312
}
313313

314-
if (\is_resource($mh = $this->multi->handles[0] ?? null) || $mh instanceof \CurlMultiHandle) {
314+
if (\is_resource($this->multi->handle) || $this->multi->handle instanceof \CurlMultiHandle) {
315315
$active = 0;
316-
while (\CURLM_CALL_MULTI_PERFORM === curl_multi_exec($mh, $active)) {
316+
while (\CURLM_CALL_MULTI_PERFORM === curl_multi_exec($this->multi->handle, $active)) {
317317
}
318318
}
319319

‎Internal/CurlClientState.php

Copy file name to clipboardExpand all lines: Internal/CurlClientState.php
+19-30Lines changed: 19 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,10 @@
2323
*/
2424
final class CurlClientState extends ClientState
2525
{
26-
/** @var array<\CurlMultiHandle|resource> */
27-
public $handles = [];
26+
/** @var \CurlMultiHandle|resource */
27+
public $handle;
28+
/** @var \CurlShareHandle|resource */
29+
public $share;
2830
/** @var PushedResponse[] */
2931
public $pushedResponses = [];
3032
/** @var DnsCache */
@@ -37,27 +39,23 @@ final class CurlClientState extends ClientState
3739

3840
public static $curlVersion;
3941

40-
private $maxHostConnections;
41-
private $maxPendingPushes;
42-
4342
public function __construct(int $maxHostConnections, int $maxPendingPushes)
4443
{
4544
self::$curlVersion = self::$curlVersion ?? curl_version();
4645

47-
array_unshift($this->handles, $mh = curl_multi_init());
46+
$this->handle = curl_multi_init();
4847
$this->dnsCache = new DnsCache();
49-
$this->maxHostConnections = $maxHostConnections;
50-
$this->maxPendingPushes = $maxPendingPushes;
48+
$this->reset();
5149

5250
// Don't enable HTTP/1.1 pipelining: it forces responses to be sent in order
5351
if (\defined('CURLPIPE_MULTIPLEX')) {
54-
curl_multi_setopt($mh, \CURLMOPT_PIPELINING, \CURLPIPE_MULTIPLEX);
52+
curl_multi_setopt($this->handle, \CURLMOPT_PIPELINING, \CURLPIPE_MULTIPLEX);
5553
}
5654
if (\defined('CURLMOPT_MAX_HOST_CONNECTIONS')) {
57-
$maxHostConnections = curl_multi_setopt($mh, \CURLMOPT_MAX_HOST_CONNECTIONS, 0 < $maxHostConnections ? $maxHostConnections : \PHP_INT_MAX) ? 0 : $maxHostConnections;
55+
$maxHostConnections = curl_multi_setopt($this->handle, \CURLMOPT_MAX_HOST_CONNECTIONS, 0 < $maxHostConnections ? $maxHostConnections : \PHP_INT_MAX) ? 0 : $maxHostConnections;
5856
}
5957
if (\defined('CURLMOPT_MAXCONNECTS') && 0 < $maxHostConnections) {
60-
curl_multi_setopt($mh, \CURLMOPT_MAXCONNECTS, $maxHostConnections);
58+
curl_multi_setopt($this->handle, \CURLMOPT_MAXCONNECTS, $maxHostConnections);
6159
}
6260

6361
// Skip configuring HTTP/2 push when it's unsupported or buggy, see https://bugs.php.net/77535
@@ -70,40 +68,31 @@ public function __construct(int $maxHostConnections, int $maxPendingPushes)
7068
return;
7169
}
7270

73-
// Clone to prevent a circular reference
74-
$multi = clone $this;
75-
$multi->handles = [$mh];
76-
$multi->pushedResponses = &$this->pushedResponses;
77-
$multi->logger = &$this->logger;
78-
$multi->handlesActivity = &$this->handlesActivity;
79-
$multi->openHandles = &$this->openHandles;
80-
$multi->lastTimeout = &$this->lastTimeout;
81-
82-
curl_multi_setopt($mh, \CURLMOPT_PUSHFUNCTION, static function ($parent, $pushed, array $requestHeaders) use ($multi, $maxPendingPushes) {
83-
return $multi->handlePush($parent, $pushed, $requestHeaders, $maxPendingPushes);
71+
curl_multi_setopt($this->handle, \CURLMOPT_PUSHFUNCTION, function ($parent, $pushed, array $requestHeaders) use ($maxPendingPushes) {
72+
return $this->handlePush($parent, $pushed, $requestHeaders, $maxPendingPushes);
8473
});
8574
}
8675

8776
public function reset()
8877
{
8978
foreach ($this->pushedResponses as $url => $response) {
9079
$this->logger && $this->logger->debug(sprintf('Unused pushed response: "%s"', $url));
91-
92-
foreach ($this->handles as $mh) {
93-
curl_multi_remove_handle($mh, $response->handle);
94-
}
80+
curl_multi_remove_handle($this->handle, $response->handle);
9581
curl_close($response->handle);
9682
}
9783

9884
$this->pushedResponses = [];
9985
$this->dnsCache->evictions = $this->dnsCache->evictions ?: $this->dnsCache->removals;
10086
$this->dnsCache->removals = $this->dnsCache->hostnames = [];
10187

102-
if (\defined('CURLMOPT_PUSHFUNCTION')) {
103-
curl_multi_setopt($this->handles[0], \CURLMOPT_PUSHFUNCTION, null);
104-
}
88+
$this->share = curl_share_init();
89+
90+
curl_share_setopt($this->share, \CURLSHOPT_SHARE, \CURL_LOCK_DATA_DNS);
91+
curl_share_setopt($this->share, \CURLSHOPT_SHARE, \CURL_LOCK_DATA_SSL_SESSION);
10592

106-
$this->__construct($this->maxHostConnections, $this->maxPendingPushes);
93+
if (\defined('CURL_LOCK_DATA_CONNECT')) {
94+
curl_share_setopt($this->share, \CURLSHOPT_SHARE, \CURL_LOCK_DATA_CONNECT);
95+
}
10796
}
10897

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

‎Response/CurlResponse.php

Copy file name to clipboardExpand all lines: Response/CurlResponse.php
+31-43Lines changed: 31 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -106,9 +106,7 @@ public function __construct(CurlClientState $multi, $ch, array $options = null,
106106
if (0 < $duration) {
107107
if ($execCounter === $multi->execCounter) {
108108
$multi->execCounter = !\is_float($execCounter) ? 1 + $execCounter : \PHP_INT_MIN;
109-
foreach ($multi->handles as $mh) {
110-
curl_multi_remove_handle($mh, $ch);
111-
}
109+
curl_multi_remove_handle($multi->handle, $ch);
112110
}
113111

114112
$lastExpiry = end($multi->pauseExpiries);
@@ -120,7 +118,7 @@ public function __construct(CurlClientState $multi, $ch, array $options = null,
120118
} else {
121119
unset($multi->pauseExpiries[(int) $ch]);
122120
curl_pause($ch, \CURLPAUSE_CONT);
123-
curl_multi_add_handle($multi->handles[0], $ch);
121+
curl_multi_add_handle($multi->handle, $ch);
124122
}
125123
};
126124

@@ -174,7 +172,7 @@ public function __construct(CurlClientState $multi, $ch, array $options = null,
174172
// Schedule the request in a non-blocking way
175173
$multi->lastTimeout = null;
176174
$multi->openHandles[$id] = [$ch, $options];
177-
curl_multi_add_handle($multi->handles[0], $ch);
175+
curl_multi_add_handle($multi->handle, $ch);
178176

179177
$this->canary = new Canary(static function () use ($ch, $multi, $id) {
180178
unset($multi->pauseExpiries[$id], $multi->openHandles[$id], $multi->handlesActivity[$id]);
@@ -184,9 +182,7 @@ public function __construct(CurlClientState $multi, $ch, array $options = null,
184182
return;
185183
}
186184

187-
foreach ($multi->handles as $mh) {
188-
curl_multi_remove_handle($mh, $ch);
189-
}
185+
curl_multi_remove_handle($multi->handle, $ch);
190186
curl_setopt_array($ch, [
191187
\CURLOPT_NOPROGRESS => true,
192188
\CURLOPT_PROGRESSFUNCTION => null,
@@ -268,7 +264,7 @@ public function __destruct()
268264
*/
269265
private static function schedule(self $response, array &$runningResponses): void
270266
{
271-
if (isset($runningResponses[$i = (int) $response->multi->handles[0]])) {
267+
if (isset($runningResponses[$i = (int) $response->multi->handle])) {
272268
$runningResponses[$i][1][$response->id] = $response;
273269
} else {
274270
$runningResponses[$i] = [$response->multi, [$response->id => $response]];
@@ -301,47 +297,39 @@ private static function perform(ClientState $multi, array &$responses = null): v
301297
try {
302298
self::$performing = true;
303299
++$multi->execCounter;
300+
$active = 0;
301+
while (\CURLM_CALL_MULTI_PERFORM === ($err = curl_multi_exec($multi->handle, $active))) {
302+
}
304303

305-
foreach ($multi->handles as $i => $mh) {
306-
$active = 0;
307-
while (\CURLM_CALL_MULTI_PERFORM === ($err = curl_multi_exec($mh, $active))) {
308-
}
304+
if (\CURLM_OK !== $err) {
305+
throw new TransportException(curl_multi_strerror($err));
306+
}
309307

310-
if (\CURLM_OK !== $err) {
311-
throw new TransportException(curl_multi_strerror($err));
308+
while ($info = curl_multi_info_read($multi->handle)) {
309+
if (\CURLMSG_DONE !== $info['msg']) {
310+
continue;
312311
}
312+
$result = $info['result'];
313+
$id = (int) $ch = $info['handle'];
314+
$waitFor = @curl_getinfo($ch, \CURLINFO_PRIVATE) ?: '_0';
313315

314-
while ($info = curl_multi_info_read($mh)) {
315-
if (\CURLMSG_DONE !== $info['msg']) {
316-
continue;
317-
}
318-
$result = $info['result'];
319-
$id = (int) $ch = $info['handle'];
320-
$waitFor = @curl_getinfo($ch, \CURLINFO_PRIVATE) ?: '_0';
321-
322-
if (\in_array($result, [\CURLE_SEND_ERROR, \CURLE_RECV_ERROR, /*CURLE_HTTP2*/ 16, /*CURLE_HTTP2_STREAM*/ 92], true) && $waitFor[1] && 'C' !== $waitFor[0]) {
323-
curl_multi_remove_handle($mh, $ch);
324-
$waitFor[1] = (string) ((int) $waitFor[1] - 1); // decrement the retry counter
325-
curl_setopt($ch, \CURLOPT_PRIVATE, $waitFor);
326-
curl_setopt($ch, \CURLOPT_FORBID_REUSE, true);
327-
328-
if (0 === curl_multi_add_handle($mh, $ch)) {
329-
continue;
330-
}
331-
}
316+
if (\in_array($result, [\CURLE_SEND_ERROR, \CURLE_RECV_ERROR, /*CURLE_HTTP2*/ 16, /*CURLE_HTTP2_STREAM*/ 92], true) && $waitFor[1] && 'C' !== $waitFor[0]) {
317+
curl_multi_remove_handle($multi->handle, $ch);
318+
$waitFor[1] = (string) ((int) $waitFor[1] - 1); // decrement the retry counter
319+
curl_setopt($ch, \CURLOPT_PRIVATE, $waitFor);
320+
curl_setopt($ch, \CURLOPT_FORBID_REUSE, true);
332321

333-
if (\CURLE_RECV_ERROR === $result && 'H' === $waitFor[0] && 400 <= ($responses[(int) $ch]->info['http_code'] ?? 0)) {
334-
$multi->handlesActivity[$id][] = new FirstChunk();
322+
if (0 === curl_multi_add_handle($multi->handle, $ch)) {
323+
continue;
335324
}
336-
337-
$multi->handlesActivity[$id][] = null;
338-
$multi->handlesActivity[$id][] = \in_array($result, [\CURLE_OK, \CURLE_TOO_MANY_REDIRECTS], true) || '_0' === $waitFor || curl_getinfo($ch, \CURLINFO_SIZE_DOWNLOAD) === curl_getinfo($ch, \CURLINFO_CONTENT_LENGTH_DOWNLOAD) ? null : new TransportException(sprintf('%s for "%s".', curl_strerror($result), curl_getinfo($ch, \CURLINFO_EFFECTIVE_URL)));
339325
}
340326

341-
if (!$active && 0 < $i) {
342-
curl_multi_close($mh);
343-
unset($multi->handles[$i]);
327+
if (\CURLE_RECV_ERROR === $result && 'H' === $waitFor[0] && 400 <= ($responses[(int) $ch]->info['http_code'] ?? 0)) {
328+
$multi->handlesActivity[$id][] = new FirstChunk();
344329
}
330+
331+
$multi->handlesActivity[$id][] = null;
332+
$multi->handlesActivity[$id][] = \in_array($result, [\CURLE_OK, \CURLE_TOO_MANY_REDIRECTS], true) || '_0' === $waitFor || curl_getinfo($ch, \CURLINFO_SIZE_DOWNLOAD) === curl_getinfo($ch, \CURLINFO_CONTENT_LENGTH_DOWNLOAD) ? null : new TransportException(sprintf('%s for "%s".', curl_strerror($result), curl_getinfo($ch, \CURLINFO_EFFECTIVE_URL)));
345333
}
346334
} finally {
347335
self::$performing = false;
@@ -371,11 +359,11 @@ private static function select(ClientState $multi, float $timeout): int
371359

372360
unset($multi->pauseExpiries[$id]);
373361
curl_pause($multi->openHandles[$id][0], \CURLPAUSE_CONT);
374-
curl_multi_add_handle($multi->handles[0], $multi->openHandles[$id][0]);
362+
curl_multi_add_handle($multi->handle, $multi->openHandles[$id][0]);
375363
}
376364
}
377365

378-
if (0 !== $selected = curl_multi_select($multi->handles[array_key_last($multi->handles)], $timeout)) {
366+
if (0 !== $selected = curl_multi_select($multi->handle, $timeout)) {
379367
return $selected;
380368
}
381369

‎Tests/CurlHttpClientTest.php

Copy file name to clipboardExpand all lines: Tests/CurlHttpClientTest.php
+2-2Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,9 +66,9 @@ public function testHandleIsReinitOnReset()
6666
$r = new \ReflectionProperty($httpClient, 'multi');
6767
$r->setAccessible(true);
6868
$clientState = $r->getValue($httpClient);
69-
$initialHandleId = (int) $clientState->handles[0];
69+
$initialShareId = $clientState->share;
7070
$httpClient->reset();
71-
self::assertNotSame($initialHandleId, (int) $clientState->handles[0]);
71+
self::assertNotSame($initialShareId, $clientState->share);
7272
}
7373

7474
public function testProcessAfterReset()

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.