TweetFollow Us on Twitter

CGIs in C
Volume Number:11
Issue Number:9
Column Tag:Internet Development

Writing CGI Applications in C

Inject Some Adrenaline into your World Wide Web
Server Applications.

By John O’Fallon, john@maxum.com

Note: Source code files accompanying article are located on MacTech CD-ROM or source code disks.

For the last two months this column has been teaching you how to write CGI applications for WebSTAR using AppleScript. AppleScript is a wonderful environment for tying existing Apple event-aware applications (database engines, for example) to WebSTAR. It also provides an easy way to get your feet wet with CGI applications. Inevitably, though, there will come a time when you need a high-throughput, high-reliability CGI for your WebSTAR server. For that, we turn our attention to the C language.

Writing CGIs in C will be very comfortable for most experienced Macintosh programmers, and will provide all of the performance and reliability the most demanding servers need. In addition, when writing CGIs, you can get these benefits without the headaches that are often associated with C. For example, developing in C normally means spending a lot of time on the user interface. But CGI applications don’t typically need any significant interface, so all you need to worry about is the actual job that you are trying to accomplish.

If you aren’t already somewhat familiar with programming in C, you should stop right here and spend some quality time with a C programming primer. You don’t necessarily need to be a C ace to write a good CGI, but familiarity with the language, the basic libraries and the Macintosh ToolBox are essential. I will also assume that you already have some experience with WebSTAR and with the topic of CGI applications in general (if not, see the July and August issues for “CGI Applications in AppleScript”) as well as a basic knowledge of HTML. Now, on to the topic at hand.

Apple Events

CGIs exist for Apple events. You will be building an application whose sole purpose in life is to receive Apple events, look at what they’re asking for, do some processing, and send back some reasonable responses. So, to begin, we’ll start with an overview of just how Apple events are used to send and receive information. Please note that I haven’t read the Inside Macintosh chapter on Apple events in almost a year, so for the real deal, in all its glorious detail, look at Inside Mac, Volume VI, Chapter 6. [or Inside Macintosh: Interapplication Communication, Chapter 3 - Assoc. Ed. jaw]

Set It Up

All a CGI really needs to do is respond to Apple events that are originated by WebSTAR. Luckily for us, responding to Apple events turns out to be quite a bit easier than sending them.

Responding to Apple events starts by installing a series of event handlers. An event handler is a procedure that will be called to process a given event, based on the event class and event ID. Every event is defined by its class (an attribute representing a group of events) and its ID (within the group, the specific event that needs to occur).

Your CGI will install five (or possibly more) Apple event handlers. The first four events to be handled are the “core” events that all good Apple event aware applications support. These events are: open the application, open a document, print a document, and quit the application. The fifth event is the interesting one...

WebSTAR defines a single event class (WWW ) and event ID (sdoc) which is used to pass requests from WebSTAR to your application. Your CGI will install a handler to process events with these attributes. These attributes, and the procedure to be called when an event with that class and ID are received is just about all you need to know to install your event handler.

There is one other missing piece. In order for your CGI to run in native mode on PowerMacs, you’ll need to reference your Apple event handling procedure as a Universal Procedure Pointer. This is easy enough, and is illustrated in the procedure below, which installs event handlers for all five of our events.

InstallAllEvents
void InstallAllEvents ()
{
OSErr MyErr;
AEEventHandlerUPP MyUPP;

MyUPP = NewAEEventHandlerProc(HandOpenApp);
MyErr = AEInstallEventHandler
(kCoreEventClass,kAEOpenApplication,MyUPP,0,FALSE);
MyUPP = NewAEEventHandlerProc(HandOpenDoc);
MyErr = AEInstallEventHandler (kCoreEventClass,kAEOpenDocuments,MyUPP,0,FALSE);
MyUPP = NewAEEventHandlerProc(HandPrintDoc);
MyErr = AEInstallEventHandler (kCoreEventClass,kAEPrintDocuments,MyUPP,0,FALSE);
MyUPP = NewAEEventHandlerProc(HandQuitApp);
MyErr = AEInstallEventHandler (kCoreEventClass,kAEQuitApplication,MyUPP,0,FALSE);
MyUPP = NewAEEventHandlerProc(HandClientRequest);
MyErr = AEInstallEventHandler (WWW '','sdoc',MyUPP,0,FALSE);
if (MyErr != noErr) {
 SysBeep (2);
    // Well behaved apps would do more than beep!
 }
}

