@@ -171,7 +171,7 @@ public function request(string $method, string $url, array $options = []): Respo
171171
172172 $ this ->logger && $ this ->logger ->info (sprintf ('Request: "%s %s" ' , $ method , implode ('' , $ url )));
173173
174- [$ host , $ port, $ url [ ' authority ' ]] = self ::dnsResolve ($ url , $ this -> multi , $ info, $ onProgress );
174+ [$ host , $ port] = self ::parseHostPort ($ url , $ info );
175175
176176 if (!isset ($ options ['normalized_headers ' ]['host ' ])) {
177177 $ options ['headers ' ][] = 'Host: ' .$ host .$ port ;
@@ -198,7 +198,6 @@ public function request(string $method, string $url, array $options = []): Respo
198198 'follow_location ' => false , // We follow redirects ourselves - the native logic is too limited
199199 ],
200200 'ssl ' => array_filter ([
201- 'peer_name ' => $ host ,
202201 'verify_peer ' => $ options ['verify_peer ' ],
203202 'verify_peer_name ' => $ options ['verify_host ' ],
204203 'cafile ' => $ options ['cafile ' ],
@@ -225,7 +224,11 @@ public function request(string $method, string $url, array $options = []): Respo
225224
226225 $ resolveRedirect = self ::createRedirectResolver ($ options , $ host , $ proxy , $ noProxy , $ info , $ onProgress );
227226 $ 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+ }
229232
230233 return new NativeResponse ($ this ->multi , $ context , implode ('' , $ url ), $ options , $ info , $ resolveRedirect , $ onProgress , $ this ->logger );
231234 }
@@ -306,9 +309,9 @@ private static function getProxy(?string $proxy, array $url): ?array
306309 }
307310
308311 /**
309- * Resolves the IP of the host using the local DNS cache if possible .
312+ * Extracts the host and the port from the URL .
310313 */
311- private static function dnsResolve (array $ url , NativeClientState $ multi , array &$ info, ? \ Closure $ onProgress ): array
314+ private static function parseHostPort (array $ url , array &$ info ): array
312315 {
313316 if ($ port = parse_url ($ url ['authority ' ], \PHP_URL_PORT ) ?: '' ) {
314317 $ info ['primary_port ' ] = $ port ;
@@ -317,8 +320,14 @@ private static function dnsResolve(array $url, NativeClientState $multi, array &
317320 $ info ['primary_port ' ] = 'http: ' === $ url ['scheme ' ] ? 80 : 443 ;
318321 }
319322
320- $ host = parse_url ($ url ['authority ' ], \PHP_URL_HOST );
323+ return [parse_url ($ url ['authority ' ], \PHP_URL_HOST ), $ port ];
324+ }
321325
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+ {
322331 if (null === $ ip = $ multi ->dnsCache [$ host ] ?? null ) {
323332 $ info ['debug ' ] .= "* Hostname was NOT found in DNS cache \n" ;
324333 $ now = microtime (true );
@@ -341,7 +350,7 @@ private static function dnsResolve(array $url, NativeClientState $multi, array &
341350 $ onProgress ();
342351 }
343352
344- return [ $ host , $ port , substr_replace ( $ url [ ' authority ' ], $ ip , - \strlen ( $ host ) - \strlen ( $ port ), \strlen ( $ host ))] ;
353+ return $ ip ;
345354 }
346355
347356 /**
@@ -404,24 +413,33 @@ private static function createRedirectResolver(array $options, string $host, ?ar
404413 }
405414 }
406415
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 );
409417
410418 if (false !== (parse_url ($ location , \PHP_URL_HOST ) ?? false )) {
411419 // Authorization and Cookie headers MUST NOT follow except for the initial host name
412420 $ requestHeaders = $ redirectHeaders ['host ' ] === $ host ? $ redirectHeaders ['with_auth ' ] : $ redirectHeaders ['no_auth ' ];
413421 $ 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 ));
415430 }
416431
417432 return implode ('' , $ url );
418433 };
419434 }
420435
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
422437 {
423438 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 ;
425443 }
426444
427445 // Matching "no_proxy" should follow the behavior of curl
@@ -430,17 +448,24 @@ private static function configureHeadersAndProxy($context, string $host, array $
430448 $ dotRule = '. ' .ltrim ($ rule , '. ' );
431449
432450 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 ;
434457 }
435458 }
436459
437- stream_context_set_option ($ context , 'http ' , 'proxy ' , $ proxy ['url ' ]);
438- stream_context_set_option ($ context , 'http ' , 'request_fulluri ' , !$ isSsl );
439-
440460 if (null !== $ proxy ['auth ' ]) {
441461 $ requestHeaders [] = 'Proxy-Authorization: ' .$ proxy ['auth ' ];
442462 }
443463
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 ;
445470 }
446471}
0 commit comments