.\" Copyright (c) 2010-2016 Hypertriton, Inc.
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
.\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
.\" INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
.\" (INCLUDING BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
.\" SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
.\" STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
.\" IN ANY WAY OUT OF THE USE OF THIS SOFTWARE EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
.Dd October 9, 2004
.Dt PERCGI 3
.Os
.ds vT PerCGI API Reference
.ds oS PerCGI 2.0
.Sh NAME
.Nm percgi
.Nd Framework for web application servers
.Sh SYNOPSIS
.Bd -literal
#include
.Ed
.Sh DESCRIPTION
The
.Nm
library provides the basic building blocks for building high-performance
web application servers in C and C-based languages.
PerCGI implements:
.Pp
.Bl -bullet -compact
.It
CGI/FastCGI Interface
.It
Authentication
.It
Session Management
.It
Modular Query Processing
.It
Input/Output Content Filters
.It
Input Filter: Variable substitution
.It
HTTP Language Negotiation
.It
HTTP Content Negotiation
.It
HTTP Cookies
.It
Validation
.El
.Sh INITIALIZATION
.nr nS 1
.Ft void
.Fn CGI_Init "CGI_Application *cgi"
.Pp
.Ft void
.Fn CGI_Exit "int exit_code" "const char *errmsg_fmt" "..."
.nr nS 0
.Pp
The
.Fn CGI_Init
function initializes the PerCGI library, and should be called prior to invoking
any other
.Nm
functions.
The
.Ft CGI_Application
argument should point to the following structure:
.Bd -literal
typedef struct cgi_application {
const char *name; /* Description */
const char *copyright; /* Copyright notice */
const char *availLangs[CGI_LANGS_MAX]; /* Available languages */
const char *homeOp; /* Default operation */
Uint flags;
#define CGI_PERSISTENT 0x02 /* Only run under FastCGI */
#define CGI_PRETTY_URL 0x04 /* Use "/op?args" instead of
"/path/to/prog.fcgi?op=op&args" */
void (*destroyFn)(void);
void (*logFn)(enum cgi_loglvl, const char *);
} CGI_Application;
.Ed
.Pp
The
.Va availLangs
list contains the set of languages (ISO 639) which are supported by the
application, and which should be offered for HTTP language negotiation.
.Pp
The
.Va homeOp
field specifies the default operation to invoke after a user has
successfully logged in (usually "home" or "index").
.Pp
.Dv CGI_PERSISTENT
indicates that the application must run under FastCGI, and will
abort if FastCGI support was not compiled in.
.Pp
The
.Dv CGI_PRETTY_URL
option enables URLs of the form "/op?args", instead of the standard
"/path/to/prog.fcgi?op=op&args" form.
With Apache httpd 2.4, it is possible to start the
.Nm
application using
.Xr fcgistarter 8
and simply match "/" with the
.Dv ProxyPass
directive, like so:
.Bd -literal
ProxyPass / fcgi://127.0.0.1:4123/
ProxyPass /static/ !
ProxyPass /images/ !
.Ed
.Pp
The
.Fn destroyFn
callback, if defined, will be invoked before the application terminates.
.Pp
The
.Fn logFn
method, if defined, overrides the default behavior of
.Fn CGI_Log .
.Pp
The
.Fn CGI_Exit
function frees allocated resources and terminates the CGI application with
the given
.Fa exit_code
and optional error message.
.Sh ERROR HANDLING
.nr nS 1
.Ft void
.Fn CGI_SetError "const char *fmt" "..."
.Pp
.Ft "char *"
.Fn CGI_GetError "void"
.nr nS 0
.Pp
The
.Fn CGI_SetError
function sets the current error message.
.Fn CGI_GetError
retrieves the last error message.
.Sh HTTP QUERY HANDLING
.nr nS 1
.Ft "void"
.Fn CGI_QueryInit "CGI_Query *q"
.Pp
.Ft "void"
.Fn CGI_QueryDestroy "CGI_Query *q"
.Pp
.Ft "int"
.Fn CGI_ReadQueryHTTP "CGI_Query *q"
.Pp
.Ft "int"
.Fn CGI_ExecQuery "CGI_Query *q" "CGI_SessionOps *sess"
.Pp
.Ft void
.Fn CGI_QueryDestroy "CGI_Query *q"
.Pp
.Ft void
.Fn CGI_WriteHeader "CGI_Query *q" "const char *contentType" "const char *charset" "int setCookies"
.Pp
.Ft void
.Fn CGI_WriteHeaderHTML "CGI_Query *q"
.Pp
.Ft ssize_t
.Fn CGI_WriteData "CGI_Query *q" "void *data" "size_t len"
.nr nS 0
.Pp
.Fn CGI_QueryInit
initializes a query structure.
.Fn CGI_QueryDestroy
releases resources allocated by a query structure.
.Pp
The
.Fn CGI_ReadQueryHTTP
function accepts an HTTP request from the web server, parses any script
arguments and initializes the
.Ft CGI_Query
structure argument according to the new request.
The function returns 0 on success or -1 if an error occured.
.Pp
The
.Fn CGI_ExecQuery
routine handles a query in the standard way, by invoking the appropriate
module call.
It is assumed that standard
.Nm
session management is used (see
.Dq SESSION MANAGEMENT
section).
It is not mandatory for queries to be processed by
.Fn CGI_ExecQuery .
.Pp
The
.Fn CGI_WriteHeader
function selects the specified Content-Type / character set, and writes HTTP
response headers to the client.
If
.Fa setCookie
is 1, "Set-Cookie" headers are emitted (see
.Fn CGI_SetCookie ) .
.Pp
The
.Fn CGI_WriteHeaderHTML
shorthand emits standard headers for text/html, and is equivalent to:
.Bd -literal
CGI_WriteHeader(q, "text/html", "utf-8", 1);
.Ed
.Pp
The
.Fn CGI_Write
routine writes
.Fa len
bytes of
.Fa data
to the client.
If registered output filters match the current "Content-Type", those
filters are applied before writing the data.
.Sh CGI ARGUMENTS
.nr nS 1
.Ft "const char *"
.Fn CGI_Get "CGI_Query *q" "const char *key" "size_t max"
.Pp
.Ft "const char *"
.Fn CGI_GetTrim "CGI_Query *q" "const char *key" "size_t max"
.Pp
.Ft "int"
.Fn CGI_GetBool "CGI_Query *q" "const char *key"
.Pp
.Ft "int"
.Fn CGI_GetInt "CGI_Query *q" "const char *key" "int *rv"
.Pp
.Ft "int"
.Fn CGI_GetIntR "CGI_Query *q" "const char *key" "int *rv" "int min" "int max"
.Pp
.Ft "int"
.Fn CGI_GetIntRange "CGI_Query *q" "const char *key" "int *rvMin" "const char *sep" "int *rvMax"
.Pp
.Ft "int"
.Fn CGI_GetEnum "CGI_Query *q" "const char *key" "Uint *rv" "Uint last"
.Pp
.Ft "int"
.Fn CGI_GetFloat "CGI_Query *q" "const char *key" "float *rv"
.Pp
.Ft "int"
.Fn CGI_GetDouble "CGI_Query *q" "const char *key" "double *rv"
.Pp
.Ft "char *"
.Fn CGI_EscapeURL "CGI_Query *q" "const char *url"
.Pp
.Ft "char *"
.Fn CGI_UnescapeURL "CGI_Query *q" "const char *url"
.Pp
.Ft "CGI_KeySet *"
.Fn CGI_GetKeySet "CGI_Query *q" "const char *key_pattern"
.Pp
.Ft void
.Fn CGI_FreeKeySet "CGI_KeySet *set"
.nr nS 0
.Pp
The
.Fn CGI_Get
function returns the value of the given CGI argument (either GET or POST).
If the argument does not exist, or it exceeds
.Fa len - 1
bytes in size,
.Fn CGI_Get
returns NULL and sets the error message accordingly.
The
.Fn CGI_GetTrim
variant strips any leading and terminating whitespace from the token.
Bounds checking is performed against the stripped token.
.Pp
The
.Fn CGI_GetBool
variant returns 1 if the given argument exists and has a value of "y".
.Pp
The
.Fn CGI_GetInt ,
.Fn CGI_GetIntR ,
.Fn CGI_GetFloat
and
.Fn CGI_GetDouble
functions parse and validate a numerical argument.
If the number is valid, they return 0 and write the value to
.Fa rv .
If the number is malformed or out of range, they return -1 and set an
error message.
The
.Fn CGI_GetIntR
variant fails if the value lies outside of the specified range.
.Pp
The
.Fn CGI_GetIntRange
function parses an argument which may be a single integer or a range
bounded by two numbers separated by any of the characters in
.Fa sep
(typically "-").
If the range is negative (pMin > pMax), the function will fail
returning an error.
.Pp
The
.Fn CGI_GetEnum
routine is a shorthand for
.Fn CGI_GetIntR
with min=0, which also fails if the return value is greater than the
.Fa last
argument.
.Pp
The
.Fn CGI_EscapeURL
function substitutes illegal URL characters as described by RFC1738.
.Fn CGI_UnescapeURL
substitutes escape codes for the character they represent, except for
NUL sequences which are replaced by underscores to avoid truncation.
.Pp
The
.Fn CGI_GetKeySet
function returns the set of arguments whose key start with the given
pattern.
It is useful for things like checkboxes in HTML forms.
The
.Ft CGI_KeySet
structure is defined as:
.Bd -literal
typedef struct cgi_keyset {
char **ents;
int nents;
} CGI_KeySet;
.Ed
.Pp
The application should use
.Fn CGI_FreeKeySet
when done with the data.
.Sh CONTENT FILTERING
.nr nS 1
.Ft void
.Fn CGI_AddFilter "CGI_Filter *filter"
.Pp
.Ft void
.Fn CGI_DelFilter "CGI_Filter *filter"
.nr nS 0
.Pp
The
.Fn CGI_AddFilter
function registers a content filtering function which should process either
data read by the script or data written to the output, which matches the
given MIME type.
Filters are useful for compression and certain types of substitutions.
.Pp
The argument of
.Fn CGI_AddFilter
is a pointer to the following structure:
.Bd -literal
typedef struct cgi_filter {
enum cgi_filter_type {
CGI_INPUT_FILTER, /* Filter data read by the script */
CGI_OUTPUT_FILTER /* Filter data written to stdout */
} type;
char *content_type; /* Apply to data of this type */
size_t (*func)(CGI_Query *q, void **data, size_t len);
} CGI_Filter;
.Ed
.Pp
The
.Fn CGI_DelFilter
function removes the specified content filter.
.Sh HTML OUTPUT
The most common operation in a PerCGI query is the servicing of
precompiled, performatted HTML data (with "$foo" style references in it).
.Bd -literal
.Ft void
.Fn HTML_SetDirectory "CGI_Query *q" "const char *path"
.Pp
.Ft void
.Fn HTML_Output "CGI_Query *q" "const char *document"
.Pp
.Ft void
.Fn HTML_OutputError "CGI_Query *q" "const char *fmt" "..."
.Pp
.Ft void
.Fn HTML_SetError "const char *fmt" "..."
.Pp
.Ft void
.Fn HTML_SetSuccess "const char *fmt" "..."
.Pp
.Ed
.Fn HTML_SetDirectory
can be used to set the default directory to search for HTML documents
and fragments (defaults to
.Pa html/ ) .
.Pp
The
.Fn HTML_Output
function writes an HTML document to the standard output (assuming the HTTP
headers have already been emitted).
.Pp
The
.Fn HTML_OutputError
function outputs an HTML document containing only the given error message.
.Pp
.Fn HTML_SetError
sets the built-in variable $_error to the given error message.
Whenever $_error is defined, the HTML template is expected to display a
closable error dialog in a suitable location (usually on top of the document).
.Fn HTML_SetSuccess
works the same, except $_error is set to a success-type message.
.Sh VARIABLE SUBSTITUTION
PerCGI provides one standard content filter, which is an Input filter
named
.Va varsubst .
This filter is used by
.Fn HTML_Output
to substitute instances of "$foo" in the HTML input, for the value of
the corresponding
.Nm
variable (per the interface described below).
.Va varsubst
also provides a handy gettext-style internationalization operator, "$_()".
Instances of "$_(Some text)" in the sources will be replaced by the
corresponding gettext translation (per the user's language settings).
.Pp
Variables are managed by PerCGI and described as:
.Bd -literal
typedef struct var {
char key[VAR_NAME_MAX]; /* Variable name */
char *value; /* Variable value */
size_t len; /* Length in characters */
size_t bufSize; /* Total buffer size */
int global; /* Persist across queries */
TAILQ_ENTRY(var) vars;
} VAR;
.Ed
.Pp
The API is as follows.
Note that the VAR_ prefix can be omitted if compiling with
.Dv _USE_PERCGI_VAR
defined.
.Pp
.nr nS 1
.Ft "VAR *"
.Fn VAR_New "const char *key"
.Pp
.Ft "VAR *"
.Fn VAR_Set "const char *key" "const char *fmt" "..."
.Pp
.Ft "VAR *"
.Fn VAR_SetS "const char *key" "const char *s"
.Pp
.Ft "VAR *"
.Fn VAR_SetS_NODUP "const char *key" "char *s"
.Pp
.Ft "VAR *"
.Fn VAR_SetGlobal "const char *key" "const char *fmt" "..."
.Pp
.Ft "VAR *"
.Fn VAR_SetGlobalS "const char *key" "const char *s"
.Pp
.Ft void
.Fn VAR_Cat "VAR *v" "const char *fmt" "..."
.Pp
.Ft void
.Fn VAR_CatS "VAR *v" "const char *s"
.Pp
.Ft void
.Fn VAR_CatS_NODUP "VAR *v" "char *s"
.Pp
.Ft void
.Fn VAR_Wipe "const char *key"
.Pp
.Ft void
.Fn VAR_Unset "const char *key"
.Pp
.Ft int
.Fn VAR_Defined "const char *key"
.Pp
.Ft void
.Fn VAR_Free "VAR *var"
.Pp
.nr nS 0
.Pp
.Fn VAR_New
creates a new variable.
The variable is initially undefined.
.Pp
.Fn VAR_Set
sets the value of a variable from a format string argument.
.Fn VAR_SetS
accepts a C string.
The
.Fn VAR_SetS_NODUP
routine accepts a pointer to user memory (which should remain accessible
as long as the variable is in use).
.Pp
The scope of variables set by
.Fn VAR_Set
is limited to the current
.Ft CGI_Query .
The
.Fn VAR_SetGlobal
and
.Fn VAR_SetGlobalS
variants set a "global" variable remains persistent across queries.
This is useful for static or semi-static content which needs to be
regenerated infrequently.
It is customary to define globals for limits such as
.Dv CGI_USERNAME_MAX ,
from the
.Fn init
method of a
.Ft CGI_Module .
.Pp
The
.Fn VAR_Cat
and
.Fn VAR_CatS
functions append a string to an existing variable.
The
.Fn VAR_CatS_NODUP
variant frees the provided string after it has been appended.
.Pp
For variable substitution to work, variables should be set prior to
calling
.Fn HTML_Output .
For example, the following assumes that the login_form HTML document
contains one or more instances of "$username" and "$password", to
be substituted:
.Bd -literal
SetS("username", "nobody");
SetS("password", "");
HTML_Output("login_form");
VAR_Wipe("password");
.Ed
.Pp
The
.Fn VAR_Wipe
routine wipes the memory currently used by the given variable.
It is recommended to call
.Fn VAR_Wipe
on variables that have been storing sensitive information such as passwords,
once the variable is no longer needed.
.Pp
.Fn VAR_Unset
searches for the named variable.
If the variable is found, it is deleted and freed.
.Pp
The
.Fn VAR_Defined
function evaluates to 1 if the named variable exists, otherwise returns 0.
.Pp
The
.Fn VAR_Free
routine frees all resources allocated by a variable.
Note that this is already done internally by PerCGI when
.Fn VAR_Unset
is called or whenever a query has been completed.
.Fn VAR_Free
should only be used to free anonymous variables (variables with key = NULL
which are not managed by PerCGI).
For example:
.Bd -literal
VAR *v;
v = SetS(NULL, "Foo"); /* Anonymous variable */
VAR_CatS(v, " bar");
VAR_Free(v);
.Ed
.Sh OUTPUT AND LOGGING
.nr nS 1
.Ft ssize_t
.Fn CGI_Write "CGI_Query *q" "const void *data" "size_t len"
.Pp
.Ft void
.Fn CGI_Printf "CGI_Query *q" "const char *fmt" "..."
.Pp
.Ft void
.Fn CGI_PutS "CGI_Query *q" "const char *s"
.Pp
.Ft void
.Fn CGI_PutC "CGI_Query *q" "char c"
.nr nS 0
.Pp
The
.Fn CGI_Write
function writes
.Fa len
bytes from
.Fa data
to the client.
It returns 0 on success, or -1 if an I/O error or EOF prevented all
.Fa len
bytes from being written.
.Pp
.Fn CGI_Write
applies any output filters matching the current "Content-Type".
.Pp
.Fn CGI_Printf
writes a
.Xr printf 3
formatted string to the client,
.Fn CGI_PutS
writes a C string, and
.Fn CGI_PutC
writes a character.
.Pp
.Sh LOGGING
.nr nS 1
.Ft void
.Fn CGI_Log "enum cgi_loglvl log_level" "const char *fmt" "..."
.Pp
.Ft void
.Fn CGI_LogErr "const char *fmt" "..."
.Pp
.Ft void
.Fn CGI_LogWarn "const char *fmt" "..."
.Pp
.Ft void
.Fn CGI_LogInfo "const char *fmt" "..."
.Pp
.Ft void
.Fn CGI_LogNotice "const char *fmt" "..."
.Pp
.Ft void
.Fn CGI_LogDebug "const char *fmt" "..."
.nr nS 0
.Pp
The
.Fn CGI_Log
function appends an entry to the application's logfile.
The
.Fa log_level
argument is one of:
.Bd -literal
enum cgi_loglvl {
CGI_LOG_EMERG,
CGI_LOG_ALERT,
CGI_LOG_CRIT,
CGI_LOG_ERR,
CGI_LOG_WARNING,
CGI_LOG_NOTICE,
CGI_LOG_INFO,
CGI_LOG_DEBUG
};
.Ed
.Pp
The
.Fn CGI_LogErr ,
.Fn CGI_LogWarn ,
.Fn CGI_LogInfo ,
.Fn CGI_LogNotice
and
.Fn CGI_LogDebug
shorthands are also provided.
.Sh SESSION MANAGEMENT
.nr nS 1
.Ft void
.Fn CGI_SessionInit "CGI_Session *sess" "CGI_SessionOps *ops"
.Pp
.Ft void
.Fn CGI_SessionDestroy "CGI_Session *sess"
.Pp
.Ft void
.Fn CGI_CloseSession "CGI_Session *sess"
.Pp
.Ft int
.Fn CGI_SessionLoad "CGI_Session *sess" "int fd"
.Pp
.Ft int
.Fn CGI_SessionSaveToFD "CGI_Session *sess" "int fd"
.Pp
.Ft int
.Fn CGI_SessionSave "CGI_Session *sess"
.Pp
.Ft int
.Fn CGI_SetSV "CGI_Session *sess" "const char *key" "const char *fmt" "..."
.Pp
.Ft int
.Fn CGI_SetSV_S "CGI_Session *sess" "const char *key" "const char *s"
.Pp
.Ft int
.Fn CGI_SetSV_ALL "CGI_SessionOps *ops" "const char *user" "const char *key" "const char *value"
.Pp
.nr nS 0
The
.Fn CGI_SessionInit
routine initializes the given
.Ft CGI_Session
structure.
The
.Fa ops
argument should point to the following structure, which describes a
session manager class.
All operations are optional, but unused methods should be initialized to NULL.
.Pp
.Bd -literal
typedef struct cgi_session_ops {
const char *name; /* Description */
size_t size; /* Structure size */
Uint flags;
#define CGI_SESSION_PREFORK_AUTH 0x01 /* Call auth() before fork() */
void (*init)(void *s);
void (*destroy)(void *s);
int (*load)(void *s, int fd);
void (*save)(void *s, int fd);
int (*auth)(void *s, const char *user, const char *pass);
void (*authRegister)(CGI_Query *q); const char *authRegisterName;
void (*authRegConfirm)(CGI_Query *q); const char *authRegConfirm;
void (*authAssist)(CGI_Query *q); const char *authAssistName;
void (*authRequest)(CGI_Query *q); const char *authRequestName;
void (*authConfirm)(CGI_Query *q); const char *authConfirmName;
void (*authCommit)(CGI_Query *q); const char *authCommitName;
int (*sessOpen)(void *s);
void (*sessClose)(void *s);
void (*sessExpired)(void *s);
void (*beginQueryUnauth)(CGI_Query *q, const char *op);
void (*loginPage)(CGI_Query *q);
void (*logout)(CGI_Query *q);
void (*addSelectFDs)(void *s, fd_set *r, fd_set *w, int *maxfds);
void (*procSelectFDs)(void *s, fd_set *r, fd_set *w);
} CGI_SessionOps;
.Ed
.Pp
The
.Va name
is an arbitrary string which identifies the session manager.
.Va size
should be set to the size of the
.Ft CGI_SessionOps
structure (or derivative thereof).
.Pp
The
.Va flags
options apply to all session manager instances.
If the
.Dv CGI_SESSION_PREFORK_AUTH
flag is set, the
.Fn auth
call will be made prior to
.Xr fork 2 .
This is recommended when using local methods of authentication
(i.e., password files), as opposed to methods that involve estalishing
a network connection.
.Pp
The
.Fn init
callback is invoked at initialization time and is expected to
initialize any extra members of structures derived from
.Ft CGI_SessionOps .
.Pp
.Fn destroy
should release all resources previously allocated by
.Fn init .
.Pp
The serialization routines
.Fn load
and
.Fn save
are invoked whenever the session file is read from, or written to the disk
file referenced by
.Fa fd .
They are useful for session managers which need to save other data
(in addition to the session variables).
The extra data will follow the list of session variables in the session file.
.Pp
Password authentication is handled by the
.Fn auth
operation, which should return 0 if
.Fa user
and
.Fa pass
are correct, or -1 otherwise.
.Pp
The
.Fn authRegister
operation is expected to process POSTDATA from a subscription form
where new users can request an account.
It should perform validation on the request data, generate a new
authentication token and e-mail a link
(a link to the
.Fn authRegConfirm
operation), to the user.
.Pp
The
.Fn authRegConfirm
operation is expected to validate the token and complete the
registration request.
.Pp
The following methods implement password recovery, to assist users
in recovering lost passwords.
.Fn authAssist
is expected to display a password recovery form (which submits to
.Fn authRequest ) .
The
.Fn authRequest
should generate a random token and e-mail it to the contact e-mail address
(or perform validation using some alternate mechanism if desired).
.Pp
The verification e-mail should be a link to the
.Fn authConfirm
operation.
Given a valid token, this operation is expected to generate a form prompting
for the security question (if one has been set), in addition to the
"New password" field.
This form should submit the token, answer to the security question, and
password to the
.Fn authCommit
operation.
.Pp
The
.Fn sessOpen
function is invoked after authentication and successful creation of a new
session.
If it returns a value other than 0, the new session will be aborted.
.Pp
.Fn sessClose
is invoked after a session has been terminated.
If a session has been terminated due to an inactivity time-out,
.Fn sessExpired
is also invoked.
.Pp
The
.Fn beginQueryUnauth
method may be used to override the default code used to initialize the
standard globals such as $_error, $_user, $_lang and $_modules in an
unauthenticated session.
.Pp
The
.Fn loginPage
method is expected to display the standard "Log in" form.
When a user gracefully logs out using "Log out", the
.Fn logout
method is called and is expected to display a confirmation message.
.Pp
.Fn addSelectFDs
and
.Fn procSelectFDs
are hooks into the standard event loop of
.Nm
(which is
.Xr select 2
based).
.Fn addSelectFDs
can add additional file descriptors to
.Fa rd
or
.Fa wr
using
.Xr FD_SET 2
(it should not modify the existing set).
.Pp
The
.Fn procSelectFDs
callback is invoked following a return from
.Xr select 2 ,
and may test the returned sets using
.Xr FD_ISSET 2 .
.Pp
.Fn CGI_SessionDestroy
releases all resources allocated by a session.
.Pp
The
.Fn CGI_CloseSession
routine closes the given session.
.Pp
The serialization routines
.Fn CGI_SessionLoad
and
.Fn CGI_SessionSave
respectively read and write session data (including all session variables)
from/to file.
.Pp
The
.Fn CGI_SetSV
routine sets the named session variable to the value (specified as a
.Xr printf 3
format string).
The
.Fn CGI_SetSV_S
variants accepts a C string argument.
.Pp
The
.Fn CGI_SetSV_ALL
routine sets the named session variable similarly to
.Fn CGI_SetSV ,
except the change applies to all sessions currently opened by
.Fa user .
.Sh HISTORY
The
.Nm
interface was first developed in 2003 (at csoft.net), under the name
of csoft-cgi.