@@ -108,7 +108,9 @@ public function __construct(CurlClientState $multi, \CurlHandle|string $ch, arra
108
108
if (0 < $ duration ) {
109
109
if ($ execCounter === $ multi ->execCounter ) {
110
110
$ multi ->execCounter = !\is_float ($ execCounter ) ? 1 + $ execCounter : \PHP_INT_MIN ;
111
- curl_multi_remove_handle ($ multi ->handle , $ ch );
111
+ foreach ($ multi ->handles as $ mh ) {
112
+ curl_multi_remove_handle ($ mh , $ ch );
113
+ }
112
114
}
113
115
114
116
$ lastExpiry = end ($ multi ->pauseExpiries );
@@ -120,7 +122,7 @@ public function __construct(CurlClientState $multi, \CurlHandle|string $ch, arra
120
122
} else {
121
123
unset($ multi ->pauseExpiries [(int ) $ ch ]);
122
124
curl_pause ($ ch , \CURLPAUSE_CONT );
123
- curl_multi_add_handle ($ multi ->handle , $ ch );
125
+ curl_multi_add_handle ($ multi ->handles [ 0 ] , $ ch );
124
126
}
125
127
};
126
128
@@ -174,7 +176,7 @@ public function __construct(CurlClientState $multi, \CurlHandle|string $ch, arra
174
176
// Schedule the request in a non-blocking way
175
177
$ multi ->lastTimeout = null ;
176
178
$ multi ->openHandles [$ id ] = [$ ch , $ options ];
177
- curl_multi_add_handle ($ multi ->handle , $ ch );
179
+ curl_multi_add_handle ($ multi ->handles [ 0 ] , $ ch );
178
180
179
181
$ this ->canary = new Canary (static function () use ($ ch , $ multi , $ id ) {
180
182
unset($ multi ->pauseExpiries [$ id ], $ multi ->openHandles [$ id ], $ multi ->handlesActivity [$ id ]);
@@ -184,7 +186,9 @@ public function __construct(CurlClientState $multi, \CurlHandle|string $ch, arra
184
186
return ;
185
187
}
186
188
187
- curl_multi_remove_handle ($ multi ->handle , $ ch );
189
+ foreach ($ multi ->handles as $ mh ) {
190
+ curl_multi_remove_handle ($ mh , $ ch );
191
+ }
188
192
curl_setopt_array ($ ch , [
189
193
\CURLOPT_NOPROGRESS => true ,
190
194
\CURLOPT_PROGRESSFUNCTION => null ,
@@ -266,7 +270,7 @@ public function __destruct()
266
270
*/
267
271
private static function schedule (self $ response , array &$ runningResponses ): void
268
272
{
269
- if (isset ($ runningResponses [$ i = (int ) $ response ->multi ->handle ])) {
273
+ if (isset ($ runningResponses [$ i = (int ) $ response ->multi ->handles [ 0 ] ])) {
270
274
$ runningResponses [$ i ][1 ][$ response ->id ] = $ response ;
271
275
} else {
272
276
$ runningResponses [$ i ] = [$ response ->multi , [$ response ->id => $ response ]];
@@ -299,38 +303,47 @@ private static function perform(ClientState $multi, array &$responses = null): v
299
303
try {
300
304
self ::$ performing = true ;
301
305
++$ multi ->execCounter ;
302
- $ active = 0 ;
303
- while (\CURLM_CALL_MULTI_PERFORM === ($ err = curl_multi_exec ($ multi ->handle , $ active )));
304
-
305
- if (\CURLM_OK !== $ err ) {
306
- throw new TransportException (curl_multi_strerror ($ err ));
307
- }
308
306
309
- while ($ info = curl_multi_info_read ( $ multi -> handle ) ) {
310
- if (\ CURLMSG_DONE !== $ info [ ' msg ' ]) {
311
- continue ;
307
+ foreach ($ multi -> handles as $ i => $ mh ) {
308
+ $ active = 0 ;
309
+ while (\ CURLM_CALL_MULTI_PERFORM === ( $ err = curl_multi_exec ( $ mh , $ active ))) {
312
310
}
313
- $ result = $ info ['result ' ];
314
- $ id = (int ) $ ch = $ info ['handle ' ];
315
- $ waitFor = @curl_getinfo ($ ch , \CURLINFO_PRIVATE ) ?: '_0 ' ;
316
311
317
- if (\in_array ($ result , [\CURLE_SEND_ERROR , \CURLE_RECV_ERROR , /*CURLE_HTTP2*/ 16 , /*CURLE_HTTP2_STREAM*/ 92 ], true ) && $ waitFor [1 ] && 'C ' !== $ waitFor [0 ]) {
318
- curl_multi_remove_handle ($ multi ->handle , $ ch );
319
- $ waitFor [1 ] = (string ) ((int ) $ waitFor [1 ] - 1 ); // decrement the retry counter
320
- curl_setopt ($ ch , \CURLOPT_PRIVATE , $ waitFor );
321
- curl_setopt ($ ch , \CURLOPT_FORBID_REUSE , true );
312
+ if (\CURLM_OK !== $ err ) {
313
+ throw new TransportException (curl_multi_strerror ($ err ));
314
+ }
322
315
323
- if (0 === curl_multi_add_handle ($ multi ->handle , $ ch )) {
316
+ while ($ info = curl_multi_info_read ($ mh )) {
317
+ if (\CURLMSG_DONE !== $ info ['msg ' ]) {
324
318
continue ;
325
319
}
326
- }
320
+ $ result = $ info ['result ' ];
321
+ $ id = (int ) $ ch = $ info ['handle ' ];
322
+ $ waitFor = @curl_getinfo ($ ch , \CURLINFO_PRIVATE ) ?: '_0 ' ;
323
+
324
+ if (\in_array ($ result , [\CURLE_SEND_ERROR , \CURLE_RECV_ERROR , /*CURLE_HTTP2*/ 16 , /*CURLE_HTTP2_STREAM*/ 92 ], true ) && $ waitFor [1 ] && 'C ' !== $ waitFor [0 ]) {
325
+ curl_multi_remove_handle ($ mh , $ ch );
326
+ $ waitFor [1 ] = (string ) ((int ) $ waitFor [1 ] - 1 ); // decrement the retry counter
327
+ curl_setopt ($ ch , \CURLOPT_PRIVATE , $ waitFor );
328
+ curl_setopt ($ ch , \CURLOPT_FORBID_REUSE , true );
329
+
330
+ if (0 === curl_multi_add_handle ($ mh , $ ch )) {
331
+ continue ;
332
+ }
333
+ }
327
334
328
- if (\CURLE_RECV_ERROR === $ result && 'H ' === $ waitFor [0 ] && 400 <= ($ responses [(int ) $ ch ]->info ['http_code ' ] ?? 0 )) {
329
- $ multi ->handlesActivity [$ id ][] = new FirstChunk ();
335
+ if (\CURLE_RECV_ERROR === $ result && 'H ' === $ waitFor [0 ] && 400 <= ($ responses [(int ) $ ch ]->info ['http_code ' ] ?? 0 )) {
336
+ $ multi ->handlesActivity [$ id ][] = new FirstChunk ();
337
+ }
338
+
339
+ $ multi ->handlesActivity [$ id ][] = null ;
340
+ $ 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 (ucfirst (curl_error ($ ch ) ?: curl_strerror ($ result )).sprintf (' for "%s". ' , curl_getinfo ($ ch , \CURLINFO_EFFECTIVE_URL )));
330
341
}
331
342
332
- $ multi ->handlesActivity [$ id ][] = null ;
333
- $ 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 (ucfirst (curl_error ($ ch ) ?: curl_strerror ($ result )).sprintf (' for "%s". ' , curl_getinfo ($ ch , \CURLINFO_EFFECTIVE_URL )));
343
+ if (!$ active && 0 < $ i ) {
344
+ curl_multi_close ($ mh );
345
+ unset($ multi ->handles [$ i ]);
346
+ }
334
347
}
335
348
} finally {
336
349
self ::$ performing = false ;
@@ -355,11 +368,11 @@ private static function select(ClientState $multi, float $timeout): int
355
368
356
369
unset($ multi ->pauseExpiries [$ id ]);
357
370
curl_pause ($ multi ->openHandles [$ id ][0 ], \CURLPAUSE_CONT );
358
- curl_multi_add_handle ($ multi ->handle , $ multi ->openHandles [$ id ][0 ]);
371
+ curl_multi_add_handle ($ multi ->handles [ 0 ] , $ multi ->openHandles [$ id ][0 ]);
359
372
}
360
373
}
361
374
362
- if (0 !== $ selected = curl_multi_select ($ multi ->handle , $ timeout )) {
375
+ if (0 !== $ selected = curl_multi_select ($ multi ->handles [ array_key_last ( $ multi -> handles )] , $ timeout )) {
363
376
return $ selected ;
364
377
}
365
378
@@ -382,15 +395,8 @@ private static function parseHeaderLine($ch, string $data, array &$info, array &
382
395
}
383
396
384
397
if ('' !== $ data ) {
385
- try {
386
- // Regular header line: add it to the list
387
- self ::addResponseHeaders ([$ data ], $ info , $ headers );
388
- } catch (TransportException $ e ) {
389
- $ multi ->handlesActivity [$ id ][] = null ;
390
- $ multi ->handlesActivity [$ id ][] = $ e ;
391
-
392
- return \strlen ($ data );
393
- }
398
+ // Regular header line: add it to the list
399
+ self ::addResponseHeaders ([$ data ], $ info , $ headers );
394
400
395
401
if (!str_starts_with ($ data , 'HTTP/ ' )) {
396
402
if (0 === stripos ($ data , 'Location: ' )) {
0 commit comments