Using HyperCard as a CGI application

Some tips and tricks

About CGI

CGI (Common Gateway Interface) is a standard for the communication of Web servers with other programs, allowing the output of dynamic information. These programs, usually labelled with the suffixes .cgi or .acgi, process data received from the client via the server (e.g., they enter data into a database which have been submitted as a form entry) and/or reply in response to information provided by the client (either by constructing and sending a complete page, or by sending a http address (URL redirection) which the client then requests; the client information is not restricted to user input, you can determine the client software and return a page optimized for the respective client).

Many complete CGI applications are available for different purposes, most of them as Freeware. If none of those can perform the tasks you need, it is up to you to write your own CGI application. If you are a "real" programmer, Perl or C/C++ definitely are the way to go. Then there are AppleScript, much easier to program in (especially when you start with Jon Wiederspan's wonderful tutorial) and Frontier, but their applications are far slower than those compiled from C.

StarNine (makers of WebStar) provides a list of tutorials and examples about producing CGI applications in any of those languages.

And finally there is HyperCard. It is definitely the easiest way for a non-programmer to start with, and while it is far slower than a C-based CGI application, it does not compare unfavourably with AppleScript (to say it cautiously) if you optimize the setup. And if you want your CGI application to link a simple database to the Web, you are much better off using HyperCard's own database abilities (including its fairly fast "find" command) than to program your own database tools. Many tasks can be accelerated enormously when you use an external command (XCMD/XFCN) for the time critical step, and there are loads and loads of these available (it would be unfair of me not to note that AppleScript and Frontier also make use of similar externals).

I know of two ways of communication between WebSTAR/MacHTTP and Hypercard: directly via an Apple event, or indirectly via an AppleScript CGI application which is called by WebSTAR and then uses Apple events to communicate with HyperCard. The only reason to use the indirect strategy I can think of is that something must be done which HyperCard can't do, but AppleScript can (and probably an Xternal exists somewhere which allows to do it in HyperCard), otherwise, the longer chain of programs will run slower and will be more prone to crashes and timeouts. In a word: I use and will describe only the direct communication (and I have no experience with server software other than WebSTAR/MacHTTP, so I have no idea whether the following is true for other Mac Web servers).

To write a CGI application in any language, you must know what kind of data you will have to deal with. Jon Wiederspan's tutorial contains so much basic information about how CGI applications work (and is easy and fun to read) that you should check it out even if you intend to script your Web site using Hypertalk only. He describes in detail what kind of data (arguments) are transmitted and in which format, so there is no need for me to repeat it here.

Overview: What Hypercard has to do as a CGI application

WebSTAR will send its SEARCH or POST data (you had a look at the Wiederspan pages?!) packed up in an Apple event. In HyperCard this triggers the appleEvent system message which you will have to deal with in an "on appleEvent...end appleEvent" handler. The Apple event can be identified by its parameters class, id, and sender which can (and should) be used to make sure that the incoming event really comes from WebSTAR (don't forget to let other Apple events pass). The enclosed data of the Apple event are extracted with the command "request ae data" (returns the path args) respectively "request ae data with keyword" (keyword "meth" returns the method: POST or GET, "post" returns the post args, "kfor" returns the search args, etc.). Your script now has to parse (extract the data and put them into the correct containers) and decode (convert + to space, and convert the coded characters from %##) these data, then you can process them ad libitum (e.g., enter them into your database or use them to search your database). Finally, produce an answer (either a complete HTML document or a redirect to an existing document) and send it back to WebSTAR with "reply yourAnswer". Because the returned data are passed to the client without further processing by the server, you have to provide them with a header (WebSTAR does that for the http documents it reads from disk before it sends them to the client) which describes whether a document (header contains "200 OK") or an address (header contains "302 FOUND") is returned. Omitting the "200 OK" header spares time and usually gives no problems, just like crossing a street when the traffic lights are red...

The basic handler step by step

The handler has to
grab the Apple event
on appleEvent class, eventID, sender (...end appleEvent)
verify it is a sdoc event from the server
if class & eventID is "WWW‡sdoc" then (...else_pass appleEvent_end if; the letter after WWW is a capital Omega, Option-z)
extract the relevant data
request appleEvent data -- get (and evaluate) the direct parameter (path args)
request appleEvent data with keyword "post" -- post args (...put it into postArgs)
request appleEvent data with keyword "kfor" -- search args (...put it into searchArgs)
the post args will have to be parsed and decoded
set the itemDelimiter to "&"
repeat with Element = 1 to the number of items of postArgs
if char 1 of item Element of postArgs is "I" then
put URLDecoder(item Element of postArgs) into Input
put empty into char 1 of Input -- remove inputName=; I use 1 letter names
put empty into char 1 of Input
... repeat for all possible elements
while the search args have only to be decoded
put URLDecoder(searchArgs) into searchFor
do whatever you want to
(search with them, add them to a database, control other programs, use them to direct your video camera...)
produce either a complete http document or redirect to another http file
put Header & Sheet & Footer into answerDoc -- here is some work to do: it is your business to mingle the data you want to display with the appropriate HTTP tags
send it back to the server
reply answerDoc

Basic HyperCard setup, adapted from Chuck Shotton's CGI Demo Stack

Put an alias to HyperCard (version at least 2.1) into the same folder as WebSTAR respectively MacHTTP, and name it "HyperCard.acgi"; put the HyperCard stack with the "on appleEvent" handler ("CGI-Stack") into the same folder. Start HyperCard by dragging the CGI-Stack on the HyperCard.acgi alias. A form which calls the CGI-Stack should contain
<form method=POST action="HyperCard.acgi$PathArgs">
the form input is put into the post args; a direct link to the CGI-Stack looks like

Optimizing the setup

This basic setup has several weak spots. If you forget the unusual opening procedure or if HyperCard quits for some reason, the call from WebSTAR will fail and produce an error. The CGI-Stack also will not be opened automatically on startup. The CGI-Stack must be the frontmost HyperCard stack, otherwise the Apple event is sent to the wrong stack, resulting in an error. And while any other script is running in HyperCard, or while you are editing a script, the execution of the CGI-Stack is blocked.
I found some tricks and modifications to avoid the problems above, and to speed up HyperCard as a CGI application. But still I sometimes find errors like
Error -1700: GetAttrPtr retID (Reply Data could not be coerced to requested type (char))
Error handling HighLevelEvent -1700

Error -1712: Sending CGI sdoc Event (AppleEvent timed out)
Error executing CGI application

in my WebSTAR log window without having an idea of what went wrong. I live with that, and you will probably have to, too, if you decide to use HyperCard as your CGI application (I am sure that programs written in other languages have some bugs, too).

Enough of gloomy warnings, now for my improvements:

I wanted the Hypercard CGI application

  1. to be fast, or at least not to take forever
  2. to work without manual help: if not running when called from the server, it should start up correctly all by itself
  3. to serve several different databases located on different stacks
  4. to allow me to use HyperCard without blocking the HyperCard.acgi
  5. to handle several requests at the same time.
Only 5. is something I could do nothing about. However, WebSTAR (or the Apple event manager) seems to handle the problem as well as possible. I suppose/hope that it queues the requests and sends each one off only when the previous has been finished.

My use of HyperCard as a CGI application

What I set up with HyperCard is the following (have a look to see how well or how poorly HyperCard behaves as a CGI application. Caution: the server is my desktop Mac (a Centris 650), so a slow response from 8am to 8pm MEZ (2am to 2pm Eastern Time) is probably due to my foreground activity and System 7's lack of preemptive multitasking, slow response at other times can only be blamed on HyperCard and my programming):

Other sites using HyperCard as CGI application/HyperCard CGI Examples

If you use HyperCard to serve the Web, tell me and I will provide a link here:

The best way to learn programming is to look at good code. If you are serious about setting up HyperCard for CGI handling, you should definitely download and investigate the following stacks:

Some HyperCard sample code used in the example above

on openStack
  global OKHeader
  put numtochar(13) & numtochar(10) into crlf
  put  "HTTP/1.0 200 OK" & crlf & "Server: WebSTAR/1.0 ID/ACGI" ¬
  & crlf & "MIME-Version: 1.0" & crlf ¬
  & "Content-type: text/html" & crlf & crlf & "<HTML><HEAD><TITLE>" into OKHeader
  go "Stack1.acgi" in new window
  go "Stack2.acgi" in new window
  -- call all stacks addressed by CGI requests
  go home
  pass openStack 
end openStack

function URLDecoder myData
  -- Calls the Xternals MtReplace and MtDecode
  if myData = empty then return empty
  put MtReplace(myData,"+"," ") into myData
  put MtDecode(myData) into myData
  put MtReplace(myData,(return&lineFeed),return) into myData
  put MtReplace(myData,lineFeed,return) into myData
  return myData 
end URLDecoder


Please, mail me suggestions for improvement, corrections, info about interesting links.

This Ultimate HyperCard Webring site owned by
Kai-Uwe Fröhlich.

[ Previous 5 Sites | Previous | Next | Next 5 Sites | Random Site | List Sites ]

[To our home page][Our lab and projects][To the software archive]

Last edited: October 23, 2001 by KaiFr