php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #67584 Misleading error in pecl_http 2.0.x
Submitted: 2014-07-07 13:40 UTC Modified: 2016-08-17 09:43 UTC
Votes:1
Avg. Score:4.0 ± 0.0
Reproduced:0 of 1 (0.0%)
From: marcus at synchromedia dot co dot uk Assigned: mike (profile)
Status: Closed Package: HTTP related
PHP Version: 5.4.30 OS: OS X
Private report: No CVE-ID: None
 [2014-07-07 13:40 UTC] marcus at synchromedia dot co dot uk
Description:
------------
I'm using pecl_http 2.0.x. I'm issuing multiple requests in one go using enqueue, and if a transfer fails it throws an exception which I catch and ignore because the details of it will be revealed when inspecting Responses afterwards. So I loop over the responses provided by the client, all of which are http\Response instances, and yet I receive this error when calling getResponseCode:

PHP Warning:  http\Message::getResponseCode(): http\Message is not if type response

(note the mis-spelling of 'of', probably makes it easier to track down). So the http\Client::getResponse is returning http\Response objects as expected, but when I call a method on one to get its status, it complains that it's another type??

It's hard to tell what it's meant to be doing because the Response class is almost entirely undocumented: http://devel-m6w6.rhcloud.com/mdref/http/Client/Response

Test script:
---------------
<?php
$urls = array(
	'http://www.apple.com/',
	'http://www.google.com/',
	'http://www.googlesdfasdfsadfsdf.com/'
);
$client = new http\Client;
$client->setOptions(array(
	'timeout' => 5,
	'connecttimeout' => 5,
));
foreach ($urls as $url) {
	$client->enqueue(new http\Client\Request('GET', $url));
}
try {
	//Issue all the requests
	$client->send();
} catch (http\Exception $e) {
	//Ignore exceptions - they will have bad response codes too
}
//Parse responses
while ($response = $client->getResponse()) {
	echo get_class($response)."\n";
	$url = $response->getTransferInfo('effective_url');
	if ($response->getResponseCode() == 200) {
		$e = $response->getBody();
		//echo $e;
	}
}


Expected result:
----------------
I'm not sure what it's meant to do because it's not documented, but it certainly shouldn't be breaking weirdly like this.

Actual result:
--------------
http\Client\Response
http\Client\Response
http\Client\Response
PHP Warning:  http\Message::getResponseCode(): http\Message is not if type response in test.php on line 25

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2014-07-07 14:52 UTC] mike@php.net
-Status: Open +Status: Assigned -Assigned To: +Assigned To: mike
 [2014-07-07 14:52 UTC] mike@php.net
I'm sorry you've had such a hard time using this library.

As already noted at your comment in the docs, all of those methods are actually http\Message methods. http\Client\Response is just a thin layer adding exactly those few methods as documented.

If the response raises that error (thanks for spotting thy typo) it basically means a response was never received and the message is completely blank. Basically an uininitialized http\Message. I'll fix that.

Now to your use case. If an exception occurs everything else currently executing is stopped of course. If the first thing that happens is a DNS exception nothing else happened. You have to use the more fine grained API if you want information of the single requests you were issuing; see http://devel-m6w6.rhcloud.com/mdref/http/Client/once which throws warnings instead of exceptions.
 [2014-07-07 15:48 UTC] marcus at synchromedia dot co dot uk
Thanks for getting back to me.


If I issue my requests with:

while (@$client->once()) {
    $client->wait();
}

Where would failure information be stored when iterating over the output of getResponse afterwards? Dealing with them inside that loop seems like it might interfere with the parallel nature of the requests? If not, how can I get a handle on which Request object caused the error, assuming they could complete or fail in random order?

When you say "I'll fix that", do you mean that getResponse will return a proper Response instance with error info instead of complaining it's a Message?

I'm using this in two places - a link checker and an image grabber - where I want all the requests to happen (even if some fail), in parallel, and assess the responses afterwards.

I'm also getting consistent segfaults in the test script on the first line inside the getResponse loop if I step through it with xdebug (in PHPStorm). I don't know if that's your department.
 [2014-07-08 10:21 UTC] mike@php.net
Disregard the exception behavior I gave before, it seems I tripped over old memory.

$response->getTransferInfo("error") should contain the same information like the exception message.

I committed a fix for the uninitialized response object to R_2_0 and master. Could you try one of those?

Do you mean that "get_class($response);" segfaults with XDebug?
I'll have a look! What's your XDebug version=?
 [2014-07-08 10:23 UTC] mike@php.net
I forgot to answer the question about the originating request:

The response has its request as parent message:
$request = $response->getParentMessage();
 [2014-07-08 11:02 UTC] marcus at synchromedia dot co dot uk
I'll have a go with a fresh build.

I just tried a few variations on the breakpoint. The segfault happens when I set a breakpoint on the '$url = ...' line. I run the script in debug mode - it echoes the first class name, then quits with an error 139, which is a segfault. I'm running xdebug 2.2.5 in PHP 5.4.30 built from homebrew on OS X 10.9.4.

Without the breakpoint, it does not segfault and completes successfully.
 [2014-07-08 15:39 UTC] marcus at synchromedia dot co dot uk
I've managed to grab your latest code from the git repo, but I don't know how to tell it where to find the raphf header files so it's failing when I do a 'pecl build'. I installed raphf and propro from source via homebrew, so their header files are in /usr/local/Cellar/php54-raphf/1.0.4/include and /usr/local/Cellar/php54-propro/1.0.0/include.
 [2014-07-10 12:06 UTC] mike@php.net
Doh. You could try with a CFLAGS env like:

CFLAGS="-I/usr/local/Cellar/php54-raphf/1.0.4/include -I/usr/local/Cellar/php54-propro/1.0.0/include" pecl build
 [2014-07-11 08:19 UTC] marcus at synchromedia dot co dot uk
That doesn't quite work - it's assuming the includes are in the ext/ folder under a PHP source tree, not built independently. I worked around that by making an ext folder containing a symlink back to its parent folder and then it found them ok, but then it fails with this error, which seems unrelated:

/Users/marcus/Sites/pecl_http/php_http_params.c:714:5: error: use of undeclared identifier 'HASH_KEY_NON_EXISTENT'
        &&      HASH_KEY_NON_EXISTENT != (key.type = zend_hash_get_current_key_ex(ht, &key.str, &key.len, &key.num, key.dup, NULL))
                ^
1 error generated.
make: *** [php_http_params.lo] Error 1
`make' failed
 [2014-07-11 09:18 UTC] mike@php.net
Sorry, I stumbled over this PHP-5.4 incompatibility the other day.
The current HEADs shouldn't suffer from this issue!
 [2014-07-11 17:49 UTC] marcus at synchromedia dot co dot uk
That worked - I can now run my original script without those type errors - thanks.

Still two things outstanding. If a request fails for a non-HTTP reason (e.g. DNS failure), I can see that it populates the transferinfo error property - is there an error code property so I don't have to rely on string matching here? As far as I can see everything else is 0 or -1.

Also, the script is still giving me 139 error codes, segfaulting at the same point as before.
 [2016-08-17 09:43 UTC] mike@php.net
-Status: Assigned +Status: Closed
 [2016-08-17 09:43 UTC] mike@php.net
Please create a report at https://github.com/m6w6/ext-http/issues if this issue still exists.

Thank you!
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Fri Apr 19 19:01:28 2024 UTC