Sun Java System Web Server 7.0 Update 7 NSAPI Developer's Guide

Chapter 2 Creating Custom Server Application Functions

This chapter describes how to write your own NSAPI plug-ins that define custom Server Application Functions (SAFs). The ability to create custom plug-ins enables you to modify or extend the Sun Java System Web 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.

This chapter has the following sections:

Before writing custom SAFs, you must familiarize yourself with the request-handling process, as described in detail in the Sun Java System Web Server 7.0 Update 7 Administrator’s Configuration File Reference. Also, before writing a custom SAF, check to see whether a built-in SAF already accomplishes the tasks you have in mind.

See Appendix B, Alphabetical List of NSAPI Functions and Macros for a list of the predefined Init SAFs. For information about predefined SAFs used in the obj.conf file, see the Sun Java System Web Server 7.0 Update 7 Administrator’s Configuration File Reference.

For a complete list of the NSAPI routines for implementing custom SAFs, see Chapter 6, NSAPI Function and Macro Reference.

Future Compatibility Issues

To keep your custom plug-ins upgradable, do the following:

SAF Interface

All SAFs whether custom or built-in have the same C interface regardless of the request-handling step for which they are written. SAFs are small functions intended for a specific purpose within a specific request-response step. SAFs receive parameters from the directive that invokes them in the obj.conf file, from the server, and from previous SAFs.

The C interface for a SAF is:

int function(pblock *pb, Session *sn, Request *rq);

The next section discusses the parameters in detail.

The SAF returns a result code that indicates whether and how it succeeded. The server uses the result code from each function to determine how to proceed with processing the request. For more information on the result codes, see Result Codes.

SAF Parameters

This section discusses the SAF parameters in detail.

pb (Parameter Block) Parameter

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 the following:


AuthTrans fn=basic-ncsa auth-type=basic dbm=users.db
    

In this case, the pb parameter passed to basic-ncsa contains name-value pairs that correspond to auth-type=basic and dbm=users.db.

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. For information on working with parameter blocks, see Parameter Block Manipulation Routines.

sn (Session) Parameter

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. For a list of important fields, see Session Data Structure.

rq (Request) Parameter

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. For a list of important fields, see Request Data Structure.

Result Codes

Upon completion, a SAF returns a result code. The result code indicates what the server should do next.

The result codes are:

Creating and Using Custom SAFs

Custom SAFs are functions in shared libraries that are loaded and called by the server.

The general steps to create a custom SAF are as follows:

The following sections describe these steps in greater detail.

Writing the Source Code for a Custom SAF

Write your custom SAFs using NSAPI functions. For a summary of some of the most commonly used NSAPI functions, see Overview of NSAPI C Functions and for available routines, see Chapter 6, NSAPI Function and Macro Reference.

For examples of custom SAFs, see Chapter 4, Examples of Custom SAFs and Filters.

The signature for all SAFs is as follows:

int function(pblock *pb, Session *sn, Request *rq);

For more details on the parameters, see SAF Parameters.

You must register your SAFs with the server. SAFs may be registered using the funcs parameter of the load-modules Init SAF or by a call to func_insert. A plug-in may define a nspai_module_init function that is used to call func_insert and perform any other initialization tasks. For more information, see nsapi_module_init() Function and func_insert() Function.

The server runs as a multi-threaded single process. On UNIX platforms, the server runs 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 of the HTTP requests.

Keep the following in mind when writing your SAF:

If necessary, write an initialization function that performs initialization tasks required by your new SAFs. The initialization function must be named nsapi_module_init and has the same signature as other SAFs:

int nsapi_module_init(pblock *pb, Session *sn, Request *rq);

SAFs should 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. 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 requires its SAFs to behave in particular ways, and your SAF must conform to the requirements of the directive for which it was written. For details on what each directive requires of its SAFs, see Required Behavior of SAFs for Each Directive.

Compiling and Linking

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.

Adhere to the following guidelines for compiling and linking.

Including Directory and nsapi.h File

Add the install-dir/include (UNIX) or install-dir\include (Windows) directory to your makefile to include the nsapi.h file.

Libraries

Add the install-dir/bin/https/lib (UNIX) or install-dir\bin\https\bin (Windows) library directory to your linker command.

The following table lists the library that you need to link to.

Table 2–1 Libraries

Platform

Library

Windows 

ns-httpd40.dll in addition to the standard Windows libraries

HP-UX 

