WordPress plugin authors: Please use timeouts when contacting other servers
We occasionally hear from customers saying “my WordPress site suddenly got so slow it’s unusable”. When we look into these, the usual cause is that:
- Our customer has installed a WordPress plugin;
- The plugin attempts to contact another server as part of its normal operation;
- But the other server isn’t working properly: it fails to respond to connection attempts.
Ideally, this wouldn’t be a problem. The plugin would contain code that includes a “timeout”, so that if it couldn’t successfully contact the other server in, say, two seconds, it would give up and continue displaying the page in a graceful way.
Unfortunately, we get reports of many plugins that contain no timeout code at all, which makes WordPress just “hang” for 30 seconds or more. For example, here’s the code from a plugin we just examined:
$ch = curl_init();
curl_setopt($ch, CURLOPT_USERAGENT, $user_agent);
curl_setopt( $ch, CURLOPT_HTTPGET, 1 );
curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 );
curl_setopt( $ch, CURLOPT_FOLLOWLOCATION , 1 );
curl_setopt( $ch, CURLOPT_URL, $url );
curl_setopt( $ch, CURLOPT_REFERER, $ref);
curl_setopt ($ch, CURLOPT_COOKIEJAR, 'cookie.txt');
$html = curl_exec($ch);
curl_close($ch);
This code sets all sorts of options, so clearly the author has an idea of how to use the PHP curl functions. But it doesn’t set a timeout, meaning this plugin will completely break the WordPress site when the server at “$url” doesn’t respond.
The solution is easy. Plugin authors can just add a couple more option lines:
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 2);
curl_setopt($ch, CURLOPT_TIMEOUT, 2);
That’s all it takes to prevent your plugin from breaking people’s sites. Other ways of loading data from other servers, such as wp_remote_post, also offer timeout features.
So: If you’re a plugin author and your plugin contacts a remote server, please make sure it times out quickly if that server isn’t working. A good test is to see what happens if you try to make it connect to an IP address that exists, but which drops packets sent to port 80. At the time of this writing, “http://8.8.8.8/” is a good example of this. If you’re looking for a test server that completes the connection quickly but takes a while to send the final response (which is a different behavior that can expose different bugs), slowapi.com is useful.