What do you do if your server can't do what you want it to? Buy another server? Not do what you were planning on? Even CGI programs can't really change the way a server works; they can only add on specific functions that need to be called in a specific way. Another way does exist, however.
The Netscape Server API, or NSAPI, enables you to add functions to your server, like CGI, but it also enables you to change the way the server works at the very core of its functionality. Don't like the way errors are handled? Change the error handling. Not enough information being logged? Change the logging system. Want to add your own custom authorization mechanism? Go right ahead. The power exists for you to change almost any function that the server performs, as well as add whatever pieces you want.
In this chapter, you explore the world of the NSAPI and see what it means to Netscape as well as to you, the developer/user. The primary focus areas are as follows:
Let me give you advance warning: creating and using NSAPI functions require a thorough knowledge of C programming. Some of the information contained in this chapter may be of more use if you have a programming background, as I cover data structures, function calls, and general programming issues. The real focus of this chapter, though, is to provide you with a detailed overview of the NSAPI itself so that you have a starting point if you want to pursue it further.
Caution |
Before you spend too much time learning about the NSAPI standard, make sure that your server supports it. It is native only to Netscape servers, and there are certain other server packages and versions that have added, or are adding, NSAPI support. You wouldn't want to create a great function only to find out it can't be of any use to you. |
When building their servers, Netscape couldn't possibly anticipate exactly how you would want to work. They could and have built in a great deal of flexibility to enable you to perform most of the tasks you want, but you will always have a set of functions or a way of doing business that is unique to your situation. Support for the open CGI standard allows easy access to functionality to extend the server's reach, but in a world where things need to be faster, more flexible, and more seamlessly integrated, easy access is often not enough.
Netscape has a vision, and that vision is the Internet Application Framework. Sounds all-encompassing, doesn't it? Well, it is. The overall focus of Netscape's efforts is to create a set of open standards and protocols that any developer can use to get the functionality that he or she needs for Internet and intranet applications. As part of Netscape's Open Network Environment (ONE) philosophy, the Internet Application Framework and NSAPI, specifically, play pivotal roles in defining the next generation of applications. Figure 26.1 shows Netscape's representation of this Internet Application Framework. The figure also shows that in Netscape's vision NSAPI and CGI (along with other technologies) reside in the category of Server APIs (Application Programming Interfaces).
Figure 26.1 : Netscape's representation of their Internes Application Framework.
Server APIs are the methods that you can use to extend your server's functionality. An API is nothing more than a way to get at special bits of data and exert an amount of control over the server itself, through a variety of methods.
Unlike CGI, whose open standard is supported by almost every server in existence, no open standard currently exists for Web servers. This lack of standard presents a problem, and it goes rather deep-each server is different, and its insides operate in different ways. Without forcing every server developer to adopt the same methodology in how he or she processes data internally, no common ground can be had for every server to take advantage of. Although this situation might present a problem for some companies, it's just another opportunity for Netscape.
With its broad base of users, Netscape can influence Internet trends, including HTML, security issues, and servers themselves. Most of this influence is through just adopting what Netscape feels is a good method of doing something and going with it. In a few cases, arbitrary additions meet with unanimous approval (frames, for instance), but Netscape has enough momentum to avoid being bogged down by a need for everyone to endorse what they've designed. Much like Microsoft often says, "This is the standard that software must conform to." Because they control a great percentage of the operating systems market, Netscape has a similar kind of power in the Internet environment, and it is due to their setting the trends, not following them.
The NSAPI is Netscape's next venture into trend-setting standards, though it will be a much more difficult task. The first reason is, as I mentioned before, that it involves having the server work in a specific way. The second is that it requires a reasonably high level of expertise to create a useful and robust API function. The final reason is the one that may be the biggest obstacle: Netscape is not alone in their proposal for a server API standard. The challengers are numerous, but the biggest competition comes from one source-the combination of Microsoft and Process Software to create the Internet Server API (ISAPI).
Note |
Later in this chapter I cover in more detail the future of the NSAPI amidst these challenges. You can also review the ISAPI in Chapter 25, "ISAPI." |
Why, then, with all these challenges, would anyone pursue the creation of NSAPI functions? To begin to understand that question, you must start by comparing NSAPI functions to the CGI standard to understand where they're similar and where they part company.
As you can see from the diagram shown in Figure 26.1, many other components fit naturally into the creation of Internet applications, but the role of NSAPI itself is the focus of attention here. Both CGI and NSAPI provide additional server-side functionality; that is, they isolate data processing from the client for convenience, security, and/or speed. The key difference is that a CGI program is built to take advantage of data gathered by the server and operate outside the boundaries of the HTTP server's environment, whereas NSAPI functions are built directly into the server itself, extending its core functionality to meet individual or corporate needs.
Of all the server software produced anywhere in the world, only a small fraction provides no support for the CGI standard or some closely related independent extension. The reason is that CGI makes sense. You can't expect the server manufacturer to know everything you want to do with the software, and often you wouldn't want the manufacturer to cramp your style even if it could predict some form of what you wanted.
As you've seen throughout this book, using CGI can be an easy and powerful way to extend the server's functionality without too much fuss.
API functions are faster than CGI functions. How much faster? They are anywhere from two to five times as fast, depending on what you're doing. Knowing how important it is to get work done as fast as possible on the Internet, this speed is a good thing.
API functions share process space with the server itself. As a result, these functions are faster. Every time a server executes a CGI program, on the other hand, a new process is started up for that program, and it doesn't like to share with anybody. That's one process per CGI execution. Imagine how much server effort that process causes if your server gets tens of thousands of CGI hits a day. And people wonder why server's need so much memory.
If you look through a CGI script, you'll see that it's just not designed to be nice to other applications that may need extra memory or processor time. Each script wants to do its task as fast as possible and get out of there. Although this capability may not be bad for most functions, think of database functions. Say you have a database with 400,000 records in it, and you're doing a search off a subset within your CGI script. Every time you want to do some Inter-Process Communications to whatever manages your data source, you're in for a long haul. API functions, on the other hand, share resources of any kind and can coexist peacefully whether they're dealing with an external or an internal resource.
The largest advantage that an API function has over a CGI program is the amount of data and number of functions that the server has available but can't be accessed from "outside the loop" of its own process space. CGI is designed to receive data and send data in a limited fashion through intermediaries (environment variables and STDOUT, normally). API functions, however, are part of the server itself and can cause the server to take some action or intercept some action that the server might normally do.
Suppose that you have a page that requires authorization, and someone within your company who isn't authorized tries to access it. You could intercept the error message that would normally go back, identify who the user is, and then present more appropriate feedback, such as "Sorry, Bob, you don't currently have access to the Technical Specifications for that product. The contact person for your department's questions is Janet, who can be reached at extension 58. Your regional contact is Joe, who can be reached at 555-0101 for any questions when Janet isn't available." As you can see, this message is a lot more helpful than the Access Denied message. By building this functionality as an additional server function, all your company's servers can easily make use of similar functionality, and it will be transparent to the users and even to some of the administrators.
The preceding example is just a sampling of what you can do, and without having much impact on your server's performance at all. You can create customized logging entries, security functions, reporting, automatic document conversion, and even "cookie"-like information for maintaining user states while they're accessing your pages. The functionality you add is all up to you, your needs, and your imagination.
To help you better understand the ways in which the NSAPI enables you to get better acquainted with your server, I delve into some of the functions and structures that make the NSAPI what it is in the following sections.
NSAPI works by acting in place of, or in addition to, specific server functions. By crawling around inside your server's configuration files and changing what things are being done, you can rebuild the server in any way you want. Not only are you customizing it to meet your needs, but you're also learning how it worked in the first place.
The server functions that you're adjusting to your own purposes take place in a specific order, starting as soon as the client sends a message that says, "I'd like this file." This process is called an HTTP Request/Response process; it's the series of tasks that occurs once the client has sent data, and the duty rests with the server to complete the exchange of information.
To come to grips with how Netscape servers treat this whole process, look at Netscape's own definition of what the HTTP Request/Response process looks like, as shown in Table 26.1.
Authorization Translation | Any client authorization data converted into user and group for server |
Name Translation | URL translated or modified, if necessary |
Path Checks | Local access tests to ensure document can be safely retrieved |
Object Type Check | Evaluate the MIME type for the given object (document) |
Response to Request | Generate appropriate feedback |
Logging of Transaction | Save information about the transaction to logging files |
To get from the beginning to the end of the whole Request/Response
process, each one of these steps has its own internal server functions,
called server application functions. These internal functions,
which are known to the server, help it do its job. These functions
can be separated into classes, called function classes,
to best describe what each internal function relates to and to
help with organizing the design process. Each function class relates
to one or more of the processes that take place when the server
answers a client's call for data. Though Netscape's breakdown
of the HTTP Request/Response process has six steps, only five
classes are used because one serves double duty. Table 26.2 lists
these classes in order of execution and tells to which of the
six steps shown in Table 26.1 they map.
AuthTrans | Performs Authorization Translation |
NameTrans | Performs Name Translation |
PathCheck | Performs Path Checks |
ObjectType | Performs Object Type Check |
Service | Performs Response to Request and Logging of Transaction |
Note |
For more detailed information on each of these functions, including what types of response codes and errors they can generate, see "Functions, Variables, and Their Responses" later in this chapter. |
At every step along the way, the server needs to know what functions take priority and what additional functions are available. Although the function classes have their own special order of working, control within each class of function is administered by the server's configuration files. To make use of your own function, you need to know how to define the function in these configuration files and what the configuration files themselves are.
All server application functions, regardless of what they do, get referenced in the same way. They let the server know what function class they belong to, what the name of the function is, and which values need to be passed to the function itself. An example of this kind of function declaration is as follows:
class fn=functionname value1=data1 .. valueN=dataN
You may also see directive substituted for class. You say potato, they say potato.
When you configure a UNIX-based Netscape server to use a function, you do so through the use of two files: magnus.conf and obj.conf.
magnus.conf
The magnus.conf file is the server's master controller. It contains the instructions and directives that the server has to take into account when it first starts up. The magnus.conf file sets up, for example, the server's name, port number, and what functions to load into memory. When you develop an NSAPI function, magnus.conf is the starting point for making sure that your function is available for use. You specify that you want the server, on initialization, to load the module that you've created which holds your function. You also give it any aliases that might be used for your function, as in the following example:
Init fn=load-module shlib=/usr/me/mymodule.so funcs=myfunction
Init specifies that this process is to be performed upon initialization. Next, you instruct the server to use its default load-modules function to load your module, and you provide the full path to that module within the shlib (shared library) parameter. The mymodule.so file is a shared object, which I discuss in the "Functions and Features" section. Finally, you provide the alias (or aliases) for your function so that you can reference it later.
obj.conf
When the server is running, obj.conf is in command. All requests that come to the server get analyzed through the order and method specified in obj.conf to determine what should happen. The breakdown order of the HTTP Request/Response process that you examined in Table 26.1 occurs here. Your particular function is specified somewhere in the obj.conf, depending on what class of function it is and what you want it to do, and the server goes through each function in class order and then function order to see what should happen.
One example of this process is a function supplied by Netscape; it takes a URL path as a value and then maps that value to a hard-coded path on your system. Essentially, it creates a symbolic path link. This function's entry in the obj.conf file follows the basic function declaration:
NameTrans fn=makepath path=/usr/mine/stuff
Here the function is in the NameTrans function class, because it should occur as the server is mapping file locations. The function itself is called makepath; it accepts only one value, a hard-coded path.
Windows NT relies on a different mechanism for controlling server processes, but the basic premise is still the same. Different sections in the Windows NT registry correspond to the purposes of the magnus.conf and obj.conf files, so you just make the entries there instead.
Caution |
Be extremely careful when doing anything to the Windows NT registry. Whereas messing up an obj.conf or a magnus.conf file would only create problems for your server, the NT registry controls all actions on your system. You could ruin your whole week if you accidentally delete or modify something. Before you modify anything, make a backup copy of the registry for safekeeping, or make a system disk that can restore your current configuration. |
You modify the Windows NT registry by running the regedt32.exe program. You should look for the HKEY_LOCAL_MAchINE\Software\Netscape\Httpd-80 section. Remember, this is your entire system configuration, so be careful!
StartUp Key
Under the Httpd-80 section is CurrentVersion\StartUp, which controls the startup processes of the Netscape server. This controls what functions are loaded into memory when the Netscape server runs as an NT service. To add your own entry, you create a new key in the StartUp folder by choosing Edit | Add Key and then entering InitFunction01 (or InitFunction02 if InitFunction01 is already there) in the Key Name value, leaving the Class entry blank for now. You then add values to the key, as shown here:
fn: load-modules
shlib: c:\netscape\stuff\mymodule.dll
funcs: myfunction
Here you're specifying that the server use its own load-modules function to place the shared library (shlib) of c:\netscape\stuff\mymodule.dll into memory. Files with a .dll extension are Windows Dynamic Linked Libraries (DLLs), which allow their functions to be shared by other processes on the system. You're also telling the server that the alias for this particular function is myfunction.
Directive Keys
To convince the server that your function should be called, now that you've specified that it should be loaded, you need to determine where your function fits into the general scheme of things. To start with, go into the CurrentVersion\Objects registry folder and check through the objects listed to see which one of them has the name: default value.
Next, you need to look under that object, in its directive keys, to find the Directive (class) under which your application falls. If your function is supposed to take place as a logging request, for example, you should see if you can find a directive key with a value of Directive: Addlog. If one doesn't exist, you can add it.
After you find (or create, which is less likely) the directive key your function should be part of, you need to add a new function underneath that Directive folder. This time, you just specify the function and any necessary values. A simple case would be just the function itself, as shown here:
fn: myfunction
Here you're just saying, "When you run through this group of functions, be sure to call myfunction as well!"
After you make any changes, regardless of which platform you make them on, you need to shut down the server and restart so that it loads the new functions. Sending the server a Restart signal isn't enough because the signal is not going to cause the server to load the new functions specified in either magnus.conf or the StartUp registry key. Make sure that you completely shut down the server and then start it back up again.
One thing to keep in mind is that certain modules may need to be explicitly instructed to stop what they're doing before the server starts up again; otherwise, you could end up with two instances of a process running, wasting space and even causing conflicts. To clean up those processes, you can use the atrestart() function, defined as
void magnus atrestart(void (*fn) (void *), void *data)
This is called by the server during restart, not during termination, with the data pointer being passed in as the argument for the function call.
To create an NSAPI function, you need to know what it's built of-what data structures and general functions are necessary and available to make your idea for a function become reality.
Just as all server application functions are defined the same way in the configuration files for how they're accessed, all the functions are defined the same way in your actual code. This ensures that they are compatible with the other processes the server is performing and that they can access the server's data in a timely manner. The prototype that follows is Netscape's required definition for each function:
int function(pblock *pb, Session *sn, Request *rq);
To determine the outcome of the function, the integer return from
the function must correspond to the available response code, as
listed in Table 26.3.
REQ_PROCEED | The function has performed its task; proceed with the remainder of the request. | |
REQ_ABORTED | An error occurred; the entire request should be aborted at this point. | |
REQ_NOACTION | The function didn't accomplish what it wanted to do, but the request should proceed. | |
REQ_EXIT | Close the session and exit. |
Depending on the class of function, different interpretations for the returns are available, as you learn in the section "Functions, Variables, and Their Responses."
The parameter block (pblock) data structure is the amino acid of NSAPI functions. Because servers deal with information based on name=value pairs, pblock is a hash table that is keyed on the name string, which then allows the function to map names to values.
The data structures used when dealing with parameter blocks are shown in Listing 26.1. The name=value pairs are stored in the pb_param structures, which are in turn used inside pb_entry to create linked lists of the pb_param structures. The hash table itself (pblock) is defined in Listing 26.2, though it is subject to change by Netscape and is normally transparent to most functions.
Listing 26.1. Parameter block structure definition.
#include "base/pblock.h"
typedef struct {
char *name,*value;
} pb_param;
struct pb_entry {
pb_param *param;
struct pb_entry *next;
};
typedef struct {
int hsize;
struct pb_entry **ht;
} pblock;
Listing 26.2. pblock hash table sample definition.
#include "base/pblock.h"
/* Create parameter with given name and value */
pb_param *param_create(char *name, char *value);
/* Free Parameter if not null, Return 1 if non-null, 0 if null*/
int param_free(pb_param *pp);
/* Create new pblock of Hash Table size 'n' */
pblock *pblock_create(int n);
/* Free defined pblock and entries it contains */
void pblock_free(pblock *pb);
/* Find entry with given name in pblock */
pblock *pblock_find(char *name, pblock *pb);
/* Return value of pblock with given name found in it */
char *pblock_findval(char *name, pblock *pb);
/* Find entry containing name in pblock, and remove it */
pblock *pblock_remove(char *name, pblock *pb);
/* Create new parameter, insert into specified pblock */
pb_param *pblock_nvinsert(char *name, char *value, pblock *pb);
/* Insert a pb_param into a pblock */
void pblock_pinsert)pb_param *pp, pblock *pb);
/* Scan the string for name=value pairs */
int pblock_str2pblock(char *str, pblock *pb);
/* Place all the parameters in pblock into string */
char *pblock_pblock2str(pblock *pb, char *str);
Not all the functions are needed for server application functions, but the preceding listings show which functions are currently defined. Before implementing any of these functions, however, check the latest version of your server documentation, which contains more specific details on each one of these functions, their use, and their current state.
A session, by Netscape's definition for the NSAPI, is the
time between the opening and the closing of the client connection.
To hold the data associated with the session in question and make
it available system-wide, a Session
data structure is needed, as outlined in Listing 26.3.
Listing 26.3. Sample Session data structure.
#include "base/session.h"
typdef struct {
pblock *client;
SYS_NETFD csd;
netbuf *inbuf;
struct in_addr iaddr;
} Session;
The client parameter block points to two more pieces of information to help identify the session uniquely: the IP address of the client machine and the resolved DNS name of the client machine. Information in csd and inbuf is relevant to the socket descriptor for the connection, whereas the iaddr structure is for internal use and contains raw socket information.
When the client makes a request, various HTTP-related information
is stored, just as it is during normal CGI operations. All this
information is accessible through the Request
data structure, as outlined in Listing 26.4.
Listing 26.4. HTTP Request data structure.
#include "frame/req.h"
typedef struct {
/* Server's working variables */
pblock *vars;
/* Method, URI, and Protocol specified */
pblock *reqpb;
/* Protocol Specific Headers */
int loadhdrs;
pblock *headers;
/* Server's Response headers */
pblock *srvhdrs;
/* Object Set constructed to handle this request */
httpd_objset *os;
/* Last stat returned by request_stat_path */
char *statpath;
struct stat *finfo;
} Request;
Contained within the Request
structure are several sources of data that your function can take
advantage of, depending on what function class your function belongs
to and what you're
looking for.
The vars parameter block contains function-specific variables, which are different for every function class. In the section "Functions, Variables, and Their Responses," you will look in more detail at what the possible values can be.
One of the first things your function comes in contact with is
the reqpb parameter block
because it contains the data you first need to evaluate, as outlined
in Table 26.4.
method | HTTP method used to initialize the request; equivalent to the REQUEST_METHOD variable |
uri | The URI that the client requests |
protocol | The HTTP protocol version that the client supports |
clf-request | The first line of the client's request to be used for logging or other similar purposes |
The headers block is just what you would expect-the headers sent by the client. If more than one value is sent for the same header, they are joined together with a comma, as follows:
Header: value1, value2
Tip |
Netscape recommends that you do not access the pblock for headers directly but instead use the following function: int request_headers(char *name, char *value, Session *sn, Request *rq) Even though you can access the pblock directly, that capability may change in the future. Because Netscape doesn't want you to create code that won't work later, they have made this recommendation. |
The data contained in srvhdrs is just the reverse of the headers block: this is the place where you can specify headers to be sent back to the client for the request result.
The last three parts of Listing 26.4 (os, statpath, and finfo) are used by the base server itself and are basically transparent to your application. They essentially verify the status of a given path, returning a stat structure if it's successful or an error code if it isn't.
With each of the application function classes, specific data is evaluated, and certain response codes are valid. In the following sections, I help you review each one of the main classes in the order that the server handles them, and then I cover what's available with each one for both variables and response codes. Following that, I provide further information on some other common functions that are available to your applications.
AuthTrans decodes any authorization type data sent by the client so that it can compare the data to internal tables and determine the validity of the user. If the user is verified, AuthTrans makes the following data available in a vars pblock:
AuthTrans returns one of the following three response codes, with the following meanings:
NameTrans converts a virtual path, such as /stuff/docs into the absolute directory path, such as /usr/bin/netscape/docs/stuff/docs.
NameTrans functions expect to receive two variables in the vars pblock on execution: ppath and name. ppath is the partial path, that is, the virtual path that was supplied such as /stuff/docs. It may have already been partially translated, and your function can modify it, no matter what it decides to return. The name variable specifies additional server objects (besides default) that should add their list of things to do to this process.
Return codes from a NameTrans function can be any of the following:
PathCheck functions verify that a given path can be safely returned to the client, based on authorization, URL screening, and other similar checks. The only information supplied to the PathCheck function is the path variable, which specifies the location to be checked.
For return codes, anything other than REQ_ABORTED is considered to be a success.
ObjectType functions are supposed to locate a filesystem object for the path supplied. MIME type checks and similar functionality are handled here. If no objects can be matched to the path in question, this function returns an error. The path variable is the only one passed to ObjectType functions, like PathCheck, and returns other than REQ_ABORTED are considered a success.
Service functions are the methods that the server uses to reply to the client's initial request. Usually, the response is automatically generated based on the type of file being sent back, its location, or the authorization of the client for the request in question. Server-Side Includes are parsed before being sent in this stage of execution, whereas other files just go on their merry way.
Because Service functions have to take the initiative for sending the information back to the client, they need to initialize the response process with the following function call:
int protocol_start_response(Session *sn, Request *rq);
Return codes for the Service class functions can be any of the following:
You can use many different functions. The current printed list is 61 pages, including details. They range from the mundane MALLOC (a cross-platform substitute for the malloc() function in C) to the following fun function (which checks for URIs containing ../ or // and returns 1 if they do or 0 if they don't):
int util_uri_is_evil(char *t);
Whatever task you want to perform, you can choose from literally dozens of functions, because you are at the base level of the server itself-anything that it does, you can do as well. Most of the functions that you will need for your server will likely involve reading data from the client, such as pblock_findval() for grabbing the request method, or sending back messages, such as the protocol_status() for sending server error codes to the client.
The complete list is available as part of the NSAPI Development White Papers and Technical Notes, all of which you can find at http://help.netscape.com. In addition, developers who are part of the Netscape Developer's program can obtain further information through the Developer's Technical Library. For further details, visit http://developer.netscape.com to see what's available to the general public and what's available to registered developers.
Reporting when problems occur is important. As I just mentioned, the protocol_status() function enables you to send back information to the client in the form of a traditional server error code. The syntax for the function is as follows:
void protocol_status(Session *sn, Request *rq, int n, char *r);
The Session and Request
structures establish which user session and for which request
the error is being generated, to be sure it goes to the right
place. To specify which error you want to send back, you can use
the r string to enter your
own specific reason that the process encountered an error, and
the n int to specify one
of the available error codes listed in Table 26.5. If you do not
specify a string in r, the
string sent to the client defaults to Reason
Unknown.
PROTOCOL_OK | |
PROTOCOL_NO_RESPONSE | |
PROTOCOL_REDIRECT | |
PROTOCOL_NOT_MODIFED | |
PROTOCOL_BAD_REQUEST | |
PROTOCOL_UNAUTHORIZED | |
PROTOCOL_FORBIDDEN | |
PROTOCOL_NOT_FOUND | |
PROTOCOL_PROXY_UNAUTHORIZED | |
PROTOCOL_SERVER_ERROR | |
PROTOCOL_NOT_IMPLEMENTED |
When you're ready to take the plunge into developing NSAPI functions, or you're at least looking at them seriously, you should be aware of a couple of points that will affect both how easy it will be to develop your solution and where you can use that solution. I describe these points in the following sections.
Who said, "You can't take it with you"? One of the great things about the NSAPI is that it's cross-platform. Currently, it is supported with Netscape products on several UNIX platforms as well as Windows NT, and that list is bound to grow with time. Because the internal function calls remain exactly the same from platform to platform, all you need to worry about is the C code that does the processing for your particular functions.
A growing amount of information is available on the NSAPI, but it is still in the early stages of development. You can obtain the best resources available through the Netscape Developer's program, called DevEdge, or through taking one of the Netscape training courses on the NSAPI, which were started in the second quarter of 1996. In public newsgroups, you also can find a number of people making use of the NSAPI, as it encompasses a wide range of programming topics. Secured newsgroups on Netscape's site, for registered developers, have a high turnout rate for questions and answers, and they provide the added benefit of serving as a link to Netscape support personnel and advanced developers.
A growing number of developers are also beginning to offer commercial services for functions such as helping you determine how you might move a CGI function into NSAPI functionality or designing server extensions from the ground up.
API programming is much easier to approach if you're already a C programmer. If you are, you're well on your way to taking advantage of all the power that API has to offer. If you're not a C programmer, however, or you work with a group with limited time for developing constantly changing functions, you may want to consider how you would go about making NSAPI functions and whether they're worth the time and effort. CGI programming still maintains one significant advantage over API programming-it's easy to do, in any language. If all your development experience is in Perl, you may not be willing to invest the considerable time and frustration it will take to learn C and become fluent enough in it to code advanced and robust functions. For many people, this decision will be the biggest obstacle to developing their functions and one of the factors that will limit API development impact on the general server marketplace.
With all the resources available and with training under your belt, you might begin to wonder if API programming is a good direction to be going in. After all, programming these functions is very specific to servers that support the NSAPI standard, and this programming is somewhat involved. Is it worth all the effort? The answer to this question depends on whom you ask, but the majority opinion is that this type of programming is definitely an area in which you should become well versed. CGI will probably never go away. Its quick and dirty, easily implemented data processing functions are always needed, and it's just way too much fun. Corporate-level solutions, however, are increasingly demanding and increasingly standards oriented.
To debug a built-in server function, you must rely heavily on your faith in your code because some possible symptoms can occur due to an errant return from your code or a slight error in placing data within a pblock. One of the best considerations is to include a logging function within your function so that a look at the system's error logs can at least help you pinpoint if your function is doing anything and what data it has.
Here is one relatively common pitfall to avoid when calling NSAPI functions through references in an HTML page. When they're being referenced in a form element like this
<FORM METHOD="POST" ACTION="/cgi-bin/nsapi/blah.useaction">
you must have a file called blah.useaction in /cgi-bin/nsapi. The file doesn't need to have anything in it (it can be a shopping list or a doghouse blueprint), but the file itself needs to exist because the server first checks the validity of the file by using the PathCheck class. If the server doesn't see a file there, it fails and doesn't do what you want it to do.
Standards are a big issue when it comes to the Internet. All companies want their technology to be the one that everyone else adopts because money rides on being the leader. To this point, Netscape has dominated the commercial sector in developing Internet standards, or at least close enough to it that they might as well be the leader. By proposing the NSAPI as a standard, the folks at Netscape have positioned themselves to try to take the lead in server extensions, just as they have in creating demand for the HTML tags that they've adopted ahead of scheduled standards implementation.
The NSAPI is not alone in the race for standardization, however. The Internet Server API (ISAPI), created by Microsoft and Process Software (see Chapter 25 for more details on ISAPI), is generating its own band of followers. In addition, other entries into the fray exist as well, either existing as something similar to NSAPI or ISAPI or as something completely different. In the face of competition from two industry giants, though, how can standardization of other entries succeed when they aren't part of either larger camp's proposal?
Would it be possible to meet somewhere in the middle? Not easily, and not likely. The NSAPI is heavily tied to the inner workings of the server itself, relying on the obj.conf and magnus.conf files, whereas the ISAPI standard goes more along the line of Microsoft's traditional DLL additions with message hooks.
Who has the advantage? Again, the answer to this question depends on whom you ask. Independent research agencies have reported conflicting information about who's in the lead and which implementation of the API functions is better suited for standardization. The real advantage, however, currently lies in the Netscape camp because of cross-platform capabilities. Microsoft's push is currently for NT as a substitute server platform for UNIX, but with the number of UNIX boxes already in use, a large and stubborn group of the more advanced developers doesn't want to switch platforms and server software just to take advantage of the API functions.
I'm not saying that the battle for who's in the lead is over, by any means. Microsoft has never been shy about pursuing its goals for market share, and if they feel that they're at a disadvantage, they'll fight even harder to become top dog. For the moment, however, Netscape maintains the edge that may well determine what direction the more serious developers go in.
Is all this competition good news for you, as an individual? Sure. It means that more powerful functions will surely be developed for a whole range of Web servers. If you're a developer, you've got a new marketplace to play in. If you're a user, many of the tasks that you perform on the Web could become faster and more powerful. No matter from which angle you look at this competition, it's a win-win situation for everyone.
The Netscape Server API is a powerful tool for customizing your Web server and making it jump through the hoops you need it to. NSAPI is not a replacement for CGI because people will always have a need for the role CGI plays. But NSAPI can perform the same functions, be called in the same manner, and do it all with less work for your server. These benefits are balanced by its being harder for developers to get up to speed and create stable functions. After you're familiar with the way NSAPI works and have had the chance to experiment, you'll understand why it's a great tool to have around.