Lessons by Jon

Error Handling CGI

This lesson will teach you how to create a CGI application that returns information even if an error occurs. In previous scripts, if an error occured the system would beep on the server, but the user gets only a long (long) wait followed by an uninformative error message. With this system, a useful error message is returned that informs the user of what kind of error occured and what the offending application was. This information can then be mailed back to the Webmaster. It also ensures that the server isn't tied up by a faulty script.

Script3.txt - An Error Handling CGI

Here is the entire script for this lesson. The comments have been removed so you see only the lines that actually get compiled. The full script, including comments and special characters, is in the archive with the name "Script3.txt".
property crlf : (ASCII character 13) & (ASCII character 10)
property http_10_header : "HTTP/1.0 200 OK" & crlf & "Server: MacHTTP" & crlf & Ā
	"MIME-Version: 1.0" & crlf & "Content-type: text/html" & crlf & crlf
property idletime : 300
property datestamp : 0

set datestamp to current date

on «event WWW½sdoc» path_args ¬
   given «class kfor»:http_search_args, ¬
      «class post»:post_args, «class meth»:method, ¬
      «class addr»:client_address, «class user»:username, ¬
      «class pass»:password, «class frmu»:from_user, ¬
      «class svnm»:server_name, «class svpt»:server_port, ¬
      «class scnm»:script_name, «class ctyp»:content_type
	
   set datestamp to current date
	
   try
		
   set return_page to http_10_header ¬
      & "<HTML><HEAD><TITLE>Unprocessed Results</TITLE></HEAD>" ¬
      & "<BODY><H1>Unprocessed Results</H1>" & return ¬
      & "<H4>http_search_args</H4>" & return & http_search_args
   set return_page to return_page & return ¬
      & "<H4>post_args</H4>" & return & post_args & return ¬
      & "<H4>method</H4>" & return & method & return ¬
      & "<H4>client_address</H4>" & return & client_address & return
   set return_page to return_page & return ¬
      & "<H4>from_user</H4>" & return & from_user & return ¬
      & "<H4>server_name</H4>" & return & server_name & return ¬
      & "<H4>server_port</H4>" & return & server_port & return
   set return_page to return_page & return ¬
      & "<H4>script_name</H4>" & return & script_name & return ¬
      & "<H4>content_type</H4>" & return & content_type & return ¬
      & "<H4>username</H4>" & return & username & return ¬
      & "<H4>password</H4>" & return
   set return_page to return_page ¬
      & "<I>Results generated at: " & (current date) ¬
      & "</I>" & "</BODY></HTML>"
   return return_page
		
   on error errMsg number errNum from suspect
      set return_page to http_10_header ¬
         & "<HTML><HEAD><TITLE>Error Page</TITLE></HEAD>" ¬
         & "<BODY><H1>Error Encountered!</H1>" & return ¬
         & "An error was encountered while trying to run this script." & return
      set return_page to return_page ¬
         & "<H3>Error Message</H3>" & return & errMsg & return ¬
         & "<H3>Error Number</H3>" & return & errNum & return ¬
         & "<H3>Suspected Target</H3>" & return & suspect & return ¬
         & "</BODY></HTML>"
      return return_page
   end try
end «event WWW½sdoc»

on idle
   if (current date) > (datestamp + idletime) then
      quit
   end if
   return 5
end idle

on quit
   continue quit
end quit

Step By Step

There are only two additions to this script. Let's take a look at them.
   try
This line, added at the start of the AppleEvent handler, tells AppleScript that you have provided an error handler (see below) in the event of an error. The usual "try" statement looks like the following:
   try
      [some statements to try to do without error]
   on error
      [statements to do if an error occurs]
   end try
The "on error" handler is part of the try statement. Therefore, the "end try" line ends the whole statement, including the error handler.
   on error errMsg number errNum
      set return_page to http_10_header ¬
         & "<HTML><HEAD><TITLE>Error Page</TITLE></HEAD>" ¬
         & "<BODY><H1>Error Encountered!</H1>" & return ¬
         & "An error was encountered while trying to run this script." & return
      set return_page to return_page ¬
         & "<H3>Error Message</H3>" & return & errMsg & return ¬
         & "<H3>Error Number</H3>" & return & errNum & return ¬
         & "</BODY></HTML>"
      return return_page
   end try
This is the error handling code. If an error occurs after the try statement, this handler is run. It is passed a number of variables. Here we are using just the two standard parameters:
errMsg
This contains the message sent by whatever generated the error (the System or AppleScript).
errNum
This contains the number of the error. Most System and AppleScript errors are negative numbers.
There are other parameters that can be used, such as suspect, which lists the offending object, and partial_results, which lists the information processed so far. These can be very useful, but are more difficult to use. Consult your AppleScript book about these (actually, my books say very little about them). It is possible for you to call the error handler on your own and pass in your own error message and number. In fact, this is recommended when you are debugging AppleScript code, as quite a bit can go wrong without generating a serious error.

As you can see in the code above, nothing is really new in this handler. All it does is create an HTML page to return that contains the error information. By passing back an HTML page, the user gets two benefits:

  1. The user gets some idea of what happened and can make a decision based on that of whether to try again or not.
  2. The CGI finishes processing instead of hanging until a timeout occurs. This means the user is freed up much sooner.
These are both "Very Good Things" for everyone involved. Your MacHTTP server will thank you. Your user will thank you. Your service provider may even thank you, but that's not likely.

Wrap It Up

Again, this code should be easy to paste into any of your existing scripts that work with MacHTTP. There are a couple of points to make, though, now that you know that there can actually be errors in AppleScript:
  1. This code is still not 100% effective against errors. If AppleScript (or MacHTTP) crash then you are still stuck, as there will be nothing available with which to return the error information.
  2. Not all error messages are very informative, and the error codes are even less so. You may want to write your own error messages to pass in some instances.
  3. This code returns error information to the user. This does not help you unless you are the user (or the user writes back to you). You may want to have errors logged to a file as well.

Jon Wiederspan
Last Edited: November 26, 1994