libns-httpd40.sl

All other UNIX platforms 

libns-httpd40.so

Linker Commands and Options for Generating a Shared Object

To generate a shared library, use the commands and options listed in the following table.

SolarisTM Operating System (SPARC® Platform Edition)

ld -G or cc -G

Windows

link -LD

HP-UX

cc +Z -b -Wl,+s -Wl,-B,symbolic

AIX

cc -p 0 -berok -blibpath:$(LD_RPATH)

Compaq

cc -shared

Linux

gcc -shared

IRIX

cc -shared

Additional Linker Flags

Use the linker flags in the following table to specify which directories should be searched for shared objects during runtime to resolve symbols.

Solaris SPARC

-R dir:dir

Windows

no flags, but the ns-httpd40.dll file must be in the system PATH variable

HP-UX

-Wl,+b,dir,dir

AIX

-blibpath:dir:dir

Compaq

-rpath dir:dir

Linux

-Wl,-rpath,dir:dir

IRIX

-Wl,-rpath,dir:dir

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 you need to use for compilation of your source code.

Solaris SPARC

-DXP_UNIX -D_REENTRANT -KPIC -DSOLARIS

Windows

-DXP_WIN32 -DWIN32 /MD

HP-UX

-DXP_UNIX -D_REENTRANT -DHPUX

AIX

-DXP_UNIX -D_REENTRANT -DAIX $(DEBUG)

Compaq

-DXP_UNIX -KPIC

Linux

-DXP_UNIX -D_REENTRANT -fPIC

IRIX

-o32 -exceptions -DXP_UNIX -KPIC

Compiling and Linking in 64–bit Mode

On the Solaris platform, the server can run in either 32–bit or 64–bit mode. Because a 32–bit shared library cannot be used in a 64–bit process and conversely, you may want to compile and link two separate shared libraries. By default, the Sun compiler and linker produce 32–bit binaries. To compile and link your plug-in for 64–bit mode on Solaris SPARC, you must use Sun Workshop 5.0 or higher with the -xarch=v9 flag. To compile and link your plug-in for 64–bit mode on Solaris x86, you must use Sun Java Studio 11 or higher with the -xarch=amd64 flag.

Issues With Using C++ in a NSAPI Plug-in

NSAPI plug-ins are typically written using the C programming language. Using the C++ programming language in an NSAPI plug-in raises special compatibility issues.

On Solaris, the server is built using the new C++ 5 ABI. If your shared library uses C++, it must be compiled with Sun Workshop 5.0 or higher. Sun Java Studio 11 or higher is recommended. Do not use the -compat=4 option when compiling and linking a shared library that uses C++. When running in 32–bit mode on Solaris SPARC, the server provides some backward compatibility for the old C++ 4 ABI or Sun Workshop 4.2. This backward compatibility may be removed at some future date. For all new NSAPI plug-ins, use the new C++ 5 ABI or Sun Workshop 5.0 or later versions.

On Linux, Web Server is built using the gcc 3.2 C++ ABI. If your shared library uses C++, compile with gcc 3.2.x. Because of the volatility of the gcc C++ ABI, avoid using C++ in NSAPI plug-ins on Linux.

Load and Initialize the SAF

For each shared library (plug-in) containing custom SAFs to be loaded into the server, add an Init directive that invokes the load-modules SAF to magnus.conf. The load-modules SAF loads the shared library and calls the shared library's nsapi_module_init function. For more information, see nsapi_module_init() Function.

The syntax for a directive that calls load-modules is:

Init fn=load-modules
     [shlib=path]
     [funcs="SAF1,...,SAFn"]
     [name1="value1"]...[nameN="valueN"]

Instruct the Server to Call the SAFs

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"]

NameTrans fn=pfx2dir
          from="/animations/small"
          dir="D:/docs/animations/small" 
          name="small_anim"
NameTrans fn=pfx2dir 
          from="/animations/fullscreen"
          dir="D:/docs/animations/fullscreen"
          name="fullscreen_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="fullscreen_anim">
Service fn=do_big_anim speed=20
</Object>

         

Restarting the Server

After modifying obj.conf, you need to restart the server. A restart is required for all plug-ins that implement SAFs and/or filters.

Testing 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://server-name/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 Mozilla Firefox, hold the shift key while clicking the Reload button to ensure that the cache is not used.

Examine the access log and error log to help with debugging.

Overview of NSAPI C Functions

NSAPI provides a set of C functions that are used to implement SAFs. These functions serve several purposes:

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 of the public routines are detailed in Chapter 6, NSAPI Function and Macro Reference.

The main categories of NSAPI functions are:

Parameter Block Manipulation Routines

The parameter block manipulation functions provide routines for locating, adding, and removing entries in a pblock data structure:

Protocol Utilities for Service SAFs

Protocol utilities provide functionality necessary to implement Service SAFs:

Memory Management

Memory management routines provide fast, platform-independent versions of the standard memory management routines. These routines 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. Wrappers enable standard memory routines to use permanent memory. To disable the server's pooled memory allocator for debugging,use the built-in SAF pool-init. For more information, see the Sun Java System Web Server 7.0 Update 7 Administrator’s Configuration File Reference.

File I/O

The file I/O functions provide platform-independent, thread-safe file I/O routines.

Network I/O

Network I/O functions provide platform-independent, thread-safe network I/O routines. These routines work with SSL when it is enabled.

Threads

Thread functions include functions for creating your own threads that are compatible with the server’s threads. Routines also exist for critical sections and condition variables.

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.


Note –

You cannot use an embedded null in a string, because NSAPI functions assume that a null is the end of the string. Therefore, passing Unicode-encoded content through an NSAPI plug-in does not work.


Virtual Server

The virtual server functions provide routines for retrieving information about virtual servers.

Required Behavior of SAFs for Each Directive

When writing a new SAF, you should define it to accomplish certain actions, 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 that were previously inserted by an AuthTrans SAF.

This section outlines the expected behavior of SAFs used at each stage in the request-handling process. The SAFs are described in the following sections:

For more detailed information about these SAFs, see the Sun Java System Web Server 7.0 Update 7 Administrator’s Configuration File Reference.

Init() SAFs

AuthTrans() SAFs

NameTrans() SAFs

PathCheck() SAFs

ObjectType() SAFs

Input() SAFs

Output() SAFs

Service() SAFs

Error() SAFs

AddLog() SAFs

CGI to NSAPI Conversion

.The CGI environment variables are not available to NSAPI. Therefore, if you need to convert a CGI variable into an SAF using NSAPI, you retrieve them from the NSAPI parameter blocks. The following table indicates how each CGI environment variable can be obtained in NSAPI.

Keep in mind that your code must be thread-safe under NSAPI. You should use NSAPI functions that are thread-safe. Also, you should use the NSAPI memory management and other routines for speed and platform independence.

Table 2–2 Parameter Blocks for CGI Variables

CGI getenv()

NSAPI

AUTH_TYPE

pblock_findval("auth-type", rq->vars);

AUTH_USER

pblock_findval("auth-user", rq->vars);

CONTENT_LENGTH

pblock_findval("content-length", rq->headers);

CONTENT_TYPE

pblock_findval("content-type", rq->headers);

GATEWAY_INTERFACE

"CGI/1.1"

HTTP_*

pblock_findval( "*", rq->headers); (* is lowercase; dash replaces underscore)

PATH_INFO

pblock_findval("path-info", rq->vars);

PATH_TRANSLATED

pblock_findval("path-translated", rq->vars);

QUERY_STRING

pblock_findval("query", rq->reqpb);

REMOTE_ADDR

pblock_findval("ip", sn->client);

REMOTE_HOST

session_dns(sn) ? session_dns(sn) : pblock_findval("ip", sn->client);

REMOTE_IDENT

pblock_findval( "from", rq->headers); (not usually available)

REMOTE_USER

pblock_findval("auth-user", rq->vars);

REQUEST_METHOD

pblock_findval("method", req->reqpb);

SCRIPT_NAME

pblock_findval("uri", rq->reqpb);

SERVER_NAME

char *util_hostname();

SERVER_PORT

conf_getglobals()->Vport; (as a string)

SERVER_PROTOCOL

pblock_findval("protocol", rq->reqpb);

SERVER_SOFTWARE

system_version()

Sun Java System-specific:

CLIENT_CERT

pblock_findval("auth-cert", rq->vars) ;

HOST

char *session_maxdns(sn); (may be null)

HTTPS

security_active ? "ON" : "OFF";

HTTPS_KEYSIZE

pblock_findval("keysize", sn->client);

HTTPS_SECRETKEYSIZE

pblock_findval("secret-keysize", sn->client);

SERVER_URL

protocol_uri2url_dynamic("","", sn, rq);