Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Exception: Host must be a string #2458

Closed
Mark-H opened this issue Dec 13, 2019 · 5 comments
Closed

Exception: Host must be a string #2458

Mark-H opened this issue Dec 13, 2019 · 5 comments
Milestone

Comments

@Mark-H
Copy link

Mark-H commented Dec 13, 2019

Guzzle version(s) affected: 6.5.0

Description

While attempting to communicate with the Mailchimp API, I'm presented with:

Exception Host must be a string

Trace:

Exception: Host must be a string
#0 vendor/guzzlehttp/psr7/src/Uri.php(458): GuzzleHttp\Psr7\Uri->filterHost(NULL)
#1 vendor/guzzlehttp/guzzle/src/Client.php(245): GuzzleHttp\Psr7\Uri->withHost(NULL)
#2 vendor/guzzlehttp/guzzle/src/Client.php(155): GuzzleHttp\Client->buildUri(Object(GuzzleHttp\Psr7\Uri), Array)
#3 vendor/guzzlehttp/guzzle/src/Client.php(183): GuzzleHttp\Client->requestAsync('GET', 'https://us2.api...', Array)
#4 MailchimpClient.php(118): GuzzleHttp\Client->request('GET', 'https://us2.api...', Array)

While the proper url is being passed by the calling code (shown below) into Client->request, which calls Client->requestAsync with still the right URL, that is somehow turned into an Uri object which somehow trips things up and causes the withHost to use NULL.

Did notice some PHP warnings that may be relevant:

vendor/guzzlehttp/guzzle/src/Client.php : 221 PHP warning: Use of undefined constant INTL_IDNA_VARIANT_UTS46 - assumed 'INTL_IDNA_VARIANT_UTS46' (this will throw an Error in a future version of PHP)
vendor/guzzlehttp/guzzle/src/Client.php : 221 PHP warning: idn_to_ascii() expects parameter 3 to be int, string given

How to reproduce

Honestly, "it works on my machine" (meaning my local development environment), but it breaks on a hosted staging environment and I don't have the faintest idea why. I've been baffled for 2 days at this error.

Here's the relevant code that calls the Guzzle client, pretty standard stuff:

        $client = new Client([
            'timeout' => 5
        ]);
        $res = $client->request('GET', 'https://us2.api.mailchimp.com/3.0/lists', [
            'auth' => ['apikey', $this->apiKey],
        ]);

Originally the url was dynamic, but I hardcoded it to eliminate any errors there. Initially without the timeout, found an older issue suggesting to add the timeout, didn't change the behaviour.

Possible Solution

Wish I knew!

Additional context

guzzlehttp/guzzle 6.5.0, guzzlehttp/promises 1.3.1, guzzlehttp/psr7 1.6.1

This environment also has guzzle/guzzle 3.9.3 (as a dependency of another dependency), but that hasn't gotten in the way of anything before. Can't use guzzle 7 yet as the software supports PHP 7.1 until March.

PHP 7.3.11, on a shared server.

As the PHP warnings mention intl, I checked, and that is installed with ICU version 4.2.1.

'./configure' '--prefix=/paas/php/versions/php-7.3.11' '--exec-prefix=/paas/php/versions/php-7.3.11' '--with-config-file-path=/paas/php/etc/generic' '--with-config-file-scan-dir=/paas/php/etc/generic/php.d' '--with-libdir=/lib64' '--disable-debug' '--with-pic' '--disable-rpath' '--enable-cli' '--disable-cgi' '--with-pear' '--with-bz2' '--with-freetype-dir=/usr' '--with-png-dir=/usr' '--with-xpm-dir=/usr/lib64' '--enable-gd-native-ttf' '--with-t1lib=/usr' '--without-gdbm' '--with-libedit' '--without-recode' '--with-gettext' '--with-gmp' '--with-iconv' '--with-jpeg-dir=/usr' '--with-openssl' '--with-zlib' '--with-layout=GNU' '--enable-exif' '--enable-ftp' '--enable-sockets' '--with-kerberos' '--enable-shmop' '--enable-calendar' '--with-libxml-dir=/usr' '--enable-xml' '--with-mhash' '--enable-pcntl' '--with-imap=shared' '--with-imap-ssl' '--enable-mbregex' '--enable-mysqlnd=shared' '--with-mysql-sock=/var/lib/mysql/mysql.sock' '--enable-pdo=shared' '--without-sqlite' '--with-sqlite3=shared' '--with-pdo-sqlite=shared,/usr' '--enable-bcmath=shared' '--with-curl=shared,/usr' '--enable-dba=shared' '--enable-dom=shared' '--enable-fileinfo=shared' '--with-gd=shared' '--enable-json=shared' '--enable-mbstring=shared' '--with-mcrypt=shared,/usr' '--with-mysql=shared,mysqlnd' '--with-mysqli=shared,mysqlnd' '--with-pdo-mysql=shared,mysqlnd' '--enable-phar=shared' '--enable-soap=shared' '--enable-wddx=shared' '--enable-xmlreader=shared' '--with-xmlrpc=shared' '--enable-xmlwriter=shared' '--with-xsl=shared,/usr' '--with-ldap=shared' '--with-ldap-sasl' '--without-pgsql' '--without-snmp' '--enable-zip=shared' '--with-pspell=shared' '--with-tidy=shared,/usr' '--enable-sysvmsg=shared' '--enable-sysvshm=shared' '--enable-sysvsem=shared' '--enable-posix=shared' '--enable-intl=shared' '--with-icu-dir=/usr' '--with-enchant=shared,/usr' '--enable-fpm' '--with-fpm-user=www-data' '--with-fpm-group=www-data' '--with-imagick=shared,/usr' '--without-libzip'