The parameter passed to NewAEEventHandlerProc is simply the name of the C procedure that will be called when an Apple event is received for the defined class and ID.

Watch For It

Now that the Apple Event Manager knows about your event handler, and knows the Apple event class and ID it can handle, you need to start watching for events. This is done in your main event loop, by adding support for high-level events.

In addition to mouse clicks, key presses, etc., your CGI application will receive high level events from the system, via WaitNextEvent. When an Apple event is sent to your application, WaitNextEvent will respond with the kHighLevelEvent constant in the ‘what’ field of the EventRecord. When a high level event is received in your main event loop, it is up to your application to dispatch it to the Apple Event Manager, which will in turn call your event handler. The code is simple, and looks like this:

while (QuitApp==FALSE) {
// Go through the event loop as long as we aren’t supposed to quit
 WaitNextEvent (everyEvent, &Action, 0L, 0L);
    // Ask the OS for an event
 switch (Action.what) {
 case mouseDown: // They clicked the mouse...
 HandleMouseDown (Action.where);
 break;
 case keyDown:   // They pressed a key...
 HandleKeyDown ((int)Action.message,(int)Action.modifiers);
 break;
 case kHighLevelEvent:
    // We have an Apple event... so let the OS...
    // dispatch it (see Inside Mac).
 MyErr = AEProcessAppleEvent (&Action);
 if (MyErr != noErr) {
 SysBeep (2);
    // Well behaved apps do more than beep!
 }
 break;
 }
 }

Handle It

The Apple Event Manager will take the event and look for an installed handler that accepts events of the given class and ID. When it finds an appropriate handler, it will execute it. In the example above, the procedure name was HandClientRequest, so this is the procedure that will be executed.

WebSTAR is very generous about the information that it supplies to your CGI, so your first task when you receive an event is to pull out the variables that are passed to you. There are quite a few variables, and StarNine adds new ones fairly regularly, so there is no way to cover them all here. Check your WebSTAR technical documentation for a complete description of the parameters. The documentation will tell you what information the parameter holds, and what its name is. The name, like the Apple event class and ID, is a 4 byte constant.

To pull a parameter out of an Apple event, you use the AEGetParamPtr routine. You specify the name of the parameter, and AEGetParamPtr will copy the data into a buffer and tell you how long it is. I normally use the length variable to cap the buffer and make it into a C string. Here are a few examples:

    // '----' - direct parameter
MyErr=AEGetParamPtr (TheRequest,'----',typeChar,&ReqType,(Ptr)PostArg_Direct,1023,
 &ReqSize);
PostArg_Direct[ReqSize] = '\0';
    // 'addr' - client address
MyErr=AEGetParamPtr (TheRequest,'addr',typeChar,&ReqType,(Ptr)PostArg_Address,255,
 &ReqSize);
PostArg_Address[ReqSize] = '\0';
    // 'Agnt' - user agent
MyErr=AEGetParamPtr (TheRequest,'Agnt',typeChar,&ReqType,(Ptr)PostArg_Client,255,
 &ReqSize);
PostArg_Client[ReqSize] = '\0';
    // 'post' - post arguments
MyErr=AEGetParamPtr (TheRequest,'post',typeChar,&ReqType,(Ptr)PostArg_Post,
 8191,&ReqSize);
PostArg_Post[ReqSize] = '\0';

Let’s take a closer look at each of these requests.

• The first parameter, TheRequest, is a pointer to the Apple event sent from WebSTAR. This tells the Apple Event Manager what event we’re processing (and so, where to pull the parameter from).

• The second parameter is the four byte name of the parameter, as defined by WebSTAR.

• The third parameter is the parameter data type. The Apple Event Manager supports an extensive list of data types, with a complete set of coercion routines. WebSTAR, however, is nice and consistent, always sending parameters as good old typeChar.

• The fourth parameter, ReqType, allows the Apple Event Manager to tell the CGI what data type the parameter is, but I ignore this field, since I know that the Apple event is coming from WebSTAR and that it’s always a typeChar.

• The fifth parameter is a buffer to receive the data, followed by the maximum length of data to be copied into the buffer. Make sure that your buffer is big enough to hold as much data as you say you can hold. Also, we’ll be adding a null to the end of the string, so make sure you have a byte to spare for that.

