Sun ONE logo     Previous      Contents      Index      Next     
Sun ONE Web Proxy Server 3.6 SP2 Administrator's Guide - UNIX Version



Chapter 17   Creating Server Plug-in Functions

This chapter describes how to create and compile your plug-in functions using the iPlanet Web Proxy Server plug-in application programming interface (API) and how to use the functions you create.

Before creating plug-in functions, you should be familiar with the server configuration files and the built-in functions.

Of the systems the iPlanet server supports, the following systems can load functions into the server at run time and can therefore use plug-in functions:

  • Solaris
  • HP/UX
  • AIX

What Is the Server Plug-in API?

The server plug-in API is a set of functions and header files that help you create functions to use with the directives in server configuration files. The iPlanet Web Proxy Server uses this API to create the functions for the directives used in both magnus.conf (the server configuration file) and obj.conf (the object configuration file).

The server uses this API, so by becoming familiar with the API, you can learn how the server works. This means you can override the server functionality, add to it, or customize your own functions. For example, you can create functions that use a custom database for access control or functions that create custom log files with special entries.

These steps are a brief overview of the process for creating your own plugin functions:

  1. You write code for your functions. Each function you create is written specifically for the directive with which it will be used in the configuration files.
  2. For Unix, you compile your code to create a shared object file (.so file).
  3. For a Unix proxy server, tell the server to load your shared object file in the Init directives of obj.conf.
  4. You use your functions in your server configuration file (obj.conf).

Before you write your functions, you should understand how the server handles requests.

Writing Plug-in Functions

This section describes how to begin writing your plug-in functions. It also describes the header files you need to include in your code. See Compiling and Linking Your Code for additional information.

The server root directory has a subdirectory called /nsapi that contains sample code, the header files, and a makefile. You should familiarize yourself with the code and samples. This documentation is written as a starting point for exploring that code. Figure 17-1 shows the hierarchy of the server plug-in API header files.

  • The nsapi/examples/ directory contains C files with examples for each class of function you can create.
  • The nsapi/include/ directory contains all the header files you need to include when writing your plug-in functions.

Figure 17-1    The hierarchy of server plug-in API header files

The server and its header files are written in ANSI C. On some systems you must have an import list that specifies all global variables and functions you need to access from the server binary.

The Server Plug-in API Header Files

This section describes the header files you can include when writing your plug-in functions. This section is intended as a starting point for learning the functions included in the header files.

Most of the header files are stored in two directories:

  • nsapi/include/base contains header files that deal with low-level, platform-independent functions such as memory, file, and network access.
  • nsapi/include/frame contains header files of functions that deal with server- and HTTP-specific functions such as handling access to configuration files and dealing with HTTP.

One header file, netsite.h, is stored in the nsapi/include directory.

Header File

Description

buffer.h

Contains functions that buffer I/O (input/output) for a file or a socket descriptor.

cinfo.h

Contains functions for object typing, specifically mapping files to MIME types.

crit.h

Contains functions for managing critical sections, an abstraction that facilitates the management of threaded servers.

daemon.h

Contains functions called from other header files. It also contains functions that manage group processes that run the server.

ereport.h

Contains functions that handle low-level errors.

file.h

Contains functions to handle file I/O.

net.h

Contains functions for I/O with the client software over the network.

pblock.h

Contains functions that manage parameter passing and server internal variables. It also contains functions to get values from a user via the server.

pool.h

Contains routines that manage memory pools.

regexp.h

Contains functions that support regular expressions.

sem.h

Contains semaphores in platform-independent ways (they prevent two processes from doing the same thing).

session.h

Contains session data structures for IP addresses, security, and so on.

shexp.h

Contains functions to customize wildcard patterns through parsed data.

shmem.h

Contains functions that support shared memory.

systems.h

Contains functions that handle systems information.

systhr.h

Contains functions that support the abstract threading mechanism.

util.h

Contains utility functions.

Header File

Description

conf.h

Contains functions to access magnus.conf (for example, to get port numbers or internal global variables).

func.h

