Wednesday, October 6, 2010

file_get_contents acting very slow

Lately i have been working on a simple REST-like service interface to an existing product at work. I admit, I found some code online that I modified. No need to do work already done, right? ;-)

The problem arose when i tried to call my brand new web service. I got extremely long waiting time (about 15 secs to precise), before the resource was returned. The code I used look like this:

$result = file_get_contents('http://example.com/service/');

As simple as it gets. When I tried calling the service directly from my browser, the result came back instantly.

I turned to my old friend Google to look for an answer. Most of the answers i got was that the DNS lookup was slow. So i tried my script from all the different servers I have access to, but with the same result.

The solution was quite simple, when I finally found it. In my REST-like service I set the follow header:

header('HTTP/1.1 200 OK');

By doing this I force the connection to use HTTP 1.1. This is pretty standard, but apparently by doing this I use the default behaviour of HTTP 1.1 and that is to keep the connection alive. The same as setting:

header('Connection: keep-alive');

So the connection started by file_get_contents() is keept open, until it times out. Timeout is set to 15 secs on the server!! So the solution was to put the following header in my service:

header('Connection: close');

A w00p w00p the result was returned instantly.

A quick tip if you run into this problem, and the service is not your own, is to set the header yourself. You can do this by giving a context to the file_get_contents. This can be done by doing the following:

$opts = array(

'http'=>array(
header' => 'Connection: close'
)
);
$context = stream_context_create($opts);

$result = file_get_contents('http://example.com/service/', false, $context);

This will force the connection to close immediately after the resource have been retrived. Al option that can be set in a context (for HTTP) can be found here: http://php.net/manual/en/context.http.php