• The last parameter is a ‘Size’ variable to receive the length that was actually copied into our buffer.

Choosing sizes for your buffers is somewhat arbitrary, and is done on a field by field basis. POST arguments, for example, can be up to 24k in length. Often, it makes sense to accept this much data, but in many cases, where you know the HTML form will be asking only for a few short fields, you can get away with substantially less. Also, in this example, we accept up to 255 characters for both the client address and for the user agent (the name of the browser). Both of these are probably more than long enough; I could most likely get away with 64 bytes for each, or less.

Finish It

Let’s take a second to recap... We detected our Apple event and dispatched it to the Apple Event Manager. The Apple Event Manager passed it off to our handling procedure, which read in the parameters it needed from WebSTAR. Next, the CGI went off and did its thing, and now it finally is time to respond to WebSTAR.

We’ll talk about processing the request and how to build the response string in a few minutes, but first, let’s finish with the Apple events. The last bit of Apple event processing we need to do is send the response. This is done quite easily with the AEPutParamPtr routine.

The nice thing about responding to Apple events is that the Apple Event Manager knows you are going to respond, so it builds the response event for you, before your handler even gets called. Once your handler finishes, it sends the event back to WebSTAR too. All this leaves for you to do is to copy your results into the event before you finish. Here is how that looks:

MyErr=AEPutParamPtr (TheReply,keyDirectObject,typeChar,
    (Ptr)PostArg_Response,ReqSize);

TheReply is the Apple event that was created for us by the Apple Event Manager for sending our response. keyDirectObject is a constant which represents what can be thought of as the main parameter of the Apple event (which is the response text, of course). typeChar simply tells the Apple Event Manager that the data is a string. PostArg_Response is a pointer to our response text, and ReqSize is the length, in bytes, of our response.

Whew! We’ve done all the work we need to do in order to communicate with WebSTAR. It’s quite a process, but the Apple event code also happens to be pretty static; the code presented here can be used almost verbatim in just about any CGI you would care to create, so now that we’ve done the work of communicating with WebSTAR, we can move on to actually doing our job.

Parsing the Post

Many CGIs function based on user-input, which comes from an HTML form. Forms are easy to build, and the browser handles all the editing controls for you, so your CGI won’t know the user is filling out a form until they are done and press a “submit” button. The upside to this is that all you have to do is process the data, forgetting almost entirely about the user interface. The downside is that there is a lack of control during the editing process.

In any event (well, actually in an sdoc event), when the user submits the form, it’ll come to you as an ASCII string. The string will list the field names as they appeared on the HTML form with the associated user-entered data. The field names are separated from the field data by an equal sign (=) and then ampersands (&) are used to separate the various field=data pairs. At the same time, any special characters in the field data (such as & and =) are encoded with a percent sign (%) and the character’s ASCII code in hex.

Maybe an example will be clearer. For a simple form that asked the user for their name, job title, and e-mail address, you might get the following post data:

UserName=John&JobTitle=Software%20Developer&EMail=john@maxum.com&unnamed-submit-input=Submit%20Form

Notice the instances of %20. These are encoded spaces (a space has an ASCII value of 0x20). Other characters like colons, slashes, etc. would give us similar encoded values. When your CGI receives this text string, the first thing it will need to do is decode those ASCII values. This is a fairly easy task and looks like this:

Replace Special Chars

/*****************************************************************/
/* REPLACESPECIALCHARS replaces instances of percent signs (%)   */
/* followed by an ASCII char value with the actual character.            */
/****************************************************************/

void ReplaceSpecialChars (char *TheText)
{
int i;
int j;
int AsciiChar;

i = 0;
j = 0;
while (TheText[i] != '\0') {// Search the entire text block
 switch (TheText[i]) {
 case '%':// if the char is a percent sign, look at the next char
 if ((TheText[i+1] >= 'A') && (TheText[i+1] <= 'F')) {
 AsciiChar = TheText[i+1] - 'A' + 10; 
 // convert A thru F to 10 thru 15
 }
 else {
 AsciiChar = TheText[i+1] - '0'; // Convert all others to 0 to 9
 }
 AsciiChar = AsciiChar * 16;
    // That was the high order of a hex number, so mult by 16 to
    // find the decimal value. Now do the low order char...
 if ((TheText[i+2] >= 'A') && (TheText[i+2] <= 'F')) {
 AsciiChar += (TheText[i+2] - 'A' + 10);
    // Convert A thru F to 10 thru 15 (and add it to the high order value)
 }
 else {
 AsciiChar += (TheText[i+2] - '0');
    // Convert all others to 0 to 9 (and add it to the high order value)
 }
 if ((AsciiChar >= 0) && (AsciiChar < 256)) {
    // if we got a valid value, replace the ASCII char
 if (AsciiChar == 10) {
 j--;
 }
 else {
 TheText[j] = AsciiChar;  // Copy the char into the string
 }
 i += 2;
    // Now that we have converted 'em, skip the extra characters
 }
 else {
 TheText[j] = TheText[i];
    // False alarm, nothing to convert, just copy the char (shouldn't happen)
 }
 break;
 case '+':
 TheText[j] = ' '; // Spaces are coded as plus signs
 break;
 case '&':
 TheText[j] = DELIM_CHAR; 
    // Replace the default delimiter with something more uncommon
 break;
 case 10:
 j--;   // Strip out linefeeds, Macs don't use them
 break;
 default:
 TheText[j] = TheText[i]; // A normal character, just copy it
 break;
 } 
 i++;
 j++;
 }
TheText[j] = '\0';     // make sure the string is capped
}

While the routine decodes the ASCII values, it also replaces the ampersands that delimit the fields. I did this because an ampersand is actually a fairly common character for people to use, and will confuse things mightily if it appears in the text and is used as our delimiter. So DELIM_CHAR is simply defined as something more obscure. The omega ( ) works well - it is rare but can be typed easily and is quickly recognizable.

You will also notice that the routine converts both plus signs (+) and the %20 ASCII encodings into spaces. This is because some browsers (notably NetScape and Mosaic) encode spaces as plus signs, and we’d like to stay compatible with as many browsers as possible (not to mention the fact that most people use these two browsers).

For the last step, we need a way of extracting the text for any given field. All we need to do is scan through the text looking for the field name followed by an equal sign. When we find that, we simply copy the user entered data into a buffer. Here is a simple routine to do just that:

GetFieldData
/****************************************************************/
/* GETFIELDDATA searches PostArg_Post for the specified field   */
/* name and returns the text entered by the user.                           */
/*************** *************************************************/

int GetFieldData (char *PostString, char *FieldName, int MaxLength, char 
*TextBuff)
{
int i,StrLen,Found,Position;

StrLen = 0; // First, find out how long the field name is
while (FieldName[StrLen] != '\0') StrLen++;
Found = FALSE;   // Assume we haven't found anything
Position = 0;
while ((Found == FALSE) && (PostString[Position] != '\0')) {
    // look til we find something or we hit the end
 Found = TRUE;   // We can hope, can't we?
 for (i = 0 ; i < StrLen ; i++)  // if any character at all doesn't match
 if (PostString[Position+i] != FieldName[i]) {
 Found = FALSE;   // then no deal, and stop trying
 i = StrLen;
 }
 Position++;
 }
if (Found) {// OK... Great... We found our field
 Position += (i - 1);// Start looking for the delimitting '='
 while (PostString[Position] != '=') Position++;   
 Position++;// Skip over the '='
 i = 0; // Almost done, just copy the string
 while ((PostString[Position+i] != '\0') &&
 (PostString[Position+i] != DELIM_CHAR) && (i < MaxLength)) {
 TextBuff[i] = PostString[Position+i];
 // Copy the user entered text into the buffer
 i++;
 }
 TextBuff[i] = '\0'; // Cap the C string
 return (TRUE);
 }
else {
 TextBuff[0] = '\0'; // Return a NULL string
 return (FALSE);
 }
}

There are other ways of extracting this information from the POST string, but this is a handy routine that is easy to get started with.

The Equivalent of “Hello World!”

So, let’s write a CGI that will be the equivalent of the ever-popular “Hello World!”. We’ll create a simple HTML form with two input fields and a “submit” button. When the user clicks “submit”, our CGI will take the words in the two input fields, stick them together, and respond with some HTML text that shows the user what we did. We start with the HTML form...

<HTML>
<TITLE>Hello World! Test</TITLE>
<BODY>
<FORM METHOD=POST ACTION="/HelloWorld.cgi">
Enter a word in each of the fields below...

