From 87b095dae9f2c562e9e0965818983ac180c70d57 Mon Sep 17 00:00:00 2001 From: Ryan McCue Date: Tue, 14 Jun 2016 05:29:58 +0000 Subject: [PATCH] HTTP API: Update Requests. This introduces a minimum value of 1 second for timeouts passed to cURL. Internally, cURL uses alarm() for interrupts, which accepts a second-resolution timeout. Any values lower than 1 second are instantly failed rather than being rounded upwards. While this makes the experience worse for those using asynchronous DNS lookups, there's no way to detect which DNS resolver is being used from PHP. See #33055, #8923. git-svn-id: https://develop.svn.wordpress.org/trunk@37694 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-includes/Requests/Transport/cURL.php | 16 ++++++++++++---- src/wp-includes/class-requests.php | 2 ++ 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/wp-includes/Requests/Transport/cURL.php b/src/wp-includes/Requests/Transport/cURL.php index ce09111cba..36cba510c7 100755 --- a/src/wp-includes/Requests/Transport/cURL.php +++ b/src/wp-includes/Requests/Transport/cURL.php @@ -176,7 +176,7 @@ class Requests_Transport_cURL implements Requests_Transport { $this->process_response($response, $options); - // Need to remove the $this reference from the curl handle. + // Need to remove the $this reference from the curl handle. // Otherwise Requests_Transport_cURL wont be garbage collected and the curl_close() will never be called. curl_setopt($this->handle, CURLOPT_HEADERFUNCTION, null); curl_setopt($this->handle, CURLOPT_WRITEFUNCTION, null); @@ -349,11 +349,19 @@ class Requests_Transport_cURL implements Requests_Transport { break; } - if (is_int($options['timeout']) || $this->version < self::CURL_7_16_2) { - curl_setopt($this->handle, CURLOPT_TIMEOUT, ceil($options['timeout'])); + // cURL requires a minimum timeout of 1 second when using the system + // DNS resolver, as it uses `alarm()`, which is second resolution only. + // There's no way to detect which DNS resolver is being used from our + // end, so we need to round up regardless of the supplied timeout. + // + // https://github.com/curl/curl/blob/4f45240bc84a9aa648c8f7243be7b79e9f9323a5/lib/hostip.c#L606-L609 + $timeout = max($options['timeout'], 1); + + if (is_int($timeout) || $this->version < self::CURL_7_16_2) { + curl_setopt($this->handle, CURLOPT_TIMEOUT, ceil($timeout)); } else { - curl_setopt($this->handle, CURLOPT_TIMEOUT_MS, round($options['timeout'] * 1000)); + curl_setopt($this->handle, CURLOPT_TIMEOUT_MS, round($timeout * 1000)); } if (is_int($options['connect_timeout']) || $this->version < self::CURL_7_16_2) { diff --git a/src/wp-includes/class-requests.php b/src/wp-includes/class-requests.php index 89a2dda9e2..f5aced060a 100644 --- a/src/wp-includes/class-requests.php +++ b/src/wp-includes/class-requests.php @@ -304,6 +304,8 @@ class Requests { * options: * * - `timeout`: How long should we wait for a response? + * Note: for cURL, a minimum of 1 second applies, as DNS resolution + * operates at second-resolution only. * (float, seconds with a millisecond precision, default: 10, example: 0.01) * - `connect_timeout`: How long should we wait while trying to connect? * (float, seconds with a millisecond precision, default: 10, example: 0.01)