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

MTR 5.0.0.1 - The Mac's oldest and...
MTR (was MacTheRipper)--the Mac's oldest and smartest DVD-backup app--is now updated to version 5.001 MTR -- the complete toolbox, not a one-trick, point-and-click extractor. MTR is intended for... Read more
LibreOffice 4.4.5.2 - Free, open-source...
LibreOffice is an office suite (word processor, spreadsheet, presentations, drawing tool) compatible with other major office suites. The Document Foundation is coordinating development and... Read more
Adobe Lightroom 6.1.1 - Import, develop,...
Adobe Lightroom is available as part of Adobe Creative Cloud for as little as $9.99/month bundled with Photoshop CC as part of the photography package. Lightroom 6 is also available for purchase as a... Read more
File Juicer 4.41 - Extract images, video...
File Juicer is a drag-and-drop can opener and data archaeologist. Its specialty is to find and extract images, video, audio, or text from files which are hard to open in other ways. It finds and... Read more
A Better Finder Rename 9.52 - File, phot...
A Better Finder Rename is the most complete renaming solution available on the market today. That's why, since 1996, tens of thousands of hobbyists, professionals and businesses depend on A Better... Read more
OmniFocus 2.2.3 - GTD task manager with...
OmniFocus helps you manage your tasks the way that you want, freeing you to focus your attention on the things that matter to you most. Capturing tasks and ideas is always a keyboard shortcut away in... Read more
TinkerTool 5.4 - Expanded preference set...
TinkerTool is an application that gives you access to additional preference settings Apple has built into Mac OS X. This allows to activate hidden features in the operating system and in some of the... Read more
Tinderbox 6.3.1 - Store and organize you...
Tinderbox is a personal content management assistant. It stores your notes, ideas, and plans. It can help you organize and understand them. And Tinderbox helps you share ideas through Web journals... Read more
Parallels Desktop 10.2.2 - Run Windows a...
Parallels Desktop is simply the world's bestselling, top-rated, and most trusted solution for running Windows applications on your Mac. With Parallels Desktop for Mac, you can seamlessly run both... Read more
Adobe Premiere Pro CC 2015 9.0.1 - Digit...
Premiere Pro CC 2015 is available as part of Adobe Creative Cloud for as little as $19.99/month (or $9.99/month if you're a previous Premiere Pro customer). Premiere Pro CS6 is still available for... Read more

You Against Me (Games)
You Against Me 1.0 Device: iOS Universal Category: Games Price: $.99, Version: 1.0 (iTunes) Description: A simple game… You. Me. Claim, steal, lock, score, win! | Read more »
Yep, it's True - Angry Birds 2 is O...
The not exactly rumors were true and the birds are back. Angry Birds 2 has come to the App Store and the world will... well I suppose it'll still be the same, but now we have more bird-flinging options! [Read more] | Read more »
You Could Design Your Own Card for Chain...
If you've ever wanted to create your own item, weapon, trap, or even monster for Chainsaw Warrior: Lords of the Night, this is your chance. Auroch Digital is currently holding a contest so that fans can fight to the death (not really) to see which... | Read more »
Bitcoin Billionaire is Going Back in Tim...
If you thought you managed to buy everything there is to buy in Bitcoin Billionaire and make all the money, well you though wrong. Those of you who made it far enough might remember investing in time travel - and it looks like that investment is... | Read more »
Domino Drop (Games)
Domino Drop 1.0 Device: iOS Universal Category: Games Price: $1.99, Version: 1.0 (iTunes) Description: Domino Drop is a delightful new puzzle game with dominos and gravity!Learn how to play it in a minute, master it day by day.Your... | Read more »
OPERATION DRACULA (Games)
OPERATION DRACULA 1.0.1 Device: iOS Universal Category: Games Price: $5.99, Version: 1.0.1 (iTunes) Description: 25% off launch sale!!! 'Could prove to be one of the most accurate representations of the Japanese bullet hell shmup... | Read more »
Race The Sun (Games)
Race The Sun 1.01 Device: iOS iPhone Category: Games Price: $4.99, Version: 1.01 (iTunes) Description: You are a solar craft. The sun is your death timer. Hurtle towards the sunset at breakneck speed in a futile race against time.... | Read more »
Tap Delay (Music)
Tap Delay 1.0.0 Device: iOS Universal Category: Music Price: $4.99, Version: 1.0.0 (iTunes) Description: Back in the “old days”, producers and engineers created delay and echo effects using tape machines. Tap Delay combines the warm... | Read more »
This Week at 148Apps: July 20-24, 2015
July is Heating Up With 148Apps How do you know what apps are worth your time and money? Just look to the review team at 148Apps. We sort through the chaos and find the apps you're looking for. The ones we love become Editor’s Choice, standing out... | Read more »
Red Game Without A Great Name (Games)
Red Game Without A Great Name 1.0.3 Device: iOS Universal Category: Games Price: $2.99, Version: 1.0.3 (iTunes) Description: The mechanical bird is flying through an unfriendly, Steampunk world. Help it avoid obstacles and deadly... | Read more »

Price Scanner via MacPrices.net

Apple’s Education discount saves up to $300 o...
Purchase a new Mac or iPad at The Apple Store for Education and take up to $300 off MSRP. All teachers, students, and staff of any educational institution qualify for the discount. Shipping is free,... Read more
12-inch MacBooks in stock for $20 off, save o...
Adorama has 12″ Retina MacBooks in stock for $20 off MSRP including free shipping plus NY & NJ sales tax only. For a limited time, Adorama will include a free Apple USB-C to USB Adapter, free 4-... Read more
College Student Deals: Additional $100 off Ma...
Take an additional $100 off all MacBooks and iMacs at Best Buy Online with their College Students Deals Savings, valid through August 8, 2015. Anyone with a valid .EDU email address can take... Read more
2015 13-inch 2.7GHz Retina MacBook Pro on sal...
B&H Photo has the new 2015 13″ 2.7GHz/128GB Retina MacBook Pro on sale today for $1199 including free shipping plus NY sales tax only. Their price is $100 off MSRP. Read more
2.8GHz Mac mini available for $988, includes...
Adorama has the 2.8GHz Mac mini available for $988, $11 off MSRP, including a free copy of Apple’s 3-Year AppleCare Protection Plan. Shipping is free, and Adorama charges sales tax in NY & NJ... Read more
Updated Mac Price Trackers
We’ve updated our Mac Price Trackers with the latest information on prices, bundles, and availability on systems from Apple’s authorized internet/catalog resellers: - 15″ MacBook Pros - 13″ MacBook... Read more
High-Precision Battery Fuel Gauge IC Extends...
Renesas Electronics Corporation has announced its new lithium-ion (Li-ion) battery fuel gauge IC, the RAJ240500, designed to extend battery life for connected mobile devices such as tablets, notebook... Read more
27-inch 3.3GHz 5K iMac on sale for $1799, $20...
B&H Photo has the 27″ 3.3GHz 5K iMac on sale for $1799 including free shipping plus NY tax only. Their price is $200 off MSRP, and it’s the lowest price available for this model from any Apple... Read more
Twelve South Free Dual Screen Backgrounds Co...
Twelve South has posted a second collection of travel Desktop photos, noting: For the Twelve South team, a vacation is never just a vacation. It’s a time to try out new prototypes on the road, visit... Read more
Apple Refurbished iMacs available for up to $...
The Apple Store has Apple Certified Refurbished iMacs available for up to $380 off the cost of new models. Apple’s one-year warranty is standard, and shipping is free: - 27″ 3.5GHz 5K iMac – $1949 $... Read more

Jobs Board

Engineering Manager, Search Relevance, *Appl...
**Job Summary** Apple 's new Spotlight Suggestions service provides fast, relevant search results from the Inte et in Spotlight and Safari on iOS and OS X. We are looking Read more
Lead Infrastructure Engineer - *Apple* /Mac P...
…of a team * Requires proven problem solving skills Preferred Additional: * Apple Certified System Administrator (ACSA) * Apple Certified Technical Coordinator (ACTC) Read more
*Apple* Retail - Multiple Positions (US) - A...
Job Description: Sales. Specialist - Retail Customer Service and Sales. Transform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
*Apple* Retail - Multiple Positions (US) - A...
Job Description: Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
*Apple* Retail - Multiple Positions (US) - A...
Job Description: Sales. Specialist - Retail Customer Service and Sales. Transform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.