Contains data structures. This file is rarely used.

http.h

Contains functions for the HTTP protocol. Most of these functions are called from functions in protocol.h.

log.h

Contains functions for logging errors.

object.h

Contains functions for reading obj.conf. You'll rarely use these functions.

objset.h

Contains functions for reading obj.conf. You'll rarely use these functions.

protocol.h

Contains functions that perform protocol-specific actions.

req.h

Contains request data structures.

Header File

Description

cache.h (Unix Only)

Contains functions that manage proxy caching.

cif.h (Unix Only)

Contains functions for cache information file management.

cutil.h (Unix Only)

Contains cache utility functions.

fs.h (Unix Only)

Contains functions the proxy uses to access the file system.

Header File

Description

netsite.h

Contains miscellaneous functions and some vital definitions. Be sure to include this in all your .c files, to make sure that the necessary definitions (#defines) are established.

">

Table 17-1    Header files in the base directory

Header File

Description

buffer.h

Contains functions that buffer I/O (input/output) for a file or a socket descriptor.

cinfo.h

Contains functions for object typing, specifically mapping files to MIME types.

crit.h

Contains functions for managing critical sections, an abstraction that facilitates the management of threaded servers.

daemon.h

Contains functions called from other header files. It also contains functions that manage group processes that run the server.

ereport.h

Contains functions that handle low-level errors.

file.h

Contains functions to handle file I/O.

net.h

Contains functions for I/O with the client software over the network.

pblock.h

Contains functions that manage parameter passing and server internal variables. It also contains functions to get values from a user via the server.

pool.h

Contains routines that manage memory pools.

regexp.h

Contains functions that support regular expressions.

sem.h

Contains semaphores in platform-independent ways (they prevent two processes from doing the same thing).

session.h

Contains session data structures for IP addresses, security, and so on.

shexp.h

Contains functions to customize wildcard patterns through parsed data.

shmem.h

Contains functions that support shared memory.

systems.h

Contains functions that handle systems information.

systhr.h

Contains functions that support the abstract threading mechanism.

util.h

Contains utility functions.

Header File

Description

conf.h

Contains functions to access magnus.conf (for example, to get port numbers or internal global variables).

func.h

Contains data structures. This file is rarely used.

http.h

Contains functions for the HTTP protocol. Most of these functions are called from functions in protocol.h.

log.h

Contains functions for logging errors.

object.h

Contains functions for reading obj.conf. You'll rarely use these functions.

objset.h

Contains functions for reading obj.conf. You'll rarely use these functions.

protocol.h

Contains functions that perform protocol-specific actions.

req.h

Contains request data structures.

Header File

Description

cache.h (Unix Only)

Contains functions that manage proxy caching.

cif.h (Unix Only)

Contains functions for cache information file management.

cutil.h (Unix Only)

Contains cache utility functions.

fs.h (Unix Only)

Contains functions the proxy uses to access the file system.

Header File

Description

netsite.h

Contains miscellaneous functions and some vital definitions. Be sure to include this in all your .c files, to make sure that the necessary definitions (#defines) are established.

Getting Data From the Server: The Parameter Block

The server stores variables in name-value pairs. The parameter block, or pblock, is a hash table keyed on the name string. The pblock maps these name strings onto their value character strings.

Basically, your plug-in functions use parameter blocks to get, change, add, and remove name-value pairs of data. In order to use the functions to do these actions, you need to know a bit about how the hash table is formed and how the data structures are managed.

The pb_param structure is used to manage the name-value pairs for each client request. The pb_entry structure creates linked lists of pb_param structures. See The Session Data Structure for more information.

Passing Parameters to Server Application Functions

All server application functions (regardless of class) are described by this prototype:

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

pb is the parameter block containing the parameters given by the site administrator for this function invocation.



Caution

The pb parameter should be considered read-only, and any data modification should be performed on copies of the data. Doing otherwise is unsafe in threaded server architectures and will yield unpredictable results in multiprocess server architectures.



Parameter-manipulating Functions

When adding, removing, editing, and creating name-value pairs, you use the following functions. This list might seem overwhelming, but you'll use only a handful of these functions in your plug-in functions.

The param_create function creates a parameter with the given name and value. If the name and value aren't null, they are copied and placed in the new pb_param structure.

The param_free function frees a given parameter if it's non-NULL. It is also useful for error checking before using the pblock_remove function.

The pblock_create function creates a new parameter block with a hash table of a chosen size.

The pblock_free function frees a given parameter block and any entries inside it.

The pblock_find function finds the name-value entry with the given name in a given parameter block.

The pblock_findval function finds the value portion of a name-value entry with a given name in a given parameter block and returns its value.

The pblock_remove function behaves like the pblock_find function, but when it finds the given parameter block, it removes it.

The pblock_nninsert and pblock_nvinsert functions both create a new parameter with a given name and value and insert it in a given parameter block. The pblock_nninsert function requires that the value be an integer, but the pblock_nvinsert function accepts a string.

The pblock_pinsert function inserts a parameter in a parameter block.

The pblock_str2pblock function scans the given string for parameter pairs in the format name=value or name="value".

The pblock_pblock2str function places all of the parameters in the given parameter block in the given string. Each parameter is of the form name="value" and is separated by a space from any adjacent parameter.

Data Structures and Data Access Functions

The data structures are Session (see The Session Data Structure) and Request (see The Request Data Structure). The data access function is request_header.

The Request->vars parameter block contains the server's working variables. The set of active variables is different depending on which step of the request the server is processing.

The Request->reqpb parameter block contains the request parameters that are sent by the client:

  • method is the HTTP method used to access the object. Valid HTTP methods are currently GET, HEAD, and POST.
  • uri is the URI for which the client asks. The uri is the part of the URL following the host:port combination. This uri is unescaped by the server using URL translations.
  • protocol identifies the protocol the client is using.
  • clf-request is the full text of the first line of the client's request. This is used for logging purposes.

The Request->headers parameter block contains the client's HTTP headers. HTTP sends any number of headers in this form (RFC 822):

Name: value

If more than one header has the same name, then they are concatenated with commas:

Name: value1, value2

The parameter block is keyed on the fully lowercase version of the name string without the colon.

The Request_header Function

The request_header function finds the parameter block that contains the client's HTTP headers.

#include "frame/req.h"

int request_header(char *name, char **value, Session *sn, Request *rq);

The name parameter should be the lowercase header name string for which to look, and value is a pointer to your char * that should contain the header. If no header with the given name is sent, value is set to NULL.

The Request->srvhdrs parameter block is the set of HTTP headers for the server to send back. This parameter block can be modified by any function.

The last three entries in the Request structure should be considered transparent to application code because they are used by the server's base code.

After the server has a path for the file it intends to return, application functions should use the request_stat_path function to obtain stat information about the file. This avoids multiple, unnecessary calls to the stat function.

Application Function Status Codes

When your plug-in function is done working with the name-value pairs, it must return a code that tells the server how to proceed with the request.

Reporting Errors to the Server

When problems occur, server application functions should set an HTTP response status code to give the client an idea of what went wrong. The function should also log an error in the error log file.

There are two ways of reporting errors: setting a response status code and reporting an error.

Setting an HTTP Response Status Code

The protocol_status function sets the status to the code and reason string. If the reason is NULL, the server attempts to match a string with the given status code (see Table 17-2). If the server can't find a string, it uses "Unknown error."

#include "frame/protocol.h"
void protocol_status(Session *sn, Request *rq, int n, char *r);

Generally, protocol_status will be called with a NULL reason string, and one of the following status codes defined in the protocol.h file. If no status is set or the code is set as NULL, the default is PROTOCOL_SERVER_ERROR.)

Table 17-2    Status codes used with protocol_status

Status code

Definition

PROTOCOL_BAD_REQUEST

The request was unintelligible. Used primarily in the framework library.

PROTOCOL_FORBIDDEN

The client is explicitly forbidden to access the object and should be informed of this fact.

PROTOCOL_NOT_FOUND

The server was unable to locate the item requested.

PROTOCOL_NOT_IMPLEMENTED

The client has asked the server to perform an action that it knows it cannot do. Generally, you would use this to indicate your refusal to implement an HTTP feature.

PROTOCOL_NOT_MODIFIED

If the client gave a conditional request, such as an HTTP request with the if-modified-since header, this indicates that the client should use its local copy of the data.

PROTOCOL_OK

Normal status; the request will be fulfilled normally. This should be set only by Service-class functions.

PROTOCOL_REDIRECT

The client should be directed to a new URL, which your function should insert into the rq->vars parameter block as url.

PROTOCOL_SERVER_ERROR

Some sort of server-side error has occurred. Possible causes include misconfiguration, resource unavailability, and so on. Any error unrelated to the client generally falls under this rather broad category.

PROTOCOL_UNAUTHORIZED

The client did not give sufficient authorization for the action it was trying to perform. A WWW-authenticate header should be present in the rq->srvhdrs parameter block that indicates to the client the level of authorization it needs to perform its action.

Error Reporting

When errors occur, it's customary to report them in the server's error log file. To do this, your plug-in functions should call log_error. This logs an error and then returns to tell you if the log records successfully (a return value of 0 means success; -1 means failure).

#include "frame/log.h"

int log_error(int degree, char *func, Session *sn, Request *rq,

char *fmt, ...);

You can give log_error any printf( ) style string to describe the error. If an error occurs after a system call, use the following function to translate an error number to an error string:

#include "base/file.h"

char *system_errmsg(SYS_FILE fd );



Note

The fd parameter is vestigial and might need to be changed for operating systems other than Unix and Windows NT. Therefore, it is best to set fd to zero.



Compiling and Linking Your Code

You can compile your code with any ANSI C compiler. See the makefile in the /nsapi/include directory. The make file assumes the use of gmake.

This section lists the linking options you need to use in order to create a Unix shared object. The server can be instructed to load by commands in the magnus.conf configuration file.

Table 17-3 describes the commands used to link object files into a shared object under the various Unix platforms. In these examples, the compiled object files t.o and u.o are linked to form a shared object called test.so.

Table 17-3    Options for linking

System

Compile options

Solaris

ld -G t.o u.o -o test.so

HP-UX

ld -b t.o u.o -o test.so

When compiling your code, you must also use the +z flag to the HP C compiler.

AIX

cc -bM:SRE -berok t.o u.o -o test.so -bE:ext.exp -lc

The ext.exp file must be a text file with the name of a function that is externally accessible for each line.

Loading Your Shared Object

After you've compiled your code, you need to tell the server to load the shared object and its functions so that you can begin using your plug-in functions in obj.conf.

When the server starts, it uses obj.conf to get its configuration information. To tell the server to load your shared object and functions in the shared object, you add this line to obj.conf:

Init fn=load-modules shlib=[path]filename.so funcs="function1,function1,...,functionN"

This initialization function opens the given shared object file and loads the functions function1, function2, and so on. You then use the functions function1 and function2 in the server configuration files (either magnus.conf or obj.conf). Remember to use the functions only with the directives for which you wrote them, as described in the following section.

Using Your Plug-in Functions

When you have compiled and arranged for the loading of your functions, you need to provide for their execution. All functions are called as follows:

Directive fn=function [name1=value1] ... [nameN=valueN]

  • Directive identifies the class of function that is being called. Functions should not be called from the wrong directive!
  • fn=function identifies the function to be called using the function's unique character-string name.

These two parameters are mandatory. After this, there may be an arbitrary number of function-specific parameters, each of which is a name-value pair.

You specify your function in the directive for which it was written. For example, the following line uses an AddLog-class plug-in function called myaddlog that adds an entry to a log file called mylogfile. The plug-in function accepts another parameter that defines how much information to log.

AddLog fn=myaddlog name="mylogfile" type="maxinfo"


Previous      Contents      Index      Next     
Copyright 2002 Sun Microsystems, Inc. All rights reserved.