3

We are currently testing performances on our web servers and are getting very different results between production servers and test servers.

The test we are making is the following:

  • Download the RSS feed XML available on the site
  • Make a HEAD request of all links present on into the XML feed to check if url is correct

Suprisingly the average response time on the Test servers is around 15ms when the same measurement reads 900 ms on prod servers. As both servers are (supposed to be) configured identically, I am very puzzled by those results.

  1. Am I correct in thinking that HEAD requests of .CFM pages do not actually involve the ColdFusion server but only IIS?
  2. If I am correct with the first point, where can I check on the IIS level what can make such a difference in response time?

Following up on the suggestions I received from you guys, I simply tried to add a log entry into a test cfm page to see if the CFLog gets executed or not.

Surprisingly, the same HEAD request on the same file generates a log entry in prod. and not in test. Obviously, the config should be different between test and prod but I don't know at which level.

E. Jaep
  • 2,095
  • 1
  • 30
  • 56
  • 1
    I wouldn't be too sure about your first assumption. Have you tried cURL to get the pages by hand? You can use the -X option to set the HTTP verb as HEAD. I'd see what each server returns in order to be sure. – barnyr Feb 15 '13 at 15:50
  • I tried using Fiddler. As expected, the response content is empty but the question on the fact that the server actually has to build the response remains. – E. Jaep Feb 15 '13 at 15:54
  • That's my other tool of choice! Have you tried putting a – barnyr Feb 15 '13 at 16:12
  • _"As both servers are (supposed to be) configured identically"_ - are both the servers identical specs too? And are the database servers also the same specs & configured identically (including, as nosilleg points out, having identical data)? – Peter Boughton Feb 18 '13 at 13:06

2 Answers2

1

Your first assumption is incorrect. A response to a HEAD request has to be coded and isn't handled automatically. A HEAD request should respond with identical header information as a GET request, which generally means executing the same code as a GET request and then omitting the message-body in the response.

From the HTTP spec, section 9.4:

The HEAD method is identical to GET except that the server MUST NOT return a message-body in the response. The metainformation contained in the HTTP headers in response to a HEAD request SHOULD be identical to the information sent in response to a GET request. This method can be used for obtaining metainformation about the entity implied by the request without transferring the entity-body itself. This method is often used for testing hypertext links for validity, accessibility, and recent modification.

The response to a HEAD request MAY be cacheable in the sense that the information contained in the response MAY be used to update a previously cached entity from that resource. If the new field values indicate that the cached entity differs from the current entity (as would be indicated by a change in Content-Length, Content-MD5, ETag or Last-Modified), then the cache MUST treat the cache entry as stale.

I think it's very rare to see dynamic sites, CMSs or frameworks that actually implement the majority of things like HEAD responses, valid ETags, etc - so generally you'll get identical responses from a GET and a HEAD, including the message-body that is supposed to be stripped from a HEAD request.

I'm assuming that what you're experiencing in the time difference is attributable to content differences between the servers. That is, a test server may only have minimal content and therefore executes faster than the full content production servers.

nosilleg
  • 2,143
  • 1
  • 22
  • 36
  • _"including executing all code"_ - it only needs to execute what it requires to set the appropriate headers. – Peter Boughton Feb 18 '13 at 12:13
  • 2
    @PeterBoughton which is why the rest of the sentence is "in order to output the same meta information". So yes, if there's code that doesn't affect the page output then it doesn't need to be run. That being said, I can't actually think of much of my own code that could be stripped when doing a `HEAD` request, since if it's not affecting the output signature then it probably shouldn't be running in the first place. – nosilleg Feb 18 '13 at 12:38
  • But the start is "do exactly the same", which is wrong. The whole sentence could probably do with re-writing to make it clear. – Peter Boughton Feb 18 '13 at 13:04
  • As for when it's different, for a CMS that calculates/stores metadata at edit time, a head request only needs to read relevant metadata, not read/execute the entire contents - similar to responding to a If-Modified-Since, which only executes enough to know if to respond 304 or to proceed with full request. – Peter Boughton Feb 18 '13 at 13:04
  • 1
    @PeterBoughton Note that I say "should" and not "must". Maybe you would prefer that I write "SHOULD" as the spec does? Feel free to hack responses with partial data, but you SHOULD be evaluating more of the actual response. I'm choosing to ignore your complaint that the start of a sentence is wrong if you refuse to read the end of it. But this is all secondary to the fact that a responses to a `HEAD` request has to be coded and isn't handled automatically, which is the crux of the question and answer. – nosilleg Feb 18 '13 at 14:11
0

I didn't know the answer to this question, but I knocked together some code to test it, and have some results. Caveat: I'm only using the internal Tomcat web server, and I'm using CF10 (I note you're using CF8). I do not think their of those caveats invalidate my findings in the context of your particular situation.

<!--- headMe.cfm --->
<cflog text="hit" file="headMe">


<!--- doHead.cfm --->
<cfhttp method="head" url="http://localhost/headMe.cfm" result="httpResponse" />
<cfdump var="#variables#">

So I browse to doHead.cfm, which does an HTTP HEAD of headMe.cfm. If headMe.cfm was actually executed, then we'd get a log entry in headMe.log. If not: no log entry.

The httpResponse variable was all legit and as to be expected for a HEAD request, and... I got the log entry.

So my conclusion is that when receiving a HEAD request, unfortunately all the CFML is actually executed. I don't really think it should be. There's nothing in the HTTP spec to suggest it should or shouldn't cause "dynamic" requests to fully execute, but it'd be nice if it didn't, I think.

Anyway, HTH.

Adam Cameron
  • 29,677
  • 4
  • 37
  • 78
  • _"I don't really think it should be."_ - HUH? Why on earth should CF _not_ handle HEAD requests? – Peter Boughton Feb 18 '13 at 12:16
  • 1
    I didn't suggest CF (the server) shouldn't handle HEAD requests, I meant that - given in 99.99% of times the ensuing CFML (the code) is not going to be relevant to the *response* from the HEAD request, it seems a shame that it all executes. However - now that I engage my brain better than before - there's still the 0.01% of the time that some of the response headers come from CFML processing, so it does still need to be done. I guess if one wants to bypass all that, it's a matter of dealing with it in onRequestStart(). – Adam Cameron Feb 19 '13 at 01:29
  • @AdamCameron Following up on your idea, I tried almost the same thing. The only difference was I called the HeadMe.cfm from Fiddler instead of a cfhttp tag. Surprisingly, on CF8, the log entry does not get generated when performing a HEAD request. Therefore the code is not executed. Could it be a difference between CF8 and CF10? to be continued... – E. Jaep Mar 01 '13 at 09:49
  • @AdamCameron Even more surprising. When performing a HEAD request on Production servers run the code when the same request on Test does not. There must be setting somewhere that controls that... – E. Jaep Mar 01 '13 at 09:54
  • Interesting. I don't have CF8 to test on here, but do @ home. Will check this evening if I get a moment. – Adam Cameron Mar 01 '13 at 13:42