CGIs in 4D
Volume Number: 12
Issue Number: 5
Column Tag: Internet Development
Writing CGI Applications With 4D 
Beam your web pages into the 4th DIMENSION
By Mike Cohen, Casper, WY
Note: Source code files accompanying article are located on MacTech CD-ROM orsource code disks.
In previous articles [in, for example, MacTech Magazine 11.7, 11.8, 11.9, 11.12,
and 12.1 - man], you were shown how WebSTAR or MacHTTP can interface with CGI
applications. In this article, I’ll demonstrate how to use this same CGI interface to
have your Web server communicate with 4th DIMENSION, using System 7 Pack from
ISIS International.
About System 7 Pack
System 7 Pack, from ISIS International, is a 4th DIMENSION external package
that lets you send and receive Apple events in your databases. With System 7 Pack, 4D
applications can control other applications, such as Microsoft Excel or QuarkXPress,
and can be accessed by other local or remote applications. Once it possesses an Apple
event handler, your 4D database can act as a CGI application for WebSTAR or MacHTTP.
CGI Applications
If you’ve read previous articles in this series, you probably know the basics of
CGI applications, but I’ll review them here. When a Web client requests a file,
WebSTAR (or MacHTTP) uses the filename’s suffix to determine how the file should be
handled. In most cases, the file will simply be returned to the client. However, for a
file type of .cgi or .acgi, the application will be launched, if it isn’t already
running, and an Apple event will be sent to it with information passed from the client.
After processing that event, the CGI application returns HTML text to WebSTAR.
Using 4D to Write CGI Applications
The first thing you need to do is to put a copy or alias of either 4D itself or a compiled
4D database merged with Runtime into your WebSTAR folder and give it a name ending
in .cgi or .acgi. If you use the suffix .acgi, your application will be called
asynchronously: WebSTAR won’t wait for an Apple event to complete before sending
additional requests. Such an application must be prepared to have multiple outstanding
requests, and may need to use semaphores to prevent simultaneous access to global
variables or data files.
Install an Apple Event Handler
The first thing your CGI application must do when 4D starts up is to install a
handler for the Apple event WebSTAR sends you. The following line of code in our
startup procedure will take care of that:
$Err := HandleAEVT ("WWWΩ";"sdoc";"CGI Handler")
This System 7 Pack function tells 4D to call the procedure named CGI Handler
whenever it receives an Apple event of class 'WWWΩ' and ID 'sdoc', which is the event
that WebSTAR sends to CGI applications. The full startup procedure (see Listing 1)
also initializes several global variables that the rest of the application will use.
Since many of our global variables will be used by the Apple event handlers,
which run in a separate process, we use interprocess variables identified by a name
beginning with the diamond character (◊). The most important variables,
◊ae_headRslt, ◊ae_TextHdr, and ◊ae_PictHdr, contain standard HTTP headers that
must be returned along with any data we send back to WebSTAR.
When 4D receives an Apple event, it automatically starts a process called Apple Event Manager, in which all event handler procedures run. With some versions of 4D (most notably 4D Server 1.0.5 and any non-server version earlier than 3.0.5),
the first Apple event received is discarded or takes a long time to handle. To avoid
these problems, we have our startup procedure send a dummy Apple event to itself.
Listing 1: STARTUP
` let’s define a few global variables here
◊crlf:=Char(13)+Char(10)
◊q:=Char(34) ` double quote
◊nl:="
" ` html line break
` standard HTML header
◊ae_headRslt:=
"HTTP/1.0 200 OK"+◊crlf+"Server: WebSTAR"+◊crlf
◊ae_headRslt:=
◊ae_headRslt+"MIME-Version: 1.0"+◊crlf
◊ae_TextHdr:=
◊ae_headRslt+"Content-type: text/html"+◊crlf+◊crlf
◊ae_PictHdr:=
◊ae_headRslt+"Content-type:image/gif"+◊crlf+◊crlf
` install our Apple event handlers
$Err:= HandleAEVT ("WWWΩ";"sdoc";"CGI Handler")
` some versions of 4D lose the first Apple event or take unusually long
` to process it, so we’ll send ourselves a bogus event to start the
` AppleEvent Manager process which will handle all incoming events
$Err:= MakeAddress("4D05";$myself)
$Err:= SendAEVT($myself;"XXXX";"XXXX";"-")
$Err:= DisposeDesc($myself)
Hand Off the Apple Event
Next, you need to write a procedure that will be executed in response to the Apple
event. It’s important for this procedure to run as quickly as possible, since each
incoming Apple event is queued and dispatched to this single process. A good approach
is to simply call AESuspend (a function introduced in System 7 Pack 3.8.3) and pass
the event returned from it to another process. For the sake of simplicity, I merely
start a new process here, but for better performance, you should start the process
when the application starts up, suspend it, and wake it up each time an event comes in.
Listing 2: CGI Handler
$Err := AESuspend (◊theEvent;◊theReply)
New process("CGI Script";32000;"CGI Script Handler")
The function AESuspend makes a copy of the incoming event and reply, and
informs the AppleEvent Manager that it shouldn’t (as it normally does) automatically
send the reply when the procedure finishes. Note that you must use interprocess
variables (indicated by a variable name that begins with ◊), since the event will later
be handled in a separate process.
The New Process command then starts up a separate process called CGI Script Handler that will run the procedure CGI Script to do the actual event handling. Once
this procedure finishes, 4D will then be free to receive additional Apple events while
the CGI Script Handler process finishes handling the event.
Process the Apple Event
Finally, the function CGI Script (see Listing 3), which will be run in a
separate process, finishes handling the request and sends the reply to WebSTAR. The
first thing we do is to save the Apple event and reply in process variables, since a new
Apple event coming in at this time would modify the interprocess variables. Next, we
initialize several variables we use to extract data from the incoming Apple event. We
then extract the path argument, sent as the direct object using the System 7 Pack
function GetTextParam. The additional arguments sent by WebSTAR, including the
method, search, and post arguments, are also extracted by calling GetTextParam.
Next, we inspect the various arguments to decide how to handle the request. In this
procedure, we handle all POST requests by adding a record to the database.When we
receive a GET request, if no PATH argument is given, we simply return a list of all
records containing the search string. If the PATH argument begins with rec, we
assume the search argument is a record number and return the full record. If the
PATH argument begins with pict, we use the search argument as a record number and
return a picture field from that record as a GIF image.
Listing 3: CGI Script
evt:=◊theEvent
rep:=◊theReply
` assume the reply format will be TEXT
$hdr:=◊ae_TextHdr
C_TEXT(http_meth) `the method - either “GET” or “POST”
C_TEXT(http_srcha) `the search arguments
C_TEXT(http_post) `the post argument
C_TEXT(http_path) `the path argument
C_TEXT(use_address) `the user issuing this request
$err:= GetTextParam (evt;"----";http_path)
`extracts the “direct object” parameter of the
`Apple event which caused this procedure to be launched
`the “direct” object of an Apple event passed from WebSTAR is the
`“path” argument
`get other pieces from this apple event
$err:= GetTextParam (evt;"meth";http_meth)
$err:= GetTextParam (evt;"kfor";http_srcha)
$err:= GetTextParam (evt;"post";http_post)
$err:= GetTextParam (evt;"addr";use_email)
Case of
: (http_meth="post") ` handle a post request
$ostr:=DoPost (http_post)
: ((http_srcha="") & (http_path="")) ` all blank
$ostr:="No search terms were given."+
"What do I search for?"+◊crlf
: http_path="rec@") ` handle a record # detail request
$ostr:=GetRecord (http_srcha)
: (http_path="pict@") ` handle an image request
$ostr:=GetImage (http_srcha)
$hdr:=◊ae_PictHdr
: (http_path="") `it’s a simple search
$ostr:=DoSearch (http_srcha)
Else
$ostr:="ERROR- The path '"+http_path+
"' is not supported."+◊crlf
End case
` now, send the reply back to WebSTAR for this Apple event
$err:= PutTextParam (rep;"----";$hdr+$ostr)
` finish processing this event and send the reply
$err:= AEResume (evt;rep)
Let’s take a closer look at this procedure.
The first two lines copy the event and reply from interprocess variables into
process variables, both for convenience and to avoid trouble if they get changed by
another process. If you expect to have many incoming events, you should probably use
an array into which the Apple event handler pushes values, and use this function to pop
them out.
We then use GetTextParam to extract the parameters that WebSTAR passed to the
CGI script. The direct object is the path value (the text that follows the $ in your
HTML request). The other important values are the method (http_meth, or the
'meth' descriptor in the Apple event), which is either GET or POST, the post argument