Sun ONE Application Server 7 Developer's Guide to NSAPI |
Creating Custom SAFsThis module describes how to write your own NSAPI plugins that define custom Server Application Functions (SAFs). Creating plugins allows you to modify or extend the Sun ONE Application Server's built-in functionality. For example, you can modify the server to handle user authorization in a special way or generate dynamic HTML pages based on information in a database.
The sections in this module are:
- Future Compatibility Issues
- The SAF Interface
- SAF Parameters
- Result Codes
- Creating and Using Custom SAFs
- Overview of NSAPI C Functions
- Required Behavior of SAFs for Each Directive
- CGI to NSAPI Conversion
Before writing custom SAFs, you should familiarize yourself with the request handling process. Also, before writing a custom SAF, check if a built-in SAF already accomplishes the tasks you have in mind. After you write the SAF, you must add a directive to obj.conf so that your new function gets invoked by the server at the appropriate time.
See "Syntax and Use of obj.conf," and "Predefined SAFs and the Request Handling Process," for information about request handling, built-in SAFs, and the obj.conf file.
For a complete list of the NSAPI routines for implementing custom SAFs, see "NSAPI Function Reference."
Future Compatibility Issues
The NSAPI interface may change in a future version of Sun ONE Application Server. To keep your custom plugins upgradeable, do the following:
- Instruct plugin users how to edit the configuration files (such as init.conf and obj.conf) manually. Do not have the plugin installation software edit these configuration files.
- Keep the source code so you can recompile the plugin.
The SAF Interface
All SAFs (custom and built-in) have the same C interface regardless of the request-handling step for which they are written. They are small functions designed for a specific purpose within a specific request-response step. They receive parameters from the directive that invokes them in the obj.conf file, from the server, and from previous SAFs.
Here is the C interface for a SAF:
int function(pblock *pb, Session *sn, Request *rq);
The next section discusses the parameters in detail.
The SAF returns a result code which indicates whether and how it succeeded. The server uses the result code from each function to determine how to proceed with processing the request. See the section "Result Codes" for details of the result codes.
SAF Parameters
This section discusses the SAF parameters in detail. The parameters are:
- pb (parameter block)-- contains the parameters from the directive that invokes the SAF in the obj.conf file.
- sn (session)-- contains information relating to a single TCP/IP session.
- rq (request)-- contains information relating to the current request.
pb (parameter block)
The pb parameter is a pointer to a pblock data structure that contains values specified by the directive that invokes the SAF. A pblock data structure contains a series of name/value pairs.
For example, a directive that invokes the basic-nsca function might look like:
AuthTrans fn=basic-ncsa auth-type=basic
dbm=/Sun/AppServer7/domains/domain1/server1/userdb/rs
In this case, the pb parameter passed to basic-ncsa contains name/value pairs that correspond to auth-type=basic and dbm=/Sun/AppServer7/domains/domain1/server1/userdb/rs.
NSAPI provides a set of functions for working with pblock data structures. For example, pblock_findval() returns the value for a given name in a pblock. See "Parameter Block Manipulation Routines" for a summary of the most commonly used functions for working with parameter blocks.
sn (session)
The sn parameter is a pointer to a Session data structure. This parameter contains variables related to an entire session (that is, the time between the opening and closing of the TCP/IP connection between the client and the server). The same sn pointer is passed to each SAF called within each request for an entire session. The following list describes the most important fields in this data structure.
(See "NSAPI Function Reference" for information about NSAPI routines for manipulating the Session data structure):
- sn->client
is a pointer to a pblock containing information about the client such as its IP address, DNS name, or certificate. If the client does not have a DNS name or if it cannot be found, it will be set to -none.
- sn->csd
is a platform-independent client socket descriptor. You will pass this to the routines for reading from and writing to the client.
rq (request)
The rq parameter is a pointer to a request data structure. This parameter contains variables related to the current request, such as the request headers, URI, and local file system path. The same request pointer is passed to each SAF called in the request-response process for an HTTP request.
The following list describes the most important fields in this data structure (See "NSAPI Function Reference," for information about NSAPI routines for manipulating the Request data structure).
- rq->vars
is a pointer to a pblock containing the server's "working" variables. This includes anything not specifically found in the following three pblocks. The contents of this pblock vary depending on the specific request and the type of SAF. For example, an AuthTrans SAF may insert an auth-user parameter into rq->vars which can be used subsequently by a PathCheck SAF.
- rq->reqpb
is a pointer to a pblock containing elements of the HTTP request. This includes the HTTP method (GET, POST, ...), the URI, the protocol (normally HTTP/1.0), and the query string. This pblock does not normally change throughout the request-response process.
- rq->headers
is a pointer to a pblock containing all the request headers (such as User-Agent, If-Modified-Since, ...) received from the client in the HTTP request. See "HyperText Transfer Protocol," for more information about request headers. This pblock does not normally change throughout the request-response process.
- rq->srvhdrs
is a pointer to a pblock containing the response headers (such as Server, Date, Content-type, Content-length,...) to be sent to the client in the HTTP response. See "HyperText Transfer Protocol," for more information about response headers.
The rq parameter is the primary mechanism for passing along information throughout the request-response process. On input to a SAF, rq contains whatever values were inserted or modified by previously executed SAFs. On output, rq contains any modifications or additional information inserted by the SAF. Some SAFs depend on the existence of specific information provided at an earlier step in the process. For example, a PathCheck SAF retrieves values in rq->vars which were previously inserted by an AuthTrans SAF.
Result Codes
Upon completion, a SAF returns a result code. The result code indicates what the server should do next. The result codes are:
- REQ_PROCEED
indicates that the SAF achieved its objective. For some request-response steps (AuthTrans, NameTrans, Service, and Error), this tells the server to proceed to the next request-response step, skipping any other SAFs in the current step. For the other request-response steps (PathCheck, ObjectType, and AddLog), the server proceeds to the next SAF in the current step.
- REQ_NOACTION
indicates the SAF took no action. The server continues with the next SAF in the current server step.
- REQ_ABORTED
indicates that an error occurred and an HTTP response should be sent to the client to indicate the cause of the error. A SAF returning REQ_ABORTED should also set the HTTP response status code. If the server finds an Error directive matching the status code or reason phrase, it executes the SAF specified. If not, the server sends a default HTTP response with the status code and reason phrase plus a short HTML page reflecting the status code and reason phrase for the user. The server then goes to the first AddLog directive.
- REQ_EXIT
indicates the connection to the client was lost. This should be returned when the SAF fails in reading or writing to the client. The server then goes to the first AddLog directive.
Creating and Using Custom SAFs
Custom SAFs are functions in shared libraries that are loaded and called by the server. Follow these steps to create a custom SAF:
- Write the Source Code
using the NSAPI functions. Each SAF is written for a specific directive.
- Compile and Link
the source code to create a shared library (.so, .sl, or .dll) file.
- Load and Initialize the SAF
by editing the obj.conf file to:
-- Load the shared library file containing your custom SAF(s).
-- Initialize the SAF if necessary.
- Instruct the Server to Call the SAFs
by editing obj.conf to call your custom SAF(s) at the appropriate time.
- Reconfigure the Server
- Test the SAF
by accessing your server from a browser with a URL that triggers your function.
The following sections describe these steps in greater detail.
Write the Source Code
Write your custom SAFs using NSAPI functions. For a summary of some of the most commonly used NSAPI functions, see the section "Overview of NSAPI C Functions." "NSAPI Function Reference," provides information about all of the routines available.
For examples of custom SAFs, see install_dir/samples/nsapi, and also see "Examples of Custom SAFs."
The signature for all SAFs is:
int function(pblock *pb, Session *sn, Request *rq);
For more details on the parameters, see the section "SAF Parameters."
The Sun ONE Application Server runs as a multi-threaded single process. On UNIX platforms there are actually two processes (a parent and a child) for historical reasons. The parent process performs some initialization and forks the child process. The child process performs further initialization and handles all the HTTP requests.
Keep these things in mind when writing your SAF. Write thread-safe code. Blocking may affect performance. Write small functions with parameters and configure them in obj.conf. Carefully check and handle all errors. Also log them so that you can determine the source of problems and fix them.
If necessary, write an initialization function that performs initialization tasks required by your new SAFs. The initialization function has the same signature as other SAFs:
int function(pblock *pb, Session *sn, Request *rq);
SAFs expect to be able to obtain certain types of information from their parameters. In most cases, parameter block (pblock) data structures provide the fundamental storage mechanism for these parameters A pblock maintains its data as a collection of name-value pairs. For a summary of the most commonly used functions for working with pblock structures, see "Parameter Block Manipulation Routines."
When defining a SAF, you do not specifically state which directive it is written for. However, each SAF must be written for a specific directive (such as AuthTrans, Service, and so on). Each directive expects its SAFs to do particular things, and your SAF must conform to the expectations of the directive for which it was written. For details of what each directive expects of its SAFs, see the section "Required Behavior of SAFs for Each Directive."
Compile and Link
Compile and link your code with the native compiler for the target platform. For UNIX, use the gmake command. For Windows, use the nmake command. For Windows, use Microsoft Visual C++ 6.0 or newer. You must have an import list that specifies all global variables and functions to access from the server binary. Use the correct compiler and linker flags for your platform. Refer to the example Makefile in the install_dir/samples/nsapi directory.
Follow these guidelines for compiling and linking.
Include Directory and nsapi.h File
Add the install_dir/include directory to your makefile to include the nsapi.h file.
Libraries
Add the install_dir/lib (UNIX) or install_dir\bin (Windows) library directory to your linker command.
The following table lists the library that you need to link to. The left column lists the platform, and the right column lists the library.
   Libraries
Platform
Library
Windows
ns-httpd40.dll (in addition to the standard Windows libraries)
HPUX
libns-httpd40.sl
All other UNIX platforms
libns-httpd40.so
Linker Commands and Options for Generating a Shared Object
The following table lists the options for generating a shared library. The left column lists the platform, and the right column lists the options.
Additional Linker Flags
Use the linker flags in to specify which directories should be searched for shared objects during runtime to resolve symbols.
The following table lists the linker flags. The left column lists the platform, and the right column lists the flags.
On UNIX, you can also set the library search path using the LD_LIBRARY_PATH environment variable, which must be set when you start the server.
Compiler Flags
The following table lists the flags and defines that you need to use for compilation of your source code. The left column lists the platform, and the right column lists the flags and defines.
Compiling iPlanet Web Server 6.x Plugins on Solaris
You must recompile and relink a plugin for use in Sun ONE Application Server 7 if it meets all of these conditions:
- The plugin was developed on the Solaris platform.
- The plugin was developed for use with iPlanet Web Server version 6.x or earlier.
- The plugin is written in C++.
- The plugin uses exceptions.
Once recompiled for Sun ONE Application Server 7, the plugin will no longer work in iPlanet Web Server 6.x. Therefore, you must maintain separate binary versions for iPlanet Web Server 6.x and Sun ONE Application Server 7.
To build a plugin for Sun ONE Application Server 7, you must use version 5.0 or higher of the Sun WorkShop C/C++ compiler (also called Forte C/C++). Do not specify the -compat flag (-compat=4 is the same as -compat, but -compat=5 is the same as not specifying the -compat flag).
Compiling 3.x Plugins on AIX
For AIX only, plugins built for 3.x versions of the server must be relinked to work with 4.x and 6.x versions. The files you need, which are in the install_dir/samples/nsapi directory, are as follows:
- The Makefile file has the -G option instead of the old -bM:SRE -berok -brtl -bnoentry options.
- A script, relink_36plugin, modifies a plugin built for 3.x versions of the server to work with 4.x and 6.x versions. The script's comments explain its use.
iPlanet Web Server 4.x and 6.x versions are built on AIX 4.2, which natively supports runtime-linking. Because of this, NSAPI plugins, which reference symbols in the appservd main executable, must be built with the -G option, which specifies that symbols must be resolved at runtime.
Previous versions of iPlanet Web Server, however, were built on AIX 4.1, which did not support native runtime-linking. Web Server had specific additional software (provided by IBM AIX development) to enable plugins. No special runtime-linking directives were required to build plugins. Because of this, plugins that have been built for previous server versions on AIX will not work with iPlanet Web Server 4.x and 6.x versions as they are.
However, they can easily be relinked to work with iPlanet Web Server 4.x and 6.x versions. The relink_36plugin script relinks existing plugins. Only the existing plugin itself is required for the script; original source and .o files are not needed. More specific comments are in the script itself. Since all AIX versions from 4.2 onward natively support runtime-linking, no plugins for iPlanet Web Server versions 4.x and later will need to be relinked.
Load and Initialize the SAF
For each shared library (plugin) containing custom SAFs to be loaded into the Sun ONE Application Server, add an Init directive that invokes the load-modules SAF to init.conf.
The syntax for a directive that calls load-modules is:
Init fn=load-modules shlib=[path]sharedlibname funcs="SAF1,...,SAFn"
- shlib is the local file system path to the shared library (plugin).
- funcs is a comma-separated list of function names to be loaded from the shared library. Function names are case-sensitive. You may use dash (-) in place of underscore (_) in function names. There should be no spaces in the function name list.
If the new SAFs require initialization, be sure that the initialization function is included in the funcs list.
For example, if you created a shared library animations.so that defines two SAFs do_small_anim() and do_big_anim() and also defines the initialization function init_my_animations, you would add the following directive to load the plugin:
Init fn=load-modules shlib=animations.so funcs="do_small_anim,do_big_anim,init_my_animations"
If necessary, also add an Init directive that calls the initialization function for the newly loaded plugin. For example, if you defined the function init_my_new_SAF() to perform an operation on the maxAnimLoop parameter, you would a directive such as the following to init.conf:
Init fn=init_my_animations maxAnimLoop=5
Instruct the Server to Call the SAFs
Next, add directives to obj.conf to instruct the server to call each custom SAF at the appropriate time. The syntax for directives is:
Directive fn=function-name [name1="value1"]...[nameN="valueN"]
- Directive is one of the server directives, such as AuthTrans, Service, and so on.
- function-name is the name of the SAF to execute.
- nameN="valueN" are the names and values of parameters which are passed to the SAF.
Depending on what your new SAF does, you might need to add just one directive to obj.conf or you might need to add more than one directive to provide complete instructions for invoking the new SAF.
For example, if you define a new AuthTrans or PathCheck SAF you could just add an appropriate directive in the default object. However, if you define a new Service SAF to be invoked only when the requested resource is in a particular directory or has a new kind of file extension, you would need to take extra steps.
If your new Service SAF is to be invoked only when the requested resource has a new kind of file extension, you might need to add an entry to the MIME types file so that the type value gets set properly during the ObjectType stage. Then you could add a Service directive to the default object that specifies the desired type value.
If your new Service SAF is to be invoked only when the requested resource is in a particular directory, you might need to define a NameTrans directive that generates a name or ppath value that matches another object, and then in the new object you could invoke the new Service function.
For example, suppose your plugin defines two new SAFs, do_small_anim() and do_big_anim() which both take speed parameters. These functions run animations. All files to be treated as small animations reside in the directory:
D:/Sun/AppServer7/domains/domain1/server1/docs/animations/small
while all files to be treated as full screen animations reside in the directory:
D:/Sun/AppServer7/domains/domain1/server1/docs/animations/fullscrn
To ensure that the new animation functions are invoked whenever a client sends a request for either a small or full screen animation, you would add NameTrans directives to the default object to translate the appropriate URLs to the corresponding pathnames and also assign a name to the request.
NameTrans fn=pfx2dir from="/animations/small"
dir="D:/Sun/AppServer7/domains/domain1/server1/docs/animations/small" name="small_anim"NameTrans fn=pfx2dir from="/animations/fullscrn"
dir="D:/Sun/AppServer7/domains/domain1/server1/docs/animations/fullscrn" name="fullscrn_anim"You also need to define objects that contain the Service directives that run the animations and specify the speed parameter.
<Object name="small_anim">
Service fn=do_small_anim speed=40
</Object>
<Object name="fullscrn_anim">
Service fn=do_big_anim speed=20
</Object>
Reconfigure the Server
After modifying obj.conf, you need to reconfigure the server. See the Sun ONE Application Server Administrator's Guide for details.
Test the SAF
Test your SAF by accessing your server from a browser with a URL that triggers your function. For example, if your new SAF is triggered by requests to resources in http://hostname/animations/small, try requesting a valid resource that starts with that URI.
You should disable caching in your browser so that the server is sure to be accessed. In Navigator you may hold the shift key while clicking the Reload button to ensure that the cache is not used. (Note that the shift-reload trick does not always force the client to fetch images from source if the images are already in the cache.)
You may also wish to disable the server cache using the cache-init SAF.
Examine the access log and server log to help with debugging.
Overview of NSAPI C Functions
NSAPI provides a set of C functions that are used to implement SAFs. They serve several purposes. They provide platform-independence across Sun ONE Application Server operating system and hardware platforms. They provide improved performance. They are thread-safe, which is a requirement for SAFs. They prevent memory leaks. And they provide functionality necessary for implementing SAFs. You should always use these NSAPI routines when defining new SAFs.
This section provides an overview of the function categories available and some of the more commonly used routines. All the public routines are detailed in "NSAPI Function Reference."
The main categories of NSAPI functions are:
- Parameter Block Manipulation Routines
- Protocol Utilities for Service SAFs
- Memory Management
- File I/O
- Network I/O
- Threads
- Utilities
- Virtual Server
Parameter Block Manipulation Routines
The parameter block manipulation functions provide routines for locating, adding, and removing entries in a pblock data structure include:
- pblock_findval returns the value for a given name in a pblock.
- pblock_nvinsert adds a new name-value entry to a pblock.
- pblock_remove removes a pblock entry by name from a pblock. The entry is not disposed. Use param_free to free the memory used by the entry.
- param_free frees the memory for the given pblock entry.
- pblock_pblock2str creates a new string containing all the name-value pairs from a pblock in the form "name=value name=value." This can be a useful function for debugging.
Protocol Utilities for Service SAFs
Protocol utilities provide functionality necessary to implement Service SAFs:
- request_header returns the value for a given request header name, reading the headers if necessary. This function must be used when requesting entries from the browser header pblock (rq->headers).
- protocol_status sets the HTTP response status code and reason phrase
- protocol_start_response sends the HTTP response and all HTTP headers to the browser.
Memory Management
Memory management routines provide fast, platform-independent versions of the standard memory management routines. They also prevent memory leaks by allocating from a temporary memory (called "pooled" memory) for each request and then disposing the entire pool after each request. There are wrappers for standard memory routines for using permanent memory. To disable pooled memory for debugging, see the built-in SAF pool-init in "SAFs in the init.conf File."
File I/O
The file I/O functions provides platform-independent, thread-safe file I/O routines.
- system_fopenRO opens a file for read-only access.
- system_fopenRW opens a file for read-write access, creating the file if necessary.
- system_fopenWA opens a file for write-append access, creating the file if necessary.
- system_fclose closes a file.
- system_fread reads from a file.
- system_fwrite writes to a file.
- system_fwrite_atomic locks the given file before writing to it. This avoids interference between simultaneous writes by multiple threads.
Network I/O
Network I/O functions provide platform-independent, thread-safe network I/O routines. These routines work with SSL when it's enabled.
- netbuf_grab reads from a network buffer's socket into the network buffer.
- netbuf_getc gets a character from a network buffer.
- net_write writes to the network socket.
Threads
Thread functions include functions for creating your own threads which are compatible with the server's threads. There are also routines for critical sections and condition variables.
- systhread_start creates a new thread.
- systhread_sleep puts a thread to sleep for a given time.
- crit_init creates a new critical section variable.
- crit_enter gains ownership of a critical section.
- crit_exit surrenders ownership of a critical section.
- crit_terminate disposes of a critical section variable.
- condvar_init creates a new condition variable.
- condvar_notify awakens any threads blocked on a condition variable.
- condvar_wait blocks on a condition variable.
- condvar_terminate disposes of a condition variable.
- prepare_nsapi_thread allows threads that are not created by the server to act like server-created threads.
Utilities
Utility functions include platform-independent, thread-safe versions of many standard library functions (such as string manipulation) as well as new utilities useful for NSAPI.
- daemon_atrestart (UNIX only) registers a user function to be called when the server is sent a restart signal (HUP) or at shutdown.
- util_getline gets the next line (up to a LF or CRLF) from a buffer.
- util_hostname gets the local hostname as a fully qualified domain name.
- util_later_than compares two dates.
- util_sprintf same as standard library routine sprintf().
- util_strftime same as standard library routine strftime().
- util_uri_escape converts the special characters in a string into URI escaped format.
- util_uri_unescape converts the URI escaped characters in a string back into special characters.
Virtual Server
The virtual server functions provide routines for retrieving information about virtual servers.
- request_get_vs finds the virtual server to which a request is directed.
- vs_alloc_slot allocates a new slot for storing a pointer to data specific to a certain virtual server.
- vs_get_data finds the value of a pointer to data for a given virtual server and slot.
- vs_get_default_httpd_object obtains a pointer to the default (or root) object from the virtual server's virtual server class configuration.
- vs_get_doc_root finds the document root for a virtual server.
- vs_get_httpd_objset obtains a pointer to the virtual server class configuration for a given virtual server.
- vs_get_id finds the ID of a virtual server.
- vs_get_mime_type determines the MIME type that would be returned in the Content-type: header for the given URI.
- vs_lookup_config_var finds the value of a configuration variable for a given virtual server.
- vs_register_cb allows a plugin to register functions that will receive notifications of virtual server initialization and destruction events.
- vs_set_data sets the value of a pointer to data for a given virtual server and slot.
- vs_translate_uri translates a URI as though it were part of a request for a specific virtual server.
Required Behavior of SAFs for Each Directive
When writing a new SAF, you should define it to do certain things, depending on which stage of the request handling process will invoke it. For example, SAFs to be invoked during the Init stage must conform to different requirements than SAFs to be invoked during the Service stage.
The rq parameter is the primary mechanism for passing along information throughout the request-response process. On input to a SAF, rq contains whatever values were inserted or modified by previously executed SAFs. On output, rq contains any modifications or additional information inserted by the SAF. Some SAFs depend on the existence of specific information provided at an earlier step in the process. For example, a PathCheck SAF retrieves values in rq->vars which were previously inserted by an AuthTrans SAF.
This section outlines the expected behavior of SAFs used at each stage in the request handling process.
- Init SAFs
- AuthTrans SAFs
- NameTrans SAFs
- PathCheck SAFs
- ObjectType SAFs
- Service SAFs
- Error SAFs
- AddLog SAFs
Init SAFs
- Purpose: Initialize at startup.
- Called at server startup and restart.
- rq and sn are NULL.
- Initialize any shared resources such as files and global variables.
- Can register callback function with daemon_atrestart() to clean up.
- On error, insert error parameter into pb describing the error and return REQ_ABORTED.
- If successful, return REQ_PROCEED.
AuthTrans SAFs
- Purpose: Verify any authorization information. Only basic authorization is currently defined in the HTTP/1.0 specification.
- Check for Authorization header in rq->headers which contains the authorization type and uu-encoded user and password information. If header was not sent return REQ_NOACTION.
- If header exists, check authenticity of user and password.
- If authentic, create auth-type, plus auth-user and/or auth-group parameter in rq->vars to be used later by PathCheck SAFs.
- Return REQ_PROCEED if the user was successfully authenticated, REQ_NOACTION otherwise.
NameTrans SAFs
- Purpose: Convert logical URI to physical path
- Perform operations on logical path (ppath in rq->vars) to convert it into a full local file system path.
- Return REQ_PROCEED if ppath in rq->vars contains the full local file system path, or REQ_NOACTION if not.
- To redirect the client to another site, change ppath in rq->vars to /URL. Add url to rq->vars with full URL (for example., http://home.sun.com/). Return REQ_PROCEED.
PathCheck SAFs
- Purpose: Check path validity and user's access rights.
- Check auth-type, auth-user and/or auth-group in rq->vars.
- Return REQ_PROCEED if user (and group) is authorized for this area (ppath in rq->vars).
- If not authorized, insert WWW-Authenticate to rq->srvhdrs with a value such as: Basic; Realm=\"Our private area\". Call protocol_status() to set HTTP response status to PROTOCOL_UNAUTHORIZED. Return REQ_ABORTED.
ObjectType SAFs
- Purpose: Determine content-type of data.
- If content-type in rq->srvhdrs already exists, return REQ_NOACTION.
- Determine the MIME type and create content-type in rq->srvhdrs
- Return REQ_PROCEED if content-type is created, REQ_NOACTION otherwise
Service SAFs
- Purpose: Generate and send the response to the client.
- A Service SAF is only called if each of the optional parameters type, method, and query specified in the directive in obj.conf match the request.
- Remove existing content-type from rq->srvhdrs. Insert correct content-type in rq->srvhdrs.
- Create any other headers in rq->srvhdrs.
- Call protocol_status to set HTTP response status.
- Call protocol_start_response to send HTTP response and headers.
- Generate and send data to the client using net_write.
- Return REQ_PROCEED if successful, REQ_EXIT on write error, REQ_ABORTED on other failures.
Error SAFs
- Purpose: Respond to an HTTP status error condition.
- The Error SAF is only called if each of the optional parameters code and reason specified in the directive in obj.conf match the current error.
- Error SAFs do the same as Service SAFs, but only in response to an HTTP status error condition.
AddLog SAFs
- Purpose: Log the transaction to a log file.
- AddLog SAFs can use any data available in pb, sn, or rq to log this transaction.
- Return REQ_PROCEED.
CGI to NSAPI Conversion
You may have a need to convert a CGI variable into an SAF using NSAPI. Since the CGI environment variables are not available to NSAPI, you'll retrieve them from the NSAPI parameter blocks.
Keep in mind that your code must be thread-safe under NSAPI. You should use NSAPI functions which are thread-safe. Also, you should use the NSAPI memory management and other routines for speed and platform independence.
The following table indicates how each CGI environment variable can be obtained in NSAPI. The left column lists the CGI variables, and the right column lists the NSAPI parameter blocks.