Sunday, January 22, 2012

How Do You Log Messages From a CGI File?

I am writing a rather special purpose CGI in Korn Shell that runs on my webpage.  Unfortunately, I am having a heck of a time figuring out how to debug it!  It has to respond to a series of HTTP GET requests sent by a third party.

I can retrieve the HTTP GET requests from the access_log on my server, and put them into a file.  I can then redirect that file into my CGI script on my local Linux box, and it produces the correct output to stdout.  I can do the same on the Unix box that runs my server, and it produces the correct output to stdout.  In case you are curious, the CGI script looks like this:





#!/bin/ksh
# Redirect stdin to get the form parms passed
PARM_PASSED=$(< /dev/stdin)
# Identifies that we are returning HTML (even though what I am sending back is just text).
print "Content-type: text/html\r\n"
# Process the form input
if [[ "$PARM_PASSED" != "" ]]
then
# Isolate the query type
PARMS=`echo "$PARM_PASSED" | sed "s/^.*cgi?q=//g" | sed "s/&.*$//g"`
# Now loop through the parameters (should only be one per line for this example).
for PARM in $PARMS
do
# The following if elif provides a case switch for the various parameters that Balihoo is
# sending me.
if [[ $PARM = "Ping" ]]
then
  print -n "OK"
elif [[ $PARM = "Resume" ]]
then
  print -n "http://www.claytoncramer.com/balihoo/RESUME.pdf"
elif [[ $PARM = "Name" ]]
then
  print -n "Clayton E. Cramer"
elif [[ $PARM = "Source" ]]
then
  print -n "http://www.claytoncramer.com/balihoo/balihoo.cgi"
elif [[ $PARM = "Years" ]]
then
  print -n "30"
elif [[ $PARM = "Degree" ]]
then
  print -n "Perhaps not relevant.  BA, History (computer science minor); MA, History."
elif [[ $PARM = "Position" ]]
then
  print -n "Senior Software Developer"
elif [[ $PARM = "Email+Address" ]]
then
  print -n "clayton@claytoncramer.com"
elif [[ $PARM = "Expression" ]]
then
  # Get the expression that they want evaluated.
  EXPRESSION=`echo "$PARM_PASSED" | sed "s/^.*What+is+//g" | sed "s/%3F.*$//g"`
  # Remove the + separators between operators and numbers
  EXPRESSION=`echo "$EXPRESSION" | sed "s/\+//g"`
  # Convert various HTML encodings to the equivalent operators
  EXPRESSION=`echo "$EXPRESSION" | sed "s/%2A/\*/g" | sed "s/%2B/\+/g" | sed "s/%2D/-/g" | sed "s&%2F&/&g"`
  RESULT=$((EXPRESSION))
  echo -n $RESULT
fi
done
fi




But the third party HTTP GET requests claim that it is not working correctly:

Expected Ping to return 'OK', but got ''.


If I create a very simple CGI script to return OK, such as this:

#!/bin/ksh
print "Content-type: text/html\r\n"
print -n "OK"
The third party HTTP GET requests work fine for the first request, but not surprisingly, goes no further for subsequent requests.

My guess is that the somewhat more elaborate CGI script to respond to the various GET requests has some subtle bug in it.  Is there some way to log messages from that CGI script so that I can see what happens when the requests come in?  Anything going to stdout or stderr appears to go back to the requester, and it does not appear that a CGI script can write to a local file when it is responding to a GET request.  (Probably a security thing, and not a bad idea.)  I do not have the option of reconfiguring the server running on my hosting service (for obvious reasons).  Can anyone suggest a method for tracking what my CGI script is doing?

UPDATE: No, it isn't the path to sed that is blowing it up.  If I put the lines:



print "Content-type: text/html\r\n"
print -n "OK"
exit 


before the attempt to isolate the PARM, it works for the first step--responding to the Ping request.


UPDATE 2: At least for Windows, here's a useful tool that lets you send individual GET operations and see what comes back.

5 comments:

J Greely said...

When run from the CGI environment, is sed in the PATH? If not, the script will exit with an error after just printing the Content-Type line.

-j

Clayton said...

Excellent catch! I will check that.

Kirk Parker said...

This seems like doing it the hard way. Surely your host supports PHP? If you know C, you can write a simple script in less time than you've spend debugging this thing.

Clayton said...

I've never written a CGI using PHP before. This ksh script is actually quite simple--what has me mystified is how to debug a ksh CGI. I suspect that writing using PHP would have the same problem--how do you see how far it gets before failing?

J Greely said...

Ah, it is the sed, but the script isn't exiting early. If sed isn't in the path, PARMS is set to an empty string, and then "for PARM in PARMS" has nothing to do. It skips to the "done" line and exits.

-j