@@ -171,7 +171,7 @@ public function request(string $method, string $url, array $options = []): Respo
171
171
172
172
$ this ->logger && $ this ->logger ->info (sprintf ('Request: "%s %s" ' , $ method , implode ('' , $ url )));
173
173
174
- [$ host , $ port, $ url [ ' authority ' ]] = self ::dnsResolve ($ url , $ this -> multi , $ info, $ onProgress );
174
+ [$ host , $ port] = self ::parseHostPort ($ url , $ info );
175
175
176
176
if (!isset ($ options ['normalized_headers ' ]['host ' ])) {
177
177
$ options ['headers ' ][] = 'Host: ' .$ host .$ port ;
@@ -198,7 +198,6 @@ public function request(string $method, string $url, array $options = []): Respo
198
198
'follow_location ' => false , // We follow redirects ourselves - the native logic is too limited
199
199
],
200
200
'ssl ' => array_filter ([
201
- 'peer_name ' => $ host ,
202
201
'verify_peer ' => $ options ['verify_peer ' ],
203
202
'verify_peer_name ' => $ options ['verify_host ' ],
204
203
'cafile ' => $ options ['cafile ' ],
@@ -225,7 +224,11 @@ public function request(string $method, string $url, array $options = []): Respo
225
224
226
225
$ resolveRedirect = self ::createRedirectResolver ($ options , $ host , $ proxy , $ noProxy , $ info , $ onProgress );
227
226
$ context = stream_context_create ($ context , ['notification ' => $ notification ]);
228
- self ::configureHeadersAndProxy ($ context , $ host , $ options ['headers ' ], $ proxy , $ noProxy , 'https: ' === $ url ['scheme ' ]);
227
+
228
+ if (!self ::configureHeadersAndProxy ($ context , $ host , $ options ['headers ' ], $ proxy , $ noProxy , 'https: ' === $ url ['scheme ' ])) {
229
+ $ ip = self ::dnsResolve ($ host , $ this ->multi , $ info , $ onProgress );
230
+ $ url ['authority ' ] = substr_replace ($ url ['authority ' ], $ ip , -\strlen ($ host ) - \strlen ($ port ), \strlen ($ host ));
231
+ }
229
232
230
233
return new NativeResponse ($ this ->multi , $ context , implode ('' , $ url ), $ options , $ info , $ resolveRedirect , $ onProgress , $ this ->logger );
231
234
}
@@ -306,9 +309,9 @@ private static function getProxy(?string $proxy, array $url): ?array
306
309
}
307
310
308
311
/**
309
- * Resolves the IP of the host using the local DNS cache if possible .
312
+ * Extracts the host and the port from the URL .
310
313
*/
311
- private static function dnsResolve (array $ url , NativeClientState $ multi , array &$ info, ? \ Closure $ onProgress ): array
314
+ private static function parseHostPort (array $ url , array &$ info ): array
312
315
{
313
316
if ($ port = parse_url ($ url ['authority ' ], \PHP_URL_PORT ) ?: '' ) {
314
317
$ info ['primary_port ' ] = $ port ;
@@ -317,8 +320,14 @@ private static function dnsResolve(array $url, NativeClientState $multi, array &
317
320
$ info ['primary_port ' ] = 'http: ' === $ url ['scheme ' ] ? 80 : 443 ;
318
321
}
319
322
320
- $ host = parse_url ($ url ['authority ' ], \PHP_URL_HOST );
323
+ return [parse_url ($ url ['authority ' ], \PHP_URL_HOST ), $ port ];
324
+ }
321
325
326
+ /**
327
+ * Resolves the IP of the host using the local DNS cache if possible.
328
+ */
329
+ private static function dnsResolve ($ host , NativeClientState $ multi , array &$ info , ?\Closure $ onProgress ): string
330
+ {
322
331
if (null === $ ip = $ multi ->dnsCache [$ host ] ?? null ) {
323
332
$ info ['debug ' ] .= "* Hostname was NOT found in DNS cache \n" ;
324
333
$ now = microtime (true );
@@ -341,7 +350,7 @@ private static function dnsResolve(array $url, NativeClientState $multi, array &
341
350
$ onProgress ();
342
351
}
343
352
344
- return [ $ host , $ port , substr_replace ( $ url [ ' authority ' ], $ ip , - \strlen ( $ host ) - \strlen ( $ port ), \strlen ( $ host ))] ;
353
+ return $ ip ;
345
354
}
346
355
347
356
/**
@@ -404,24 +413,33 @@ private static function createRedirectResolver(array $options, string $host, ?ar
404
413
}
405
414
}
406
415
407
- [$ host , $ port , $ url ['authority ' ]] = self ::dnsResolve ($ url , $ multi , $ info , $ onProgress );
408
- stream_context_set_option ($ context , 'ssl ' , 'peer_name ' , $ host );
416
+ [$ host , $ port ] = self ::parseHostPort ($ url , $ info );
409
417
410
418
if (false !== (parse_url ($ location , \PHP_URL_HOST ) ?? false )) {
411
419
// Authorization and Cookie headers MUST NOT follow except for the initial host name
412
420
$ requestHeaders = $ redirectHeaders ['host ' ] === $ host ? $ redirectHeaders ['with_auth ' ] : $ redirectHeaders ['no_auth ' ];
413
421
$ requestHeaders [] = 'Host: ' .$ host .$ port ;
414
- self ::configureHeadersAndProxy ($ context , $ host , $ requestHeaders , $ proxy , $ noProxy , 'https: ' === $ url ['scheme ' ]);
422
+ $ dnsResolve = !self ::configureHeadersAndProxy ($ context , $ host , $ requestHeaders , $ proxy , $ noProxy , 'https: ' === $ url ['scheme ' ]);
423
+ } else {
424
+ $ dnsResolve = isset (stream_context_get_options ($ context )['ssl ' ]['peer_name ' ]);
425
+ }
426
+
427
+ if ($ dnsResolve ) {
428
+ $ ip = self ::dnsResolve ($ host , $ multi , $ info , $ onProgress );
429
+ $ url ['authority ' ] = substr_replace ($ url ['authority ' ], $ ip , -\strlen ($ host ) - \strlen ($ port ), \strlen ($ host ));
415
430
}
416
431
417
432
return implode ('' , $ url );
418
433
};
419
434
}
420
435
421
- private static function configureHeadersAndProxy ($ context , string $ host , array $ requestHeaders , ?array $ proxy , array $ noProxy , bool $ isSsl )
436
+ private static function configureHeadersAndProxy ($ context , string $ host , array $ requestHeaders , ?array $ proxy , array $ noProxy , bool $ isSsl ): bool
422
437
{
423
438
if (null === $ proxy ) {
424
- return stream_context_set_option ($ context , 'http ' , 'header ' , $ requestHeaders );
439
+ stream_context_set_option ($ context , 'http ' , 'header ' , $ requestHeaders );
440
+ stream_context_set_option ($ context , 'ssl ' , 'peer_name ' , $ host );
441
+
442
+ return false ;
425
443
}
426
444
427
445
// Matching "no_proxy" should follow the behavior of curl
@@ -430,17 +448,24 @@ private static function configureHeadersAndProxy($context, string $host, array $
430
448
$ dotRule = '. ' .ltrim ($ rule , '. ' );
431
449
432
450
if ('* ' === $ rule || $ host === $ rule || substr ($ host , -\strlen ($ dotRule )) === $ dotRule ) {
433
- return stream_context_set_option ($ context , 'http ' , 'header ' , $ requestHeaders );
451
+ stream_context_set_option ($ context , 'http ' , 'proxy ' , null );
452
+ stream_context_set_option ($ context , 'http ' , 'request_fulluri ' , false );
453
+ stream_context_set_option ($ context , 'http ' , 'header ' , $ requestHeaders );
454
+ stream_context_set_option ($ context , 'ssl ' , 'peer_name ' , $ host );
455
+
456
+ return false ;
434
457
}
435
458
}
436
459
437
- stream_context_set_option ($ context , 'http ' , 'proxy ' , $ proxy ['url ' ]);
438
- stream_context_set_option ($ context , 'http ' , 'request_fulluri ' , !$ isSsl );
439
-
440
460
if (null !== $ proxy ['auth ' ]) {
441
461
$ requestHeaders [] = 'Proxy-Authorization: ' .$ proxy ['auth ' ];
442
462
}
443
463
444
- return stream_context_set_option ($ context , 'http ' , 'header ' , $ requestHeaders );
464
+ stream_context_set_option ($ context , 'http ' , 'proxy ' , $ proxy ['url ' ]);
465
+ stream_context_set_option ($ context , 'http ' , 'request_fulluri ' , !$ isSsl );
466
+ stream_context_set_option ($ context , 'http ' , 'header ' , $ requestHeaders );
467
+ stream_context_set_option ($ context , 'ssl ' , 'peer_name ' , null );
468
+
469
+ return true ;
445
470
}
446
471
}
0 commit comments