<P><B>Field 1:</B> <INPUT TYPE="text" NAME="Field1" SIZE="32" MAXLENGTH="32">

<P><B>Field 2:</B> <INPUT TYPE="text" NAME="Field2" SIZE="32" MAXLENGTH="32">

<P><INPUT TYPE=submit VALUE="Submit Form">
</FORM>
</BODY>
</HTML>

Last month, Jon Wiederspan went into some detail about how forms work, and they are very well documented in many places on the Web, so I won’t go into detail about what is going on here. There are, however, two important things to notice. First, the ACTION parameter of the FORM command is “/HelloWorld.cgi”. This is simply the file name of the CGI application we are going to write. The application name must end with either “.cgi” or “.acgi” to be recognized as a CGI application by WebSTAR. (Actually, you can reconfigure the file extension definitions within WebSTAR to recognize other extensions, but we won’t get into that here.)

The other thing to notice is the field definitions. They are both text fields and are named Field1 and Field2 (creative, eh?). The field names defined in the HTML file will be important when we go to parse the POST argument in the CGI.

Now for the CGI code. All of the code listed so far will be needed, as well as other standard Macintosh application stuff for initializing menus, windows, etc. The core of the program will be the HandleClientRequest routine, and will look like this:

HandClientRequest

pascal OSErr HandClientRequest (AppleEvent *TheRequest, 
 AppleEvent *TheReply, long Reference)
{
OSErr MyErr;
DescType ReqType;
Size ReqSize;
char Post[1024];
char Response[1024];
char Field1[64];
char Field2[64];

    // Get the post data
MyErr=AEGetParamPtr (TheRequest,'post', typeChar,&ReqType,
 (Ptr)Post, BUFFER_SIZE,&ReqSize);
PostArg_Post[ReqSize] = '\0'; // and cap it as a C string
 
ReplaceSpecialChars (Post); // Replace the special characters
GetFieldData (Post, "Field1", 64, Field1); // Get the user entered data
GetFieldData (Post, "Field2", 64, Field2); // out of the post string
sprintf (Response,
 "<HTML><TITLE>CGI RESPONSE</TITLE><BODY><H1>%s %s</H1></BODY></HTML>",
 Field1, Field2); // Build the HTML response string
ReqSize = strlen (Response);// Get the # of chars in the response string
MyErr=AEPutParamPtr (TheReply,keyDirectObject,
 typeChar,(Ptr)Response,ReqSize);

return (MyErr);
}

This example is a bit over-simplified, but works for our test. For one thing, in a real CGI, you would probably want to allocate more memory to both the post string and the response string.

The first thing that happens in our application is a high level event is received from the OS. Our main event loop passes it off to the Apple Event Manager, which calls this routine. When HandClientRequest gets the request, it pulls the POST argument out of the Apple event and then parses out the user entered data using GetFieldData. After that, all it has to do is put the user’s words into a simple HTML response and stick the resulting string into the reply Apple event. Piece of cake.

CGI vs. ACGI

We wrote “HelloWorld.cgi” as a CGI, but we might want to make it an ACGI (Asynchronous CGI). The difference here is simply in the filename of the finished application. This example program will run as either a CGI or an ACGI just fine; the difference is in what WebSTAR does when it sends the event to us.

If the application ends with “.cgi”, then WebSTAR creates the Apple event, sends it off to our application, and waits for a result. All server activity stops cold while the CGI does its thing. With an ACGI, WebSTAR sends the event and goes merrily on its way serving other connections. This sounds like a better solution, and often is, but not always.

For example, our “HelloWorld.cgi” should be left as a CGI. It is so fast that it won’t really cause a delay on the server, and making it an ACGI would just add overhead that we have no need to incur. So plain old CGIs can be safely used when the CGI is doing something very fast. ACGIs should always be used when processing might take a bit longer, so that other connections don’t get hung up waiting for the application to finish.

But if the application is running asynchronously, you ask, what happens when WebSTAR sends us a new event while we’re processing another? Simple. While our CGI is processing an event, the main event loop isn’t running, so Apple events aren’t being processed and will build up in a queue until we are ready to handle them. So even though WebSTAR is processing connections asynchronously, the CGI is processing them one at a time. This isn’t a problem unless the CGI is going to spend a large amount of its time sitting idle (say, waiting for results from a client/server database engine running on another machine). In this case, processing incoming requests synchronously can become a big problem.

Threading

We really have three classes of CGIs, and we use each depending on the situation at hand.

• When your CGI will be very fast, make it a CGI. “Very fast” means that it probably works strictly within memory and doesn’t have to wait for disk I/O or other slow processes.

• When your CGI is fast, but can take a second or two to run, use an ACGI. ACGIs can also safely be used when processing will take a long time to run but is fairly uncommon. If the CGI isn’t run very often, the requests will rarely pile up in the Apple event queue.

• When your CGI may take longer than a few seconds, and when it will be accessed frequently, you have little choice but to make it threaded or else it will become a processing bottleneck for the entire server.

Writing threaded applications simply means that the program uses the Thread Manager to execute multiple instances of parts of your program simultaneously. Without going into the details of the Thread Manager, here is how a CGI can use threads to perform its job for multiple simultaneous connections.

1) Receive the Apple event in the main event loop.

2) Suspend the Apple event

3) Spawn a thread and pass all connection information (post string, etc.) to the new thread.

4) The main event loop yields to any active thread.

5) The thread performs its task. At key intervals (usually when waiting for slow processes) the thread yields to other active threads (including the main event loop).

6) When the thread has built its response, it resumes the Apple event and replies.

7) The thread disposes itself.

The Thread Manager implements “Lightweight” concurrent processing, so switching between thread contexts is extremely fast. You will notice very little performance degradation by making your CGI threaded. Also, you’ll find that making the Thread Manager calls are relatively straightforward, but there are a couple of “gotchas”. First, you can not allocate or release memory within a thread context. Your main event loop should do all of this and then pass the handles or pointers to each thread. You will also need to watch your use of global variables closely. Global variables are available to threads, but they are common to all threads running. So using globals can be very handy, but make sure you don’t rely on a global variable for storing data within a thread or you may find the threads are writing over each others’ data.

Other Special Considerations

Being a server-based application, your CGI will need to pay special attention and be a good citizen. Here are just a few tips:

1) Release the CPU as often as possible, and for a decent amount of time. In general, your main event loop won’t be doing much when your CGI is idle, so all you really need to do is use a large value for the “sleep ticks” in your WaitNextEvent call. Sleep ticks apply only to idle events, so you will be notified immediately when an Apple event comes in anyway.

2) Don’t use modal dialog boxes. Many servers will be unattended, and modal dialogs are a sure way to hang the server. If you get errors, write an entry into a log file, or display the error on your status window (if you have one) and beep.

3) CGIs are limited to 32K for the return file size, so if your application is running as a CGI, you won’t be able to send huge return strings. The limit on ACGIs is much higher, and is dependent on when Apple events starts generating memory errors. I haven’t done exhaustive research on this, but it does vary from machine to machine. Most servers handle 60K replies just fine, but some will crash when you try to pass this much data. I wouldn’t recommend trying to send any more than 50 to 60K just to be on the safe side.

4) When a CGI isn’t already running, WebSTAR will launch it when it is needed, so some CGIs quit after every time they are executed. This causes a few seconds of delay while the CGI launches, but may not be an issue if the CGI is executed only very rarely. The other problem with launching CGIs on the fly is that you may encounter problems starting up. Out of memory errors and other startup problems may cause modal dialog boxes to be displayed, which may cause the server to halt.

Advanced Topics

Well, now you have plenty to get started building Web-based applications in C. There is more to learn, though, once you have had a few successes. For one thing, StarNine is constantly coming out with enhancements that make CGIs easier to use and more powerful. By the time you’ve read this, there will undoubtedly be new capabilities available to CGIs, but here are a few of the things that you will want to learn more about once you feel comfortable with the basic principals:

1) A URL that activates a CGI, as we have said, normally includes the name of the CGI. WebSTAR now supports “actions”, which allows you to define filename extensions that will trigger your CGI. So, for example, if your CGI performs a database search, you could map the CGI to a filename suffix of “.srch”. Any URL that references a file ending with “.srch” would be passed to your CGI. The file being referenced by the CGI doesn’t need to actually exist, in fact, it probably won’t. The URL will simply be passed to your CGI and you will decide what to do with it. Very powerful stuff.

