I've been going crazy because of a timeout that is occurring on chunked requests with PHP version 5.5 and curl version 7.51.0. PHP is requesting a set of data from a Scala Play Framework service, which is returning a chunked response.
What's happening: As soon as the PHP request waits 60 seconds for the next chunk, it terminates with a CURL error 18. This same endpoint works with requests of smaller sizes, so I know that it's not a general connection issue.
Testing the endpoint from the PHP box via command line using a request of this format works without issue:
curl -i -X POST -H 'Content-Type: application/json' -d '<Request Params>' <URL>
My PHP Request (using guzzle shown here, but I've also tried raw curl exec) looks like this:
$client->request('POST', $route, [
// I thought this would work first
'timeout' => 120,
// Maybe some of these other timeouts will help...
'connect_timeout' => 120,
'read_timeout' => 120,
'json' => $body,
'headers' => [
// I found some random SOs that suggest setting headers..
'Connection' => 'close',
'Expect' => '',
'Transfer-Encoding' => 'chunked'
],
'stream' => true,
'curl' => [
// Beginning the descent into insanity
CURLOPT_CONNECTTIMEOUT => 120,
// I don't have a low speed limit set but maybe?
CURLOPT_LOW_SPEED_TIME => 120,
// Perhaps there's a guzzle bug that doesn't set timeout.. NOPE
CURLOPT_TIMEOUT => 120,
// Hey, this one works! We'll see in the curlinfo below
CURLINFO_HEADER_OUT => true,
CURLOPT_VERBOSE => true,
CURLOPT_STDERR => '<logloc>',
// alright this isn't even a socket connection but sure
CURLOPT_FORBID_REUSE => true,
// SET ALL OF THE TIMEOUTS!!
CURLOPT_TCP_KEEPALIVE => 120,
CURLOPT_TCP_KEEPIDLE => 120,
CURLOPT_TCP_KEEPINTVL => 120
]
]);
None of the above worked. Some suggestions recommend that I set HTTP version to 1.0. That is an unnacceptable solution, as the data returned from this endpoint needs to be streamed directly in the response (hence stream => true). The same problem occurs with raw curl (without Guzzle).
In addition to the above request settings, I've set the following PHP settings:
set_time_limit(0); // also have set this to large numbers
ini_set("default_socket_timeout", 270); // Have also set this in the PHP.ini
The curl stats of the failed response are
{
"url": "<URL>",
"content_type": "text/plain; charset=utf-8",
"http_code": 200,
"header_size": 144,
"request_size": 207,
"filetime": -1,
"ssl_verify_result": 0,
"redirect_count": 0,
"total_time": 60.20854, // WHY CRUEL WORLD??
"namelookup_time": 0.124769,
"connect_time": 0.125011,
"pretransfer_time": 0.132244,
"size_upload": 116,
"size_download": 51,
"speed_download": 0,
"speed_upload": 1,
"download_content_length": -1,
"upload_content_length": -1,
"starttransfer_time": 0.132248,
"redirect_time": 0,
"redirect_url": "",
"primary_ip": "<>",
"certinfo": [],
"primary_port": 443,
"local_ip": "<>",
"local_port": 39562,
"request_header": "POST <URL> HTTP/1.1 Host: <HOST> User-Agent: GuzzleHttp/6.2.1 curl/7.51.0 PHP/5.5.38 Content-Type: application/json Connection: close Transfer-Encoding: chunked "
}
Then it throws:
cURL error 18: transfer closed with outstanding read data remaining (see http://curl.haxx.se/libcurl/c/libcurl-errors.html
To sum up..
I've set a number of timeout variables, but none that I've set have been able to rid me of this insanity. Can anyone show me the light?