1
0
mirror of https://github.com/guzzle/guzzle.git synced 2025-01-29 11:17:44 +01:00

Merge pull request #2483 from gmponos/merge650-to-master

Merge 6.5 to master
This commit is contained in:
Mponos George 2019-12-21 17:00:23 +02:00 committed by GitHub
commit b8310d23c8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 108 additions and 32 deletions

View File

@ -1,5 +1,10 @@
# Change Log
## 6.5.1 - 2019-12-21
* Better defaults for PHP installations with old ICU lib [#2454](https://github.com/guzzle/guzzle/pull/2454)
* IDN support for redirects [#2424](https://github.com/guzzle/guzzle/pull/2424)
## 6.5.0 - 2019-12-07
* Improvement: Added support for reset internal queue in MockHandler. [#2143](https://github.com/guzzle/guzzle/pull/2143)

View File

@ -561,7 +561,7 @@ idn_conversion
:Types:
- bool
- int
:Default: ``true`` if ``intl`` extension is available, ``false`` otherwise
:Default: ``true`` if ``intl`` extension is available (and ICU library is 4.6+ for PHP 7.2+), ``false`` otherwise
:Constant: ``GuzzleHttp\RequestOptions::IDN_CONVERSION``
.. code-block:: php

View File

@ -222,36 +222,9 @@ class Client implements ClientInterface, \Psr\Http\Client\ClientInterface
$uri = Psr7\UriResolver::resolve(Psr7\uri_for($config['base_uri']), $uri);
}
if ($uri->getHost() && isset($config['idn_conversion']) && ($config['idn_conversion'] !== false)) {
if (isset($config['idn_conversion']) && ($config['idn_conversion'] !== false)) {
$idnOptions = ($config['idn_conversion'] === true) ? IDNA_DEFAULT : $config['idn_conversion'];
$asciiHost = \idn_to_ascii($uri->getHost(), $idnOptions, INTL_IDNA_VARIANT_UTS46, $info);
if ($asciiHost === false) {
$errorBitSet = isset($info['errors']) ? $info['errors'] : 0;
$errorConstants = \array_filter(\array_keys(\get_defined_constants()), function ($name) {
return \substr($name, 0, 11) === 'IDNA_ERROR_';
});
$errors = [];
foreach ($errorConstants as $errorConstant) {
if ($errorBitSet & \constant($errorConstant)) {
$errors[] = $errorConstant;
}
}
$errorMessage = 'IDN conversion failed';
if ($errors) {
$errorMessage .= ' (errors: ' . \implode(', ', $errors) . ')';
}
throw new InvalidArgumentException($errorMessage);
} else {
if ($uri->getHost() !== $asciiHost) {
// Replace URI only if the ASCII version is different
$uri = $uri->withHost($asciiHost);
}
}
$uri = _idn_uri_convert($uri, $idnOptions);
}
return $uri->getScheme() === '' && $uri->getHost() !== '' ? $uri->withScheme('http') : $uri;
@ -271,7 +244,9 @@ class Client implements ClientInterface, \Psr\Http\Client\ClientInterface
];
// idn_to_ascii() is a part of ext-intl and might be not available
$defaults['idn_conversion'] = \function_exists('idn_to_ascii');
// Old ICU versions don't have this constant, so we are basically stuck (see https://github.com/guzzle/guzzle/pull/2424
// and https://github.com/guzzle/guzzle/issues/2448 for details)
$defaults['idn_conversion'] = \function_exists('idn_to_ascii') && defined('INTL_IDNA_VARIANT_UTS46');
// Use the standard Linux HTTP_PROXY and HTTPS_PROXY if set.

View File

@ -168,7 +168,13 @@ class RedirectMiddleware
$modify['body'] = '';
}
$modify['uri'] = $this->redirectUri($request, $response, $protocols);
$uri = $this->redirectUri($request, $response, $protocols);
if (isset($options['idn_conversion']) && ($options['idn_conversion'] !== false)) {
$idnOptions = ($options['idn_conversion'] === true) ? IDNA_DEFAULT : $options['idn_conversion'];
$uri = _idn_uri_convert($uri, $idnOptions);
}
$modify['uri'] = $uri;
Psr7\rewind_body($request);
// Add the Referer header if it is told to do so and only

View File

@ -1,10 +1,12 @@
<?php
namespace GuzzleHttp;
use GuzzleHttp\Exception\InvalidArgumentException;
use GuzzleHttp\Handler\CurlHandler;
use GuzzleHttp\Handler\CurlMultiHandler;
use GuzzleHttp\Handler\Proxy;
use GuzzleHttp\Handler\StreamHandler;
use Psr\Http\Message\UriInterface;
/**
* Debug function used to describe the provided value type and class.
@ -312,3 +314,46 @@ function _current_time()
{
return \function_exists('hrtime') ? \hrtime(true) / 1e9 : \microtime(true);
}
/**
* @param int $options
*
* @return UriInterface
*
* @internal
*/
function _idn_uri_convert(UriInterface $uri, $options = 0)
{
if ($uri->getHost()) {
$idnaVariant = defined('INTL_IDNA_VARIANT_UTS46') ? INTL_IDNA_VARIANT_UTS46 : 0;
$asciiHost = idn_to_ascii($uri->getHost(), $options, $idnaVariant, $info);
if ($asciiHost === false) {
$errorBitSet = isset($info['errors']) ? $info['errors'] : 0;
$errorConstants = array_filter(array_keys(get_defined_constants()), function ($name) {
return substr($name, 0, 11) === 'IDNA_ERROR_';
});
$errors = [];
foreach ($errorConstants as $errorConstant) {
if ($errorBitSet & constant($errorConstant)) {
$errors[] = $errorConstant;
}
}
$errorMessage = 'IDN conversion failed';
if ($errors) {
$errorMessage .= ' (errors: ' . implode(', ', $errors) . ')';
}
throw new InvalidArgumentException($errorMessage);
} else {
if ($uri->getHost() !== $asciiHost) {
// Replace URI only if the ASCII version is different
$uri = $uri->withHost($asciiHost);
}
}
}
return $uri;
}

View File

@ -5,11 +5,13 @@ use GuzzleHttp\Client;
use GuzzleHttp\Cookie\CookieJar;
use GuzzleHttp\Handler\MockHandler;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Middleware;
use GuzzleHttp\Promise\PromiseInterface;
use GuzzleHttp\Psr7;
use GuzzleHttp\Psr7\Request;
use GuzzleHttp\Psr7\Response;
use GuzzleHttp\Psr7\Uri;
use GuzzleHttp\RequestOptions;
use PHPUnit\Framework\TestCase;
use Psr\Http\Message\ResponseInterface;
@ -764,4 +766,36 @@ class ClientTest extends TestCase
self::assertSame('http://xn--d1acpjx3f.xn--p1ai/baz', (string) $mock->getLastRequest()->getUri());
self::assertSame('xn--d1acpjx3f.xn--p1ai', (string) $mock->getLastRequest()->getHeaderLine('Host'));
}
public function testIdnWithRedirect()
{
if (!extension_loaded('intl')) {
self::markTestSkipped('intl PHP extension is not loaded');
}
$mockHandler = new MockHandler([
new Response(302, ['Location' => 'http://www.tést.com/whatever']),
new Response()
]);
$handler = HandlerStack::create($mockHandler);
$requests = [];
$handler->push(Middleware::history($requests));
$client = new Client(['handler' => $handler]);
$client->request('GET', 'https://яндекс.рф/images', [
RequestOptions::ALLOW_REDIRECTS => [
'referer' => true,
'track_redirects' => true
],
'idn_conversion' => true
]);
$request = $mockHandler->getLastRequest();
self::assertSame('http://www.xn--tst-bma.com/whatever', (string) $request->getUri());
self::assertSame('www.xn--tst-bma.com', (string) $request->getHeaderLine('Host'));
$request = $requests[0]['request'];
self::assertSame('https://xn--d1acpjx3f.xn--p1ai/images', (string) $request->getUri());
self::assertSame('xn--d1acpjx3f.xn--p1ai', (string) $request->getHeaderLine('Host'));
}
}

View File

@ -139,6 +139,17 @@ class FunctionsTest extends TestCase
{
self::assertGreaterThan(0, GuzzleHttp\_current_time());
}
public function testIdnConvert()
{
if (!extension_loaded('intl')) {
self::markTestSkipped('intl PHP extension is not loaded');
}
$uri = GuzzleHttp\Psr7\uri_for('https://яндекс.рф/images');
$uri = GuzzleHttp\_idn_uri_convert($uri);
self::assertSame('xn--d1acpjx3f.xn--p1ai', $uri->getHost());
}
}
final class StrClass