Doing a bit more research into the php warnings:

vendor/guzzlehttp/guzzle/src/Client.php : 221 PHP warning: Use of undefined constant INTL_IDNA_VARIANT_UTS46 - assumed 'INTL_IDNA_VARIANT_UTS46' (this will throw an Error in a future version of PHP)
vendor/guzzlehttp/guzzle/src/Client.php : 221 PHP warning: idn_to_ascii() expects parameter 3 to be int, string given

.. this might just be the problem in idn_to_ascii:

Either INTL_IDNA_VARIANT_2003 (deprecated as of PHP 7.2.0) for IDNA 2003 or INTL_IDNA_VARIANT_UTS46 (only available as of ICU 4.6) for UTS #46.

ICU 4.2.1 is installed on this server. That probably causes idn_to_ascii to return false rather than a hostname it can use..

@Mark-H
Copy link
Author

Mark-H commented Dec 13, 2019

Definitely rubber ducking here. 🦆

Looks like the IDN support was just added in 6.5.0 which is why I'm only running into it now. The problem appears introduced in #2286 - in combination with the wildly out of date intl/ICU situation.

I've managed to prevent the problem by adding 'idn_conversion' => false, to the Client constructor options.

While I'll prompt the server admin about intl/ICU, I think it's probably a good idea to correct the check for $asciiHost to also make sure it isn't empty. It should probably not be possible for valid input to be gobbled up like this.


The call to idn_to_ascii is returning NULL (even though according to the docs, the return value for an error should have been false).

Changing

if ($asciiHost === false) {

to

if ($asciiHost === false || $asciiHost === null) {

causes the regular error handling to kick in which makes it throw an InvalidArgumentException with message IDN conversion failed.

I'd argue that it should not throw an exception for a failed IDN conversion at all, or perhaps only when a special option is set so the user makes idn conversion mandatory).


I'd be happy to try and prepare a patch, but would appreciate some guidance on what others think the best way to fix this would be.

@alexeyshockov
Copy link
Collaborator

Please take a look at #2454

@Mark-H
Copy link
Author

Mark-H commented Dec 13, 2019

Ahh.. excellent! :) Confirmed that fixes the issue on my environment.

@brandonkelly
Copy link
Contributor

@Mark-H Probably should reopen until #2454 has actually been merged in

@nadia-am
Copy link

@Mark-H changing if ($asciiHost === false) { to if ($asciiHost === false || $asciiHost === null) { Solve that problem but it cause an other error :
Fatal error: Uncaught GuzzleHttp\Exception\InvalidArgumentException: IDN conversion failed in .../translate/vendor/guzzlehttp/guzzle/src/Client.php:243 Stack trace: #0 .../translate/vendor/guzzlehttp/guzzle/src/Client.php(156): GuzzleHttp\Client->buildUri(Object(GuzzleHttp\Psr7\Uri), Array) #1 .../translate/vendor/guzzlehttp/guzzle/src/Client.php(184): GuzzleHttp\Client->requestAsync('get', 'https://transla...', Array) #2 .../translate/vendor/guzzlehttp/guzzle/src/Client.php(97): GuzzleHttp\Client->request('get', 'https://transla...', Array) #3 .../translate/vendor/stichoza/google-translate-php/src/GoogleTranslate.php(304): GuzzleHttp\Client->__call('get', Array) #4 .../translate/vendor/guzzlehttp/guzzle/src/Client.php on line 243
the error is in client.php
if ($asciiHost === false || $asciiHost === null) { $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);/*********** here is line 243 ***********/ }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants