@@ -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 ' ],
@@ -222,7 +221,11 @@ public function request(string $method, string $url, array $options = []): Respo
222221 $ proxy = self ::getProxy ($ options ['proxy ' ], $ url , $ options ['no_proxy ' ]);
223222 $ resolveRedirect = self ::createRedirectResolver ($ options , $ host , $ proxy , $ info , $ onProgress );
224223 $ context = stream_context_create ($ context , ['notification ' => $ notification ]);
225- self ::configureHeadersAndProxy ($ context , $ host , $ options ['headers ' ], $ proxy );
224+
225+ if (!self ::configureHeadersAndProxy ($ context , $ host , $ options ['headers ' ], $ proxy , 'https: ' === $ url ['scheme ' ])) {
226+ $ ip = self ::dnsResolve ($ host , $ this ->multi , $ info , $ onProgress );
227+ $ url ['authority ' ] = substr_replace ($ url ['authority ' ], $ ip , -\strlen ($ host ) - \strlen ($ port ), \strlen ($ host ));
228+ }
226229
227230 return new NativeResponse ($ this ->multi , $ context , implode ('' , $ url ), $ options , $ info , $ resolveRedirect , $ onProgress , $ this ->logger );
228231 }
@@ -265,9 +268,9 @@ private static function getBodyAsString($body): string
265268 }
266269
267270 /**
268- * Resolves the IP of the host using the local DNS cache if possible .
271+ * Extracts the host and the port from the URL .
269272 */
270- private static function dnsResolve (array $ url , NativeClientState $ multi , array &$ info, ? \ Closure $ onProgress ): array
273+ private static function parseHostPort (array $ url , array &$ info ): array
271274 {
272275 if ($ port = parse_url ($ url ['authority ' ], \PHP_URL_PORT ) ?: '' ) {
273276 $ info ['primary_port ' ] = $ port ;
@@ -276,8 +279,14 @@ private static function dnsResolve(array $url, NativeClientState $multi, array &
276279 $ info ['primary_port ' ] = 'http: ' === $ url ['scheme ' ] ? 80 : 443 ;
277280 }
278281
279- $ host = parse_url ($ url ['authority ' ], \PHP_URL_HOST );
282+ return [parse_url ($ url ['authority ' ], \PHP_URL_HOST ), $ port ];
283+ }
280284
285+ /**
286+ * Resolves the IP of the host using the local DNS cache if possible.
287+ */
288+ private static function dnsResolve ($ host , NativeClientState $ multi , array &$ info , ?\Closure $ onProgress ): string
289+ {
281290 if (null === $ ip = $ multi ->dnsCache [$ host ] ?? null ) {
282291 $ info ['debug ' ] .= "* Hostname was NOT found in DNS cache \n" ;
283292 $ now = microtime (true );
@@ -300,7 +309,7 @@ private static function dnsResolve(array $url, NativeClientState $multi, array &
300309 $ onProgress ();
301310 }
302311
303- return [ $ host , $ port , substr_replace ( $ url [ ' authority ' ], $ ip , - \strlen ( $ host ) - \strlen ( $ port ), \strlen ( $ host ))] ;
312+ return $ ip ;
304313 }
305314
306315 /**
@@ -363,24 +372,33 @@ private static function createRedirectResolver(array $options, string $host, ?ar
363372 }
364373 }
365374
366- [$ host , $ port , $ url ['authority ' ]] = self ::dnsResolve ($ url , $ multi , $ info , $ onProgress );
367- stream_context_set_option ($ context , 'ssl ' , 'peer_name ' , $ host );
375+ [$ host , $ port ] = self ::parseHostPort ($ url , $ info );
368376
369377 if (false !== (parse_url ($ location , \PHP_URL_HOST ) ?? false )) {
370378 // Authorization and Cookie headers MUST NOT follow except for the initial host name
371379 $ requestHeaders = $ redirectHeaders ['host ' ] === $ host ? $ redirectHeaders ['with_auth ' ] : $ redirectHeaders ['no_auth ' ];
372380 $ requestHeaders [] = 'Host: ' .$ host .$ port ;
373- self ::configureHeadersAndProxy ($ context , $ host , $ requestHeaders , $ proxy );
381+ $ dnsResolve = !self ::configureHeadersAndProxy ($ context , $ host , $ requestHeaders , $ proxy , 'https: ' === $ url ['scheme ' ]);
382+ } else {
383+ $ dnsResolve = isset (stream_context_get_options ($ context )['ssl ' ]['peer_name ' ]);
384+ }
385+
386+ if ($ dnsResolve ) {
387+ $ ip = self ::dnsResolve ($ host , $ multi , $ info , $ onProgress );
388+ $ url ['authority ' ] = substr_replace ($ url ['authority ' ], $ ip , -\strlen ($ host ) - \strlen ($ port ), \strlen ($ host ));
374389 }
375390
376391 return implode ('' , $ url );
377392 };
378393 }
379394
380- private static function configureHeadersAndProxy ($ context , string $ host , array $ requestHeaders , ?array $ proxy ): bool
395+ private static function configureHeadersAndProxy ($ context , string $ host , array $ requestHeaders , ?array $ proxy, bool $ isSsl ): bool
381396 {
382397 if (null === $ proxy ) {
383- return stream_context_set_option ($ context , 'http ' , 'header ' , $ requestHeaders );
398+ stream_context_set_option ($ context , 'http ' , 'header ' , $ requestHeaders );
399+ stream_context_set_option ($ context , 'ssl ' , 'peer_name ' , $ host );
400+
401+ return false ;
384402 }
385403
386404 // Matching "no_proxy" should follow the behavior of curl
@@ -389,17 +407,24 @@ private static function configureHeadersAndProxy($context, string $host, array $
389407 $ dotRule = '. ' .ltrim ($ rule , '. ' );
390408
391409 if ('* ' === $ rule || $ host === $ rule || substr ($ host , -\strlen ($ dotRule )) === $ dotRule ) {
392- return stream_context_set_option ($ context , 'http ' , 'header ' , $ requestHeaders );
410+ stream_context_set_option ($ context , 'http ' , 'proxy ' , null );
411+ stream_context_set_option ($ context , 'http ' , 'request_fulluri ' , false );
412+ stream_context_set_option ($ context , 'http ' , 'header ' , $ requestHeaders );
413+ stream_context_set_option ($ context , 'ssl ' , 'peer_name ' , $ host );
414+
415+ return false ;
393416 }
394417 }
395418
396- stream_context_set_option ($ context , 'http ' , 'proxy ' , $ proxy ['url ' ]);
397- stream_context_set_option ($ context , 'http ' , 'request_fulluri ' , true );
398-
399419 if (null !== $ proxy ['auth ' ]) {
400420 $ requestHeaders [] = 'Proxy-Authorization: ' .$ proxy ['auth ' ];
401421 }
402422
403- return stream_context_set_option ($ context , 'http ' , 'header ' , $ requestHeaders );
423+ stream_context_set_option ($ context , 'http ' , 'proxy ' , $ proxy ['url ' ]);
424+ stream_context_set_option ($ context , 'http ' , 'request_fulluri ' , !$ isSsl );
425+ stream_context_set_option ($ context , 'http ' , 'header ' , $ requestHeaders );
426+ stream_context_set_option ($ context , 'ssl ' , 'peer_name ' , null );
427+
428+ return true ;
404429 }
405430}
0 commit comments