I had an interesting (read frustrating) day at work today. We are in the process of consolodating some of our servers, we got a new duel 2.6ghz xeon’s with raid’d scsi and a chunk of ram - i don’t remember the specs but it’s pretty fast and it’s going to be our new sql server. The old box that used to serve both sql and web was also a duel spec’d machine albeit a slower one, that ran 2000 server and iis 5.0, this box’s new lease of life is that of a dedicated http server. Both machines will be running 2003 server. So that’s the background to this little adventure.
Last friday I began a test migration of our old webapp to a test setup of IIS 6.0 that is temporarily living on the new sql server. The web app is a mixture of mostly stock standard asp but there are also a couple of .net components and a couple of straight forward perl scripts (more about these two PITA’s later). ASP pages aren’t enabled by default in IIS 6.0 so the first thing I had to do was enable the ASP server extension. The server extensions node in the IIS manager appears to be a new management concept to control centrally what extensions are supported by the web server, things such as server-side-includes, asp.net support CGI program support, ISAPI support and the rest - much like the AddModule/AddHandler stuff in Apache. I think this is a good idea, though, I was a bit dissapointed that the server extensions weren’t obviously configurable on a website by website basis. That was the first part of getting my ASP pages working. The second part involved editing the metabase.xml file (located at %WINDIR%/System32/inetsvr/metabase.xml) and setting the AspEnableParentPath attribute to TRUE. This is because a lot of the ASP I had written included different asp modules from relative parent directories (i.e. they used ../[../]* in their paths). Again this is a property that is disabled by default for security reasons and is generally not needed when using the more recent asp.net technologies. So after enabling ASP and setting up my Data Source to point to the current DB the majority of the web app was up and running and after setting the connection string to use for the asp.net components so too were they. By now it was about 4:30pm and time for a beer.
Well the weekend flew past and this morning it was time to send the email to the PTB (powers that be) informing them of the pending downtime and movement, it was also time that I checked to make sure that my perl scripts were working properly and this my friends is where the “fun” and frustration begins. So after reading the documentation that came with ActiveState perl 5.8.4 I was wrongly hoping that my perl scripts would just-work™. How wrong I was it took me a day to figure out and in the end was caused by two simple yet frustrating changes in the behaviour of CGI in IIS 5.0 and IIS 6.0, with no help i might add from the error message spat to the browser by IIS or from IIS’s log entries. Basically the error that i saw looked something like this (this is from memory so it is quite possible it is not entirely accurate):
<title>Error<title>
CGI Error
The specified CGI application misbehaved by not returning a complete set of HTTP headers. The headers it did return are:
So, it appears that my scripts had not only become deliquents during their transfer but were also not returning any errors. Well I thought that was a bit strange so I went and had a look at the log files for the requests (it’s amazing how many ctrl-F5’s you’ll do just to see if it works this time around) and all they had to tell me was that the server returned a HTTP 502 error. Not the HTTP 200 OK that I so desired. Taken from msdn: HTTP 502 is the error code for a Bad Gateway and the description is The server, while acting as a gateway or proxy, received an invalid response from the upstream server it accessed in attempting to fulfill the request. Hrmm.
So I realise that when it says upstream server (particularly wrt CGI) it is talking about the program that is called by the http server to generate the content to return, but it still didn’t make particularly a lot of sense to me. But moving right along, I hacked up a little test hello world perl script and it looked like this:
print “Content-type: text/htmlnn";
print “hellohello";
and by god it worked! (note: both scripts ran as they should when they were run from the command line). I"m going to paraphrase my day and skip to a shorter (but still long winded) description of the problem and the solution. So I try and add one of my perl modules that i use in the production scripts to my little tester and WHAM! i get that educative error message shown above, I thought thats a little wierd the modules work just fine when ran from the command line - whats changed? My first thought was that in the security upgrades to IIS 6.0 and server 2003 that they’d somehow overridden or replaced the open function used by cgi programs such that they were unable to use relative directories, so I replaced the relative directories that I was adding to the @INC array with absolute directories and wahla the script worked more than it did two minutes before. They still weren’t working as the should though.
My scripts grab some data from the database put it in a temporary file and then process the tempory file, they use a temporary file as both a cache of the data (it doesn’t change once it’s entered in the database) and so that they can pass the data to third party apps before they do some further processing. The problem was that these files weren’t being created!? WTF they’re being created when I run the script from the command line so again, what problem is IIS having. So for some reason I decided to find out what the current working directory was that the script was running in. It took me a few looks but then it clicked, the script was being run from a directory different to what I was expecting, and thats why the relative paths weren’t working but the absolute paths were and it’s also why the temporary files weren’t being created.
Here’s what I think happens when executing cgi IIS 5.0 compared with IIS 6.0. Say a request is made for /foo/bar.pl (maps to c:webappfoobar.pl). Now, IIS5.0 appears to changes directory to c:webappfoo and then executes the equivalent of perl bar.pl. So the current working directory is c:webappfoo and any relative path is relative to this directory. IIS6.0 on the other hand appears to stay in the root directory of the web app (in this case /, which maps to c:webapp) and executes the equivalent of perl foo/bar.pl. It’s this difference that was causing me a lot of my headaches but not all of them. I’ll talk about the second problem I had tomorrow. Sorry for taking so long to talk about so little.
]: Failed opening '/home/unexcog/public_html/ir/blog/wp-comments.php' for inclusion (include_path='.:/usr/lib/php:/usr/local/lib/php') in