2) You can also now define a “Pre-processor” and a “Post-processor” for WebSTAR. The pre-processor is a CGI that gets every request before WebSTAR processes it. The CGI can choose to process the request itself or pass it back to WebSTAR for normal processing. The post-processor gets information about the request after WebSTAR is done processing it, which can be used to implement new logging methods or set off alarms for certain activity.

3) WebSTAR will not only send Apple events when incoming requests need to be processed, but will also respond to them. You can use Apple events to extract and update many of the configuration options in WebSTAR, as well as perform other interesting jobs. That means that your CGI can manipulate WebSTAR itself. Note that, in order to do this, you must be using an ACGI. Otherwise, WebSTAR stops and waits for the CGI to reply, and can’t respond to events.

4) Finally, WebSTAR supports “server push” by allowing a CGI to return data to the client in multiple Apple events. This can be handy for applications where the data is being returned on a timed basis (like reports every minute) or where the data is being gathered very slowly (as in searching a large database). This is also a way to get around the file size limitation, because while each event can contain only 60k or so of data, you can use multiple chunks to send an arbitrarily large amount of data back to the user.

Wrapping Up

Now that you know how C CGIs work, you’ll want to get started. The fastest way is to visit my Web site, where you’ll find “Responder”. To get to the Maxum Web site, point your browser at “http://www.maxum.com/maxum/”. [It’s at all the usual source code sites, listed on page 2, as well. -jtk]

Responder is a very simple CGI that includes source code and a CodeWarrior project that will get you started very quickly. There is at least one other C CGI available so you might want to look around to find what will work best for you. Responder is a bare-bones shell that is very easy to understand, and it will make sense to you, having just read this article, since most of the code listed here has been clipped from Responder.

Have fun!

 

Community Search:
MacTech Search:

Software Updates via MacUpdate

Latest Forum Discussions

See All

Whitethorn Games combines two completely...
If you have ever gone fishing then you know that it is a lesson in patience, sitting around waiting for a bite that may never come. Well, that's because you have been doing it wrong, since as Whitehorn Games now demonstrates in new release Skate... | Read more »
Call of Duty Warzone is a Waiting Simula...
It's always fun when a splashy multiplayer game comes to mobile because they are few and far between, so I was excited to see the notification about Call of Duty: Warzone Mobile (finally) launching last week and wanted to try it out. As someone who... | Read more »
Albion Online introduces some massive ne...
Sandbox Interactive has announced an upcoming update to its flagship MMORPG Albion Online, containing massive updates to its existing guild Vs guild systems. Someone clearly rewatched the Helms Deep battle in Lord of the Rings and spent the next... | Read more »
Chucklefish announces launch date of the...
Chucklefish, the indie London-based team we probably all know from developing Terraria or their stint publishing Stardew Valley, has revealed the mobile release date for roguelike deck-builder Wildfrost. Developed by Gaziter and Deadpan Games, the... | Read more »
Netmarble opens pre-registration for act...
It has been close to three years since Netmarble announced they would be adapting the smash series Solo Leveling into a video game, and at last, they have announced the opening of pre-orders for Solo Leveling: Arise. [Read more] | Read more »
PUBG Mobile celebrates sixth anniversary...
For the past six years, PUBG Mobile has been one of the most popular shooters you can play in the palm of your hand, and Krafton is celebrating this milestone and many years of ups by teaming up with hit music man JVKE to create a special song for... | Read more »
ASTRA: Knights of Veda refuse to pump th...
In perhaps the most recent example of being incredibly eager, ASTRA: Knights of Veda has dropped its second collaboration with South Korean boyband Seventeen, named so as it consists of exactly thirteen members and a video collaboration with Lee... | Read more »
Collect all your cats and caterpillars a...
If you are growing tired of trying to build a town with your phone by using it as a tiny, ineffectual shover then fear no longer, as Independent Arts Software has announced the upcoming release of Construction Simulator 4, from the critically... | Read more »
Backbone complete its lineup of 2nd Gene...
With all the ports of big AAA games that have been coming to mobile, it is becoming more convenient than ever to own a good controller, and to help with this Backbone has announced the completion of their 2nd generation product lineup with their... | Read more »
Zenless Zone Zero opens entries for its...
miHoYo, aka HoYoverse, has become such a big name in mobile gaming that it's hard to believe that arguably their flagship title, Genshin Impact, is only three and a half years old. Now, they continue the road to the next title in their world, with... | Read more »

Price Scanner via MacPrices.net

B&H has Apple’s 13-inch M2 MacBook Airs o...
B&H Photo has 13″ MacBook Airs with M2 CPUs and 256GB of storage in stock and on sale for up to $150 off Apple’s new MSRP, starting at only $849. Free 1-2 day delivery is available to most US... Read more
M2 Mac minis on sale for $100-$200 off MSRP,...
B&H Photo has Apple’s M2-powered Mac minis back in stock and on sale today for $100-$200 off MSRP. Free 1-2 day shipping is available for most US addresses: – Mac mini M2/256GB SSD: $499, save $... Read more
Mac Studios with M2 Max and M2 Ultra CPUs on...
B&H Photo has standard-configuration Mac Studios with Apple’s M2 Max & Ultra CPUs in stock today and on Easter sale for $200 off MSRP. Their prices are the lowest available for these models... Read more
Deal Alert! B&H Photo has Apple’s 14-inch...
B&H Photo has new Gray and Black 14″ M3, M3 Pro, and M3 Max MacBook Pros on sale for $200-$300 off MSRP, starting at only $1399. B&H offers free 1-2 day delivery to most US addresses: – 14″ 8... Read more
Department Of Justice Sets Sights On Apple In...
NEWS – The ball has finally dropped on the big Apple. The ball (metaphorically speaking) — an antitrust lawsuit filed in the U.S. on March 21 by the Department of Justice (DOJ) — came down following... Read more
New 13-inch M3 MacBook Air on sale for $999,...
Amazon has Apple’s new 13″ M3 MacBook Air on sale for $100 off MSRP for the first time, now just $999 shipped. Shipping is free: – 13″ MacBook Air (8GB RAM/256GB SSD/Space Gray): $999 $100 off MSRP... Read more
Amazon has Apple’s 9th-generation WiFi iPads...
Amazon has Apple’s 9th generation 10.2″ WiFi iPads on sale for $80-$100 off MSRP, starting only $249. Their prices are the lowest available for new iPads anywhere: – 10″ 64GB WiFi iPad (Space Gray or... Read more
Discounted 14-inch M3 MacBook Pros with 16GB...
Apple retailer Expercom has 14″ MacBook Pros with M3 CPUs and 16GB of standard memory discounted by up to $120 off Apple’s MSRP: – 14″ M3 MacBook Pro (16GB RAM/256GB SSD): $1691.06 $108 off MSRP – 14... Read more
Clearance 15-inch M2 MacBook Airs on sale for...
B&H Photo has Apple’s 15″ MacBook Airs with M2 CPUs (8GB RAM/256GB SSD) in stock today and on clearance sale for $999 in all four colors. Free 1-2 delivery is available to most US addresses.... Read more
Clearance 13-inch M1 MacBook Airs drop to onl...
B&H has Apple’s base 13″ M1 MacBook Air (Space Gray, Silver, & Gold) in stock and on clearance sale today for $300 off MSRP, only $699. Free 1-2 day shipping is available to most addresses in... Read more

Jobs Board

Medical Assistant - Surgical Oncology- *Apple...
Medical Assistant - Surgical Oncology- Apple Hill Location: WellSpan Medical Group, York, PA Schedule: Full Time Sign-On Bonus Eligible Remote/Hybrid Regular Apply Read more
Omnichannel Associate - *Apple* Blossom Mal...
Omnichannel Associate - Apple Blossom Mall Location:Winchester, VA, United States (https://jobs.jcp.com/jobs/location/191170/winchester-va-united-states) - Apple Read more
Cashier - *Apple* Blossom Mall - JCPenney (...
Cashier - Apple Blossom Mall Location:Winchester, VA, United States (https://jobs.jcp.com/jobs/location/191170/winchester-va-united-states) - Apple Blossom Mall Read more
Operations Associate - *Apple* Blossom Mall...
Operations Associate - Apple Blossom Mall Location:Winchester, VA, United States (https://jobs.jcp.com/jobs/location/191170/winchester-va-united-states) - Apple Read more
Business Analyst | *Apple* Pay - Banco Popu...
Business Analyst | Apple PayApply now " Apply now + Apply Now + Start applying with LinkedIn Start + Please wait Date:Mar 19, 2024 Location: San Juan-Cupey, PR Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.