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

Tokkun Studio unveils alpha trailer for...
We are back on the MMORPG news train, and this time it comes from the sort of international developers Tokkun Studio. They are based in France and Japan, so it counts. Anyway, semantics aside, they have released an alpha trailer for the upcoming... | Read more »
Win a host of exclusive in-game Honor of...
To celebrate its latest Jujutsu Kaisen crossover event, Honor of Kings is offering a bounty of login and achievement rewards kicking off the holiday season early. [Read more] | Read more »
Miraibo GO comes out swinging hard as it...
Having just launched what feels like yesterday, Dreamcube Studio is wasting no time adding events to their open-world survival Miraibo GO. Abyssal Souls arrives relatively in time for the spooky season and brings with it horrifying new partners to... | Read more »
Ditch the heavy binders and high price t...
As fun as the real-world equivalent and the very old Game Boy version are, the Pokemon Trading Card games have historically been received poorly on mobile. It is a very strange and confusing trend, but one that The Pokemon Company is determined to... | Read more »
Peace amongst mobile gamers is now shatt...
Some of the crazy folk tales from gaming have undoubtedly come from the EVE universe. Stories of spying, betrayal, and epic battles have entered history, and now the franchise expands as CCP Games launches EVE Galaxy Conquest, a free-to-play 4x... | Read more »
Lord of Nazarick, the turn-based RPG bas...
Crunchyroll and A PLUS JAPAN have just confirmed that Lord of Nazarick, their turn-based RPG based on the popular OVERLORD anime, is now available for iOS and Android. Starting today at 2PM CET, fans can download the game from Google Play and the... | Read more »
Digital Extremes' recent Devstream...
If you are anything like me you are impatiently waiting for Warframe: 1999 whilst simultaneously cursing the fact Excalibur Prime is permanently Vault locked. To keep us fed during our wait, Digital Extremes hosted a Double Devstream to dish out a... | Read more »
The Frozen Canvas adds a splash of colou...
It is time to grab your gloves and layer up, as Torchlight: Infinite is diving into the frozen tundra in its sixth season. The Frozen Canvas is a colourful new update that brings a stylish flair to the Netherrealm and puts creativity in the... | Read more »
Back When AOL WAS the Internet – The Tou...
In Episode 606 of The TouchArcade Show we kick things off talking about my plans for this weekend, which has resulted in this week’s show being a bit shorter than normal. We also go over some more updates on our Patreon situation, which has been... | Read more »
Creative Assembly's latest mobile p...
The Total War series has been slowly trickling onto mobile, which is a fantastic thing because most, if not all, of them are incredibly great fun. Creative Assembly's latest to get the Feral Interactive treatment into portable form is Total War:... | Read more »

Price Scanner via MacPrices.net

Early Black Friday Deal: Apple’s newly upgrad...
Amazon has Apple 13″ MacBook Airs with M2 CPUs and 16GB of RAM on early Black Friday sale for $200 off MSRP, only $799. Their prices are the lowest currently available for these newly upgraded 13″ M2... Read more
13-inch 8GB M2 MacBook Airs for $749, $250 of...
Best Buy has Apple 13″ MacBook Airs with M2 CPUs and 8GB of RAM in stock and on sale on their online store for $250 off MSRP. Prices start at $749. Their prices are the lowest currently available for... Read more
Amazon is offering an early Black Friday $100...
Amazon is offering early Black Friday discounts on Apple’s new 2024 WiFi iPad minis ranging up to $100 off MSRP, each with free shipping. These are the lowest prices available for new minis anywhere... Read more
Price Drop! Clearance 14-inch M3 MacBook Pros...
Best Buy is offering a $500 discount on clearance 14″ M3 MacBook Pros on their online store this week with prices available starting at only $1099. Prices valid for online orders only, in-store... Read more
Apple AirPods Pro with USB-C on early Black F...
A couple of Apple retailers are offering $70 (28%) discounts on Apple’s AirPods Pro with USB-C (and hearing aid capabilities) this weekend. These are early AirPods Black Friday discounts if you’re... Read more
Price drop! 13-inch M3 MacBook Airs now avail...
With yesterday’s across-the-board MacBook Air upgrade to 16GB of RAM standard, Apple has dropped prices on clearance 13″ 8GB M3 MacBook Airs, Certified Refurbished, to a new low starting at only $829... Read more
Price drop! Apple 15-inch M3 MacBook Airs now...
With yesterday’s release of 15-inch M3 MacBook Airs with 16GB of RAM standard, Apple has dropped prices on clearance Certified Refurbished 15″ 8GB M3 MacBook Airs to a new low starting at only $999.... Read more
Apple has clearance 15-inch M2 MacBook Airs a...
Apple has clearance, Certified Refurbished, 15″ M2 MacBook Airs now available starting at $929 and ranging up to $410 off original MSRP. These are the cheapest 15″ MacBook Airs for sale today at... Read more
Apple drops prices on 13-inch M2 MacBook Airs...
Apple has dropped prices on 13″ M2 MacBook Airs to a new low of only $749 in their Certified Refurbished store. These are the cheapest M2-powered MacBooks for sale at Apple. Apple’s one-year warranty... Read more
Clearance 13-inch M1 MacBook Airs available a...
Apple has clearance 13″ M1 MacBook Airs, Certified Refurbished, now available for $679 for 8-Core CPU/7-Core GPU/256GB models. Apple’s one-year warranty is included, shipping is free, and each... Read more

Jobs Board

Seasonal Cashier - *Apple* Blossom Mall - J...
Seasonal Cashier - Apple Blossom Mall Location:Winchester, VA, United States (https://jobs.jcp.com/jobs/location/191170/winchester-va-united-states) - Apple Read more
Seasonal Fine Jewelry Commission Associate -...
…Fine Jewelry Commission Associate - Apple Blossom Mall Location:Winchester, VA, United States (https://jobs.jcp.com/jobs/location/191170/winchester-va-united-states) Read more
Seasonal Operations Associate - *Apple* Blo...
Seasonal Operations Associate - Apple Blossom Mall Location:Winchester, VA, United States (https://jobs.jcp.com/jobs/location/191170/winchester-va-united-states) - Read more
Hair Stylist - *Apple* Blossom Mall - JCPen...
Hair Stylist - Apple Blossom Mall Location:Winchester, VA, United States (https://jobs.jcp.com/jobs/location/191170/winchester-va-united-states) - Apple Blossom 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
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.