|
DevEdge Online Archive
The current DevEdge site has moved! Please bookmark http://devedge.netscape.com.
|
|
The function you write for NSAPI is called a server application function (SAF). SAFs are directive functions. You can have any number of SAFs plus other C functions in your program. The function that interfaces with the server, however, must be a server application function. Because the SAF is the function that is invoked by the server, you should begin writing your program by writing an SAF. Although an SAF should be the starting point of your program, your program can include a number of different SAFs. You can write a program that includes multiple server directive functions. These functions can work together to provide the specific features you need. The server passes information (for example, server variables and the client's input) to the SAF. The SAF can also return appropriate responses to the server. An SAF can be an AuthTrans, NameTrans, or other directive's function. For example, you can write a Service function that processes a client's request. This function may call other C functions to read from and write to a file to process the request. The SAF can then return the appropriate response to the server.
To write an SAF, you first must decide which functionality you need and match it to a directive. You provide the added functionality by plugging your directive function (your SAF) into the server. Similar to how you add the built-in (predefined) server functions, you also add your SAF to the obj.conf file, where a directive function like yours belongs (Figure 1). The SAF can accomplish more than what a CGI function does (that is, reading input from a client, processing the client's request, and sending dynamic pages to the client). For example, you may want to write a customized authentication or logging function. You may even want to add features to the server, which a CGI program can later use.

Here, we will focus on Service functions. A Service function provides similar capabilities as a CGI program. It allows you to create a dynamic site, with the added benefit of supporting persistent data. You can use the information in this article to transfer your existing CGI programs or skills to write an NSAPI program.
Figure 2 provides an overview of how data are sent back and forth between the server and your server application function. In this article, we will discuss how to send data to and how to read data from the server. We will go through the steps for writing a simple SAF, Hello Client. We will also review how you can obtain data from the server, including the equivalent value of a CGI environment variable, using NSAPI functions.

The declaration of your SAF is based on how server functions are defined by Netscape. If you look in the server header file (for example, the nsapi.h file for Server 3.x or the func.h file for Server 2.x), you will find the following code:
#ifdef XP_UNIX typedef int Func(pblock *, Session *, Request *); #else /* XP_WIN32 */ typedef int _cdecl Func(pblock *, Session *, Request *); #endif
An SAF should have the following format:
NSAPI_PUBLIC int <function name>(pblock *<param>, Session *<sn>, Request *<rq>);
As you can see, we defined the SAF declaration by following the same format as the Func definition does. You declare your function as type NSAPI_PUBLIC, with three predefined parameters and an integer as the return value. The server uses the functions defined in the obj.conf file to create a hash table of function declarations at the start of the server. The server looks for your SAF function in the obj.conf file to link to it.
Netscape NSAPI functions are declared as type NSAPI_PUBLIC so that your functions can use them. You also declare your function as type NSAPI_PUBLIC to allow the server to recognize it and link to it. These functions are then compiled into shared libraries for Unix or DLLs for NT. For example, for NT NSAPI_PUBLIC is defined as __declspec(dllexport). This declaration is an extension to the C language for Windows programs. __declspec is a Microsoft-specific keyword that is used to qualify an extended attribute as a Microsoft-specific storage-class attribute. dllexport explicitly declares your function as exportable, enabling it to be exported from your DLL. Thus your function will become accessible to Netscape Server.
The parameters of an SAF are pointers to the three data structure types found in the server's header files. The first parameter of an SAF function stores the variables (parameters) defined for your function in the obj.conf file. When the server invokes your SAF (which you have placed in the obj.conf file), it passes the parameters defined there to your SAF through the first parameter (pblock *<param>). For an AuthTrans user-defined basic-auth function, an SAF's first parameter can also include other useful variables, such as the user name and password. The second parameter, Session, holds the session-specific data. This data structure includes data that are applicable session-wide (that is, from the opening to the closing of the connection between the client and the server). The third parameter, the Request data structure, holds request-specific information. With the exception of global server variables, you get all other relevant data from the server through these three data structures.
In this article, we use Session and Request to refer to the data structures you will use in your program. In other words, we use Session->client to refer to the client pblock in the Session data structure. Because Session and Request are the reserved names for the internal server data structure, however, you must replace Session and Request with your own specified SAF parameter names. For example, in your code you might use sn->client but not Session->client. We will use param, sn, and rq for the three parameters of our SAF. These parameters are pointers to the internal server data structures.
Your function should return an integer, the value of which is defined by the server. The server uses this return value to determine which action it should take. You should return REQ_PROCEED upon success. REQ_NOACTION is returned when, although no error has occurred, the function does not perform the expected action for the directive. REQ_ABORTED or REQ_EXIT is returned upon error. REQ_ABORTED does not abort the session, but rather aborts the request and begins returning the error page. REQ_EXIT is used for more severe cases when you wish your function to close the session and exit immediately.
Although your function's name can include only underscores (_) in its name, the name you use in the obj.conf file can include either underscores or dashes (-). (Under Server 1.x, you needed to replace underscores with dashes in the name of the function in the configuration file.) No matter which convention you use to refer to your function in the configuration file (obj.conf), make sure that it is the same for all references to your function in the configuration file. Also, make sure that the name of your function is unique and does not conflict with any built-in server function.
You normally write your NSAPI program in ANSI C. Although Netscape expects a C function for the SAF, you may be able to write your code using C++. To use C++, you should use C linkage (extern "C"). This option allows your C++ module to communicate with the C interface of Netscape's SAF. It allows you to compile your code using a C++ compiler. The compiler will then use the C naming convention and C linkage instead of the C++ type-safe naming (naming decoration) and C++ calling convention. This choice allows the server to use the right convention and symbols at load time. Declare your SAF and the include files inside extern "C" brackets.
extern "C"
{
#include "nsapi.h"
NSAPI_PUBLIC yourSAF(pblock *param, Session *sn, Request *rq)
{
/* Your code */
}
}
You cannot use exception handling when writing your NSAPI in C++. You must disable default exceptions generated by the compiler.
To use the server data structures and functions, you should include the pblock.h, session.h, and req.h header files when compiling your SAF function for Servers 1.x and 2.x. These files are the standard header files needed for an SAF. session.h and req.h include the appropriate Session and Request data structures plus a number of other relevant functions. pblock.h includes the pblock functions and data structure.
For Server 3.x, you need to include only the nsapi.h file. All NSAPI functions and data structures are defined in this file. Because Server 3.x includes header files with the same name as the earlier header files, you can still use the earlier include directives (for example, #include "base/pblock.h") when compiling your program for Server 3.x. For Server 3.x, these header files indirectly include the nsapi.h file. (As already mentioned, for backward-compatibility reasons, Server 3.x includes header files with the same name as the 2.x header files. These files simply include the nsapi.h file [#include "nsapi.h"].) You may opt to use the same include directives as Server 2.x for Server 3.x if you plan to write a program that can be compiled for both servers.
Under Servers 1.x and 2.x, there are a number of interdependencies between the various Netscape header files. Therefore, you may find that including one file may include a number of other header files. For example, pblock.h includes netsite.h, which, in turn, includes systems.h and version.h. So, by including pblock.h you also include another important file: netsite.h. In fact, by just including req.h, you already include netsite.h, pblock.h, and session.h. Nevertheless, for general compatibility, you should follow the suggestion of Netscape and include all three files for Servers 1.x and 2.x.
As with CGI, there are three types of information you can return to the client. You can return a dynamically generated page, redirect the client to an already existing page, or return an error page containing the default error status and an explanation. Unlike with CGI, you cannot simply use the printf function to write to the client. To write to the client, you must use functions such as net_write, netbuf_buf2sd, and filebuf_buf2sd. With NSAPI, you are not simply using stdin and stdout to communicate with the client. Instead, you use the access to the client's socket and to the network buffer to return data.
To write a page to the client, you usually take a series of steps. These steps send an HTML or text page to the client. It is not always necessary to take all these steps, as your function may use features that do not require every step. You can also reorder the following steps to suit your needs. For example, you can generate the response (Step 6), before sending the Status-Line and other response headers (Step 5). Nevertheless, it is important to review these steps and understand them before you make any changes. Some of these steps must precede others. For instance, you should not insert a response header (Step 3) after you have already sent the headers (Step 5). You should also look at Listing 1 to see these steps in action. We will refer to this example as we go through each step.
As with any HTTP response, the server must return the Status-Line (that is, HTTP-Version Status-Code Reason-Phrase CRLF) as the first line of the response message. For NSAPI, you use protocol_status to set the Status-Line of the response. The server must also return any necessary HTTP response-headers (for example, WWW-Authenticate, Location, and so on), plus HTTP entity-headers (such as content-type, content-length, and last-modified). Response-headers provide additional information about the response that the server sends. They usually include information about access and the server. Entity-headers give additional information about the entity-body or message-body (the data) being sent or the resources requested by the client. They are intended to help the client recognize and process the data correctly. You normally do not have to set most of these headers. You do, however, need to take care of the content-type of the data being sent and the right status code. Netscape keeps the response-header and entity-headers in one pblock, srvhdrs, in the Request data structure. Thus all the headers you may want to send to the client should be inserted into Request->srvhdrs. In this article, we will usually refer to all of the headers (found in Request->srvhdrs) that your server may return to the client as response-headers.
When responding to a client as part of a CGI program, you return the content-type. Normally, you do the same with an NSAPI function. Before your Service function is invoked, however, a content-type is already set by the ObjectType directive. The magnus-internal MIME type defined for your function is already set as a content-type. Because a content-type is already specified, you must first remove the existing content-type before setting the one to be returned to the client. You do not have to take this step for CGI programs, as the Service function send-cgi takes care of setting the content-type for these programs.
If you do not remove the existing content-type, and simply attempt to insert a new content-type, the server will successfully place the new content-type in the pblock for a response header. When the server returns the content-type, however, it returns the first content-type in the Request->srvhdrs pblock - your function's content-type. Because the client's browser will not recognize a magnus-internal content type, it will not correctly process and display the file you are sending. The browser will either display an error message, saying it could not open the Internet site (as with Internet Explorer 3.x), or ask the client to specify the unknown file type (as with Netscape Navigator). (You can test for this condition by removing the line param_free(pblock_remove("content-type", rq->srvhdrs)); from the Hello Client example given later in this article.)
The MIME type (the request entity-header content-type) that the client uses to invoke your application (magnus-internal MIME type) is different from the MIME types that the client can accept as a response entity-header. As with CGI programs, the client requests a MIME type that your server recognizes and processes correctly (for example, magnus-internal/cgi for CGI applications). The CGI program or your SAF then returns a type of document (content-type) that the client can accept and process correctly.
To remove the content-type, use the pblock_remove function and pass it the name of the pblock entry (content-type) and the pblock for response headers (Request->srvhdrs). Removing a pblock entry does not free (deallocate) the memory used by the entry. param_free frees the pblock entry you have removed.
Once you have removed the pblock entry content-type, you can use pblock_nvinsert to insert the new content-type (that is, the type of data you are sending). For pblock_nvinsert, you specify the name and value of the pblock entry and the actual pblock into which they should be inserted. In the Hello Client example, we will insert the content type text/html, as we are sending an HTML file. You may also want to send other headers to the client. In that case, you can insert them in the same way we inserted the content-type header after you inserted the response's content-type. If the header you are returning is not already defined, then you do not need to worry about removing it from the Request->srvhdrs pblock. If it does exist, however, then you must take the same steps as we took with content-type. An example of another type of header you may want to insert is a cookie. Cookies are special tokens that can be saved on the client's machine. The client returns the value of these cookies to your server when it makes a request. To send a cookie response header, you insert the header set-cookie with the appropriate parameters.
You may also want to set the content-length header. This information is used by the client and the server to establish a Keep-Alive or persistent connection. With Keep-Alive, a session connection can be kept open while a multipart request is processed. For example, a page with embedded images can be delivered in one connection. Without content-length, the server does not keep the connection alive. If you wish to use this feature, then you must send content-length with the rest of the response headers. If the value of content-length that you want to set is an integer, you should use pblock_nninsert instead of pblock_nvinsert. pblock_nninsert expects an integer for its value parameter.
Once you have inserted the appropriate headers, you are ready to set the status to OK. You should send this status when everything has gone well and you are ready to return a page. The protocol_status function sets the status to be returned to the client. The server then creates the Status-Line to send to the client. You also use this function to return an error status. The status type is defined in the third parameter of the protocol_status (for example, PROTOCOL_OK). The fourth parameter is reserved for a descriptive reason string that should be returned with the page. This parameter can be used when you are sending an error status and you want to send added information about the error to the client. If you specify NULL for the fourth parameter, the server sends the default description for the status code. In the case of PROTOCOL_OK (status code 200), you should set the parameter to NULL and have the server send the default description, OK. After all, you will send the actual data through your program, not a predefined server error page. The Status-Line 200 OK means that the request was successfully processed. We will discuss the various server status codes and how to send an error page shortly.
Now you are ready to send the headers to the client with protocol_start_response. These headers include the Status-Line and any other appropriate response-headers or entity-headers. Besides content-type and status, you normally do not need to worry about any other header, unless you are interested in changing or sending a specific header, such as content-length. content-length is used by the client and server to keep a connection alive with a Keep-Alive or persistent connection. If the server does not send content-length and you want the server to use the Keep-Alive feature or support persistent connection, you must insert content-length yourself. After protocol_start_response, you are ready to send the entity-body. The client is now also waiting to receive the actual content. In the Hello Client example, we will send the HTML page with the word "Hello" plus the client's IP address.
protocol_start_response also returns REQ_NOACTION if the request is a HEAD method of request. You should check for this value so as not to return data to the client. A HEAD request means that the client wants the headers but not the entity-body (for example, the actual Hello Client page). If the protocol_start_response returns REQ_NOACTION, your SAF should send a return of REQ_PROCEED. The server then stops and will not continue with the rest of the code. The following code gives an example of this process:
if(protocol_start_response(sn, rq) == REQ_NOACTION)
{
/* You should first free any allocated memory, close any
file, and so on, before exiting. */
return REQ_PROCEED;
}
In Hello Client, we will use util_sprintf to create the buf string that is sent to the client. The util_sprintf function also formats the string. Hence, we can use the %s format to include the IP address (which is a string) in the HTML page we are returning to the client. This process is similar to the way in which printf works. We also use the util_sprintf function's return variable length to specify the size of the data we are returning. You could also use the C function strlen to get the length of this buffer string.
In your program, you may use the length of the dynamically generated response to specify the content-length response-header that is sent to the client. You must set the response-headers before you use protocol_start_response. If you want to use the value of length returned by the util_sprintf function, for example, you need to set content-length before Step 5. For example, you can create the response (Step 6) and set content-length before setting the status to OK (Step 4) and sending the Status-Line and response-headers to the client (Step 5). You should also use pblock_nninsert instead of pblock_nvinsert. pblock_nvinsert expects a string for its value parameter. For the Hello Client example (Listing 1), we do not set content-length, as this step is not necessary for this example.
net_write writes the buffer we received from util_sprintf to the client's socket. You do not use a stdout function as you would with a CGI program. An NSAPI function does not use stdin and stdout to read from and write to the server. Your function is built into the server and has access to the same data as the server can access. Thus you actually write to the client's socket. This approach has the added benefit of allowing you to write a function that takes advantage of the socket connection between the client and the server. The client's socket is available through the Session->csd variable (sn->csd in the Hello Client example in Listing 1). For net_write, you also specify information about the buffer's string (buf) and its length.
You should check for any errors while writing to the client's socket. net_write returns IO_ERROR if an error occurs. In case of error, your function should return REQ_EXIT, which stops the processing of the request.
Other functions that can be used to send a buffer to the client are netbuf_buf2sd (netbuf_buf2sd(netbuf *buf, SYS_NETFD sd, int len)) and filebuf_buf2sd (filebuf_buf2sd(filebuffer *buf, SYS_NETFD SD)). netbuf_buf2sd sends a buffer, usually previously read, to the socket. filebuf_buf2sd sends the contents of the specified file to the socket, as long as nothing was read from the filebuffer.
If everything went as planned, we return REQ_PROCEED. For a Service function, this return usually means the server has finished processing the request. If your Service function processes a request, no other Service function is called by the server.
If you are using a version of Netscape Server earlier than Server 3.x, use the following code instead of the include directive in Listing 1.
/* The following three files are the standard header files
needed for the SAF. */
#include "base/pblock.h"
#include "base/session.h"
#include "frame/req.h"
#include "base/util.h" /* util_sprintf */
#include "frame/protocol.h" /* protocol_start_response
protocol_status */
/* Include this file if you are using Server 3.x. */
#include "nsapi.h"
/* This function sends an HTML page to the client. */
NSAPI_PUBLIC int hello_client(pblock *param, Session *sn, Request *rq)
{
char *client; /* Holds the client IP address. */
char *buf; /* A buffer to be sent to the client. */
int length; /* Size of buffer. */
/* Get client's IP address from Session's client pblock. */
client = pblock_findval("ip", sn->client);
/* Begin returning the HTML page. */
/* Get rid of internal content type - usually the
SAF's magnus-internal content type. */
param_free(pblock_remove("content-type", rq->srvhdrs));
/* Set content type to html. */
pblock_nvinsert("content-type", "text/html", rq->srvhdrs);
/* Set status to OK. */
protocol_status(sn, rq, PROTOCOL_OK, NULL);
/* Send the headers and get ready for sending the page. */
protocol_start_response(sn, rq);
/* MALLOC a rough size for buffer. */
buf = (char *) MALLOC(100 * sizeof(char));
/* Put all the variables and the rest of the HTML page
information into one buffer. */
length = util_sprintf(buf,
"<HTML><HEAD>"
"<TITLE>Hello</TITLE>"
"</HEAD>\n"
"<BODY><H1>"
"Hello %s</H1>\n"
"</BODY></HTML>", client);
/* Send the information to the client. Also check
for any error while sending the page to the client.
If an error occurred, exit. */
if(net_write(sn->csd, buf, length) == IO_ERROR)
{
return REQ_EXIT;
}
/* Return success to the server. */
return REQ_PROCEED;
}
Listing 1 includes some actions that were not discussed in the nine steps given earlier. For example, we use pblock_findval to get the IP address of the client from the server's Session data structure's client pblock (sn->client). We will shortly go through all the various data available from the server and how you can access them using NSAPI functions. Also, with util_sprintf, you must make sure the size of the string (buf) is large enough to hold the formatted string. Listing 1 does not do any bounds checking. Use util_snprintf if you need to perform this step.
Besides returning a document or redirecting a client, you may wish to return an error page. You can specify the type of error code and provide a reason for the error by using protocol_status. Just as we returned status OK (or 302 Found) with protocol_status, you can return other HTTP status codes as well. After your program inserts the status code using protocol_status and exits, the server finishes processing the request and returns an appropriate page to the client. The server usually does this task automatically without you having to define an Error directive function. The following demonstrates the protocol_status:
protocol_status(sn, rq, PROTOCOL_ UNAUTHORIZED, "You do not have the adequate access privileges");
The following is the definition of protocol_status. (For Server 2.x, you can find the definition in the httpd.h file under the nsapi/include/frames directory.)
#define protocol_status http_status NSAPI_PUBLIC void http_status(Session *sn, Request *rq, int n, char *r);
As you can see, protocol_status is a redefinition of http_status. The function protocol_status sets the status code through the n parameter. It also returns the string pointed to by the r parameter as the description (reasoning) of the status. Normally, the description is returned with the rest of the error page to the client. Your error message - that is, the reasoning - will appear as HTML Heading 1. The standard error description defined for the status by the server follows. You can set the value for the fourth parameter, r, to NULL if you want the server to return only the predefined (default) reasoning. If no reason string is found for an error status code, the server returns Unknown reason as Heading 1 and An error has occurred as a further description. If the status code (n) is not defined, the server returns the default status code, PROTOCOL_SERVER_ERROR.
Protocol_status sets the status entry in the Request->srvhdrs. The status string includes both the status code and the reasoning. If no reason is specified, the string will include the default string for the status code. For example, the status string for the previously given protocol_status function will be
"401 You do not have the adequate access privileges"
You should use this function frequently - whenever you include error-checking code and wish to inform the client of the type of error that occurred. This function typically works in concert with the log_error function, which logs error information in the errors log file.
Your SAF needs data of different types, available through different methods, to process a client request. Global server variables are available globally or through the configuration data structure (conf_global_vars_s). You can also place parameters for your function in the configuration file that your SAF accesses through its first parameter (pblock * <param>). Other variables, which are available through the Session and Request data structures passed to your function, are specific to a client or a request. You usually get client input through the GET and POST methods. Typically, you use a form to get the client's input. These variables are available through the query string found in Request->reqpb for the GET method, and in the network buffer for the POST method. Finally, in addition to the data received from the server, you may need data from other sources, such as a database or file. For example, you may need to access a database to get the response for a client request.
Table 1 lists the common types of data provided by the server and available for use by your program. The table is organized by the type of information sought, not necessarily by the location of the data.
|
|
|
Global server information, some of which is set in the magnus.conf file (for example, server name or port) Information in the obj.conf file, especially your user-defined SAF parameters |
|
|
|
Client information (for example, client IP or DNS address, user name and password, or browser name) Information about the requested resource (for example, content type or path information) Additional request headers (for example, type of connection or cookie information) |
|
|
|
Input from a GET method (query string sent with the request) Input from a POST method (data provided through the network buffer) |
With CGI programs, it is easy to access the environment variables as they are all accessed via the same function. (For example, the getenv function is used for CGI programs written in C.) With NSAPI, these same variables are located mostly in different pblock data structures available through the Session and Request data structures. The pblock data structure holds a hash table of name/value pairs that resembles an environment-variable linked list. The requirement that you access variables through different data structures or functions may seem complicated and confusing to CGI programmers. We will try to make this transition easier by providing an overview of how you obtain data from the server.
With a typical CGI program, you get most of the data through the environment variables or through stdin. In this case, the environment variables are processed by the server and then passed to your application. Because a CGI program is a separate application spawned by the server, the relevant information must be passed to the CGI program through specific channels. Environment variables furnish an easy way to accomplish this task. NSAPI programs, however, access these variables as they appear to the server. An SAF, which works in the server process, has access to and can change the actual server variables. Moreover, information available to an NSAPI function may not be available to a CGI program. The value of a variable can also change before it becomes available to an SAF or a CGI program. A variable can be available for one directive and not another. A variable can also be changed in earlier directives for use by a later directive. For example, the physical path information (path) is derived from the ppath variables of Request->vars and a base directory of a NameTrans function. After the NameTrans directive is carried out, ppath is no longer available, whereas path becomes available for the later directives. In contrast, a CGI program is processed through the Service function send-cgi. Such a program cannot directly access or change the server variables that are available to send-cgi. Based on the directive function you write, your SAF, however, can access a specific subset of server variables. It can also change these variables and thereby affect how the rest of the server directives process a request.
NSAPI variables are available as they were intended for the server. In other words, they are organized based on the categorization appropriate for the server's processing of a request. Although variables passed to a CGI program are of different types (some include global server information, while others include specific request data), they are all environment variables, and are accessed through the same function. Netscape could have placed all of the NSAPI variables in a special parameter block and made it accessible to your program. Because the SAF uses the same information available to the server, however, these variables are not separated and parsed into one pblock for your function. For the server, the actual variables are of different types and are, therefore, processed in different data structures. For instance, a global server variable for the server port should be available through the server global variables and not through a specific request's variable. This strategy permits the tailored sharing of data and removes redundancy.
Other factors distinguish environment variables from NSAPI variables. For example, some environment variables (such as GATEWAY_INTERFACE) are not relevant to an NSAPI program. Moreover, NSAPI variables, unlike environment variables, appear as they are defined by HTTP protocol or Netscape Server. These variables are not converted to uppercase and do not use underscores. In place of underscores (_), dashes (-) are used to separate compound names. Also, the HTTP request header variables do not include the prefix HTTP_.
Table 2 provides a quick overview of the CGI environment variables and their equivalent NSAPI variables. param, rq, and sn represent the names of the parameters of the SAF, as in NSAPI_PUBLIC int hello_client(pblock *param, Session *sn, Request *rq). The NSAPI information is also based on Servers 2.x and 3.x.
|
|
||
|
CGI environment variable |
NSAPI variables |
Location of NSAPI variables |
|
What it gives you |
How to access NSAPI variables - an example |
|
|
|
Notes |
|
|
|
||
|
GATEWAY_INTERFACE |
None |
|
|
CGI version information (for example, CGI/1.1) |
|
|
|
|
Specific to CGI and not relevant to NSAPI. |
|
|
SERVER_NAME |
server_hostname (global) |
Global variable (also through conf_global_vars_s) |
|
Server hostname or IP address (for example, www.foo.com) |
conf_getglobals()->Vserver_hostname |
|
|
|
You can get the server name in a number of ways. For example, you can get the value through the conf_global_vars_s data structures or as a global variable, server_hostname. You can also use the util_hostname function to get the host name. (Make sure to compile your program with the NET_SSL compiler switch for 2.x Server. Otherwise, the structure is offset and you may retrieve NULL when attempting to retrieve the host name.) |
|
|
SERVER_SOFTWARE |
MAGNUS_VERSION_STRING (for Server 2.x) <version> (for Server 3.x) |
Global variable for Server 2.x Use system_version for Server 3.x. |
|
Server software name and version (for example, Netscape-Enterprise/3.6) |
char *version = system_version(); (Server 3.x) |
|
|
|
Under Server 2.x, server software information is optioned through the global variable MAGNUS_VERSION_STRING. This variable is no longer available under Server 3.x. Under Server 3.x, however, you can use the new function system_version to get the server software information. |
|
|
|
||
|
AUTH_TYPE |
auth-type |
Request->vars |
|
Authentication type (for example, Basic) |
char *type = pblock_findval("auth-type", rq->vars); |
|
|
CONTENT_ENCODING |
content-encoding |
Request->headers |
|
Content encoding type sent by the client (for example, x-gzip) |
request_header("content-encoding", &hvalue, sn, rq); (hvalue holds the content-encoding value.) |
|
|
|
The desired method of accessing pblock headers entries is through the request_header function, but you can also access the value with the pblock_findval function. The variables content-encoding, content-length, and content-type defined in Request->headers are different from the variables of the same names defined for Request->srvhdrs. These HTTP variables (headers) are sent by the client to the server. The server headers (srvhdrs) are sent by the server to the client. |
|
|
CONTENT_LENGTH |
content-length |
Request->headers |
|
Content length information sent by the client (for example, 1020) |
request_header("content-length", &hvalue, sn, rq); (hvalue holds the content-length value.) |
|
|
|
See CONTENT_ENCODING. |
|
|
CONTENT_TYPE |
content-type |
Request->headers |
|
Content type send by client (for example, application/x-www-form-urlencoded) |
request_header("content-type", &hvalue, sn, rq); (hvalue holds the content-type value.) |
|
|
|
See CONTENT_ENCODING. |
|
|
PATH_INFO |
path-info |
Request->vars (available after PathCheck function find-pathinfo is run) |
|
Extended path information (for example, <http://www.foo.com/get.exe>/data/id.txt) |
char *extra_path = pblock_findval("path-info", rq->vars); |
|
|
|
Although this value is available in the Request pblock vars, you cannot actually use extended path as part of the URL of an NSAPI Service program. Any extended path is seen as part of the actual requested path. Consequently, the server looks for the extended path instead of your program. To pass values such as extra path information, use additional parameters for the NSAPI function found in the obj.conf file. These variables can then be accessed through the pblock parameter (param) that is passed onto your program. |
|
|
PATH_TRANSLATED |
None |
|
|
Extended path information translated into full physical path (for example, c:/net/data/id.txt) |
|
|
|
|
See PATH_INFO for more information. The server goes through the directives a second time to translate the path found in path-info into a physical path, that is, PATH_TRANSLATED. This information is then passed onto the CGI program as an environment variable. For NSAPI, if you wish to convert a partial path (for example, PATH_INFO) to a complete physical path, you can use the NSAPI function servact_translate_uri (also defined as request_translate_uri). This function was removed from the main NSAPI functions under Server 3.0x. The NSAPI library file (ns-httpd30.lib), however, may still include it. Otherwise, for Server 3.0x, you need to write your own function to translate a URI path to a physical path. Servers 3.5.1 and 3.6 do include this function. |
|
|
QUERY_STRING |
query |
Request->reqpb |
|
Query string sent by the client (for example, <NSAPI program path>?name=joe) |
char *query = pblock_findval("query", rq->reqpb); |
|
|
REMOTE_ADDR |
ip |
Session->client |
|
Remote client's IP address (for example, 1.2.3.4) |
char *ip = pblock_findval("ip", sn->client); |
|
|
REMOTE_HOST |
dns |
Session->client |
|
Remote client's DNS address (for example, www.foo.com) |
char *client_dns = session_dns(sn); (sn is the current Session data structure.) |
|
|
|
You should use the session_dns or session_maxdns functions to access the DNS information of the client instead of using the pblock_findval function. If these functions are not called, the dns variable is not inserted in theRequest->Client. You also need to have DNS enabled for this value to be available. |
|
|
REMOTE_USER (AUTH_USER) |
auth-user |
Request->vars |
|
Name of the authenticated user (for example, Joe) |
char *type = pblock_findval("auth-user", rq->vars); |
|
|
|
This variable is actually the environment variable AUTH_USER, which is equivalent to REMOTE_USER. For Enterprise Server, the value of auth-user and REMOTE_USER would be the same as the UID (User ID) defined in the directory server. |
|
|
REQUEST_METHOD |
method |
Request->reqpb |
|
Client's request method (for example, GET) |
char *method = pblock_findval("method", rq->reqpb); |
|
|
SCRIPT_NAME |
uri |
Request->reqpb |
|
Virtual (relative) path to the requested program (for example, /get.env) |
char *program_path = pblock_findval("uri", rq->reqpb); |
|
|
|
This path is used by the client to call your program - that is, the virtual (partial) path to your NSAPI program. |
|
|
SERVER_PORT |
Vport |
conf_global_vars_s |
|
Port address where the request is sent (for example, 80) |
int port_num = conf_getglobals()->Vport; |
|
|
|
There is also a global variable for the server port that you can use. Under Server 2.x, port is defined as an extern int in the conf.h header file. You can directly access the value of the server port using the global variable port. Under Server 3.x, you can use the global variable server_portnum. |
|
|
SERVER_PROTOCOL |
protocol |
Request->reqpb |
|
Version of protocol being used by the client (for example, HTTP/1.0) |
char *protocol = pblock_findval("protocol", rq->reqpb); |
|
|
|
||
|
HTTP_ACCEPT |
accept |
Request->headers |
|
Mime types accepted by the client's browser (for example, image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*) |
request_header("accept", &hvalue, sn, rq); (hvalue holds the accept value.) |
|
|
|
The correct method of accessing a pblock headers entry is through request_header. But, you can also access the variable with pblock_findval. |
|
|
HTTP_CONNECTION |
connection |
Request->headers |
|
Verifies if the connection is kept open - that is, whether Keep-Alive or persistent connection is used (for example, Keep-Alive) |
request_header("connection", &hvalue, sn, rq); (hvalue holds the connection value.) |
|
|
|
See HTTP_ACCEPT. |
|
|
HTTP_COOKIE |
cookie |
Request->headers |
|
Cookie data sent by the client. The data must originally be set by your server. (for example, User=JoeBoxer) |
request_header("cookie", &hvalue, sn, rq); (hvalue holds the cookie value.) |
|
|
|
See HTTP_ACCEPT. |
|
|
HTTP_FROM |
No longer supported |
|
|
|
|
|
|
HTTP_IF_MODIFIED_SINCE |
if-modified-since |
Request->headers |
|
Date sent by the client. It is used to verify whether data should be sent. (for example, Monday, 1-Jan-96 12:00:00 GMT) |
request_header("if-modified-since", &hvalue, sn, rq); (hvalue holds the if-modified-since value.) |
|
|
|
See HTTP_ACCEPT. |
|
|
HTTP_REFERER |
referer |
Request->headers |
|
URL from which the request came (for example, http://www.yahoo.com) |
request_header("referer", &hvalue, sn, rq); (hvalue holds the referer value.) |
|
|
|
See HTTP_ACCEPT. |
|
|
HTTP_USER_AGENT |
user-agent |
Request->headers |
|
Name of the client's browser (for example, Mozilla/4.07 [en] (WinNT; I)) |
request_header("user-agent", &hvalue, sn, rq); (hvalue holds the user-agent value.) |
|
|
|
See HTTP_ACCEPT. |
|
|
|
||
|
HTTPS |
security_active |
Global variable (conf_global_vars_s) |
|
Determines whether SSL security is enabled |
conf_getglobals()->Vsecurity_active; |
|
|
|
The variable security_active is not defined if the NET_SSL compiler switch is not specified for Server 1.x and 2.x. You should compile with NET_SSL options to make sure all SSL variables are available. Otherwise, for Server 2.x, the data structure conf_global_vars_s is offset. The default makefile that comes with the Netscape Server 1.x and 2.x does not include this switch. For Enterprise Server 3.x, you no longer need to use the NET_SSL compiler switch. |
|
|
HTTPS_KEYSIZE |
keysize |
Session->client |
|
Bit size of session key used for encryption (for example, 128) |
char *k = pblock_findval("keysize", sn->client); |
|
|
|
SSL must be enabled. |
|
|
HTTPS_SECRETSIZE |
secret-keysize |
Session->client |
|
Bit size used to generate the server private key (for example, 128) |
char *sk = pblock_findval("secret-keysize", sn->client); |
|
|
|
SSL must be enabled. |
|
|
HTTPS_SESSIONID |
ssl-id |
Session->client |
|
Base64 encoding of the SSL session value (for example, B+rZPf11DpxjCWGst6iFA |
char *sid = pblock_findval("ssl-id", sn->client); |
|
|
|
To have access to ssl-id, you must add the AuthTrans function get-sslid to the obj.conf file. SSL must also be enabled. |
|
|
|
||
|
Other Parameters |
[your parameter name] |
param (first parameter of your SAF) |
|
Extra parameters sent through obj.conf file |
char *extra = pblock_findval("extras", param); |
|
|
|
When you install your SAF, you can define a number of parameters in [name]="[value]" pairs in the obj.conf file. You then access these parameters from the pblock structure using pblock_findval. The parameters are passed onto your function through the first parameter of your function. |
|
The categories of the CGI environment variables used in Table 2 are based on the original groupings of the CGI environment variables as defined by NCSA. With NSAPI, we must consider variables a bit differently. The following categories are based on how you obtain the NSAPI variables from the server. The four types of NSAPI variables are available as global variables, and through the data structures Session, Request, and param. Session, Request, and param are parameters passed to your function. As well as the four types of variables, you also have access to the socket and network buffer. The input from a POST method of request is usually accessed through the network buffer. You read the data from the network buffer using NSAPI functions (for example, netbuf_getc).
The following are the types of NSAPI variables.
The Session data structure holds variables that apply to the entire session. It includes session information about the client (that is, information about the IP and DNS of the client), plus the SSL security information (for example, keysize). These variables are kept in the client pblock. The information available through the Session data structure is meant to apply to the entire session with the client, not just a single request.
Session->client
You get the IP address by using pblock_findval("ip", sn->client). The pblock_findval function finds the value of a specified name/value pair in a pblock. You specify the name as the first parameter and the client pblock as the second parameter; the function then returns the value. pblock_findval is used to get most of the values of the name/value pairs in a pblock. Although we will continue to use this function to obtain other values, we use the session_dns or session_maxdns function (char *session_dns(Session *sn)) to get the value of the client's DNS. session_dns gets the DNS host name from the client's IP for the session specified in its parameter and inserts the value in the client pblock. This function does the actual look-up of the client's DNS. You also must have the DNS enabled for the server. Session_dns returns the client's DNS number. You can also use session_maxdns to have the server look up and verify the client host name, providing for additional validation of the DNS.
The values for keysize, secret-keysize, cipher, ssl-id, issuer_dn, and user_dn can be obtained through the pblock_findval function. You must have SSL enabled for these variables to be present. Otherwise, the function returns NULL. For ssl-id, you must also add the AuthTrans function get-sslid to the obj.conf file. The distinguished name (DN) of the issuer of the client certificate (issuer_dn) and the client's distinguished name (user_dn) are available only with Enterprise Server 3.5.1 and later. For example, if you had issued a certificate using Netscape Certificate Server, the issuer_dn could be CN=my Certificate Server, O=my company, and the user_dn could be UID=jdoe CN=john doe O=my company. If no certificate is used, the values of these two entries will reflect no certificate. To have the client pblock include the issuer and user DN, you should require client certificate for all requests through the Server Manager's Server Preferences|Encryption Preferences menu.
The Request data structure holds variables that apply to a specific request. It includes three pblock data structures (vars, reqpb, and headers) that hold the NSAPI variables related to a client's request. These variables are request-specific headers. In this section, we will review each of these pblocks. The fourth pblock data structure (srvhdrs) holds the server response-headers. Each pblock holds a number of NSAPI variables.
Sample of Request->vars entries