Skip to content

curl_error() is missing a fallback as expected and documented in curl manual #14915

Closed
@arekm

Description

@arekm

Description

The following code:

$session = curl_init();
curl_setopt($session, CURLOPT_URL, "https://someserver/cmd.php");
curl_setopt($session, CURLOPT_USERPWD, "user:pass");
curl_setopt($session, CURLOPT_SSL_VERIFYHOST, 1);
curl_setopt($session, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($session, CURLOPT_TIMEOUT, 70);
curl_setopt($session, CURLOPT_CONNECTTIMEOUT, 10);
curl_setopt($session, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($session, CURLOPT_HTTPHEADER, array('Content-type: application/json', 'Expect:'));
curl_setopt($session, CURLOPT_FAILONERROR, 1);
curl_setopt($session, CURLOPT_POST, 1);
curl_setopt($session, CURLOPT_POSTFIELDS, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
$response = curl_exec($session);
echo "curl_error: " . curl_error($session) . ", curl_errno: " . curl_errno($session) . "\n";

Resulted in this output:

$ php83 --version
PHP 8.3.9 (cli) (built: Jul  7 2024 09:48:02) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.3.9, Copyright (c) Zend Technologies
$ php83 test.php
curl_error: , curl_errno: 16

But I expected this output instead:

curl_error: Error in the HTTP2 framing layer, curl_errno: 16

since that's what curl cmdline returns

$ sh test.sh
curl: (16) Error in the HTTP2 framing layer

Server is some old lighttpd 1.4.73 which most likely mishandles HTTP/2 and allows me to reproduce such error but unfortunately it's not reachable over internet.

But I have an explanation on what's wrong.

php is currently doing

PHP_FUNCTION(curl_error)
{
[...]
        if (ch->err.no) {
                ch->err.str[CURL_ERROR_SIZE] = 0;
                RETURN_STRING(ch->err.str);
        } else {
                RETURN_EMPTY_STRING();
        }
}

and err.str is set

curl_easy_setopt(ch->cp, CURLOPT_ERRORBUFFER,       ch->err.str);

The problem

curl documentation says that errobuffer sometimes can be not filled with error and then you are expected to fallback to curl_easy_strerror(). See example C code in manual: https://curl.se/libcurl/c/CURLOPT_ERRORBUFFER.html

That's what curl cmdline does:
https://github.com/curl/curl/blob/curl-8_8_0/src/tool_operate.c#L402-L403
(msg is their CURLOPT_ERRORBUFFER buffer)

Similar bug existed in pycurl until got fixed in latest release:
pycurl/pycurl@88d2bff

Solution

Solution is to return curl_easy_strerror() information instead of RETURN_EMPTY_STRING()

PHP Version

PHP 8.3.9 (all existing php versions including git master)

Operating System

No response

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions