percgi



PERCGI(3)                  Library Functions Manual                  PERCGI(3)


NAME

     percgi - Framework for web application servers


SYNOPSIS

     #include <libpercgi/cgi.h>


DESCRIPTION

     The percgi library provides the basic building blocks for building high-
     performance web application servers in C and C-based languages.  PerCGI
     implements:

     o   CGI/FastCGI Interface
     o   Authentication
     o   Session Management
     o   Modular Query Processing
     o   Input/Output Content Filters
     o   Input Filter: Variable substitution
     o   HTTP Language Negotiation
     o   HTTP Content Negotiation
     o   HTTP Cookies
     o   Validation


INITIALIZATION

     void
     CGI_Init(CGI_Application *cgi);

     void
     CGI_Exit(int exit_code, const char *errmsg_fmt, ...);

     The CGI_Init() function initializes the PerCGI library, and should be
     called prior to invoking any other percgi functions.  The CGI_Application
     argument should point to the following structure:

     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_HTML_ERRORS 0x01    /* Send HTML errors to stdout */
     #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;

     The availLangs list contains the set of languages (ISO 639) which are
     supported by the application, and which should be offered for HTTP
     language negotiation.

     The homeOp field specifies the default operation to invoke after a user
     has successfully logged in (usually "home" or "index").

     The CGI_HTML_ERRORS flag causes errors to be output in HTML form.

     CGI_PERSISTENT indicates that the application must run under FastCGI, and
     will abort if FastCGI support was not compiled in.

     The 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 percgi application using fcgistarter(8)
     and simply match "/" with the ProxyPass directive, like so:

         ProxyPass / fcgi://127.0.0.1:4123/
         ProxyPass /static/ !
         ProxyPass /images/ !

     The destroyFn() callback, if defined, will be invoked before the
     application terminates.

     The logFn() method, if defined, overrides the default behavior of
     CGI_Log().

     The CGI_Exit() function frees allocated resources and terminates the CGI
     application with the given exit_code and optional error message.


ERROR HANDLING

     void
     CGI_SetError(const char *fmt, ...);

     char *
     CGI_GetError(void);

     The CGI_SetError() function sets the current error message.
     CGI_GetError() retrieves the last error message.


HTTP QUERY HANDLING

     void
     CGI_QueryInit(CGI_Query *q);

     void
     CGI_QueryDestroy(CGI_Query *q);

     int
     CGI_ReadQueryHTTP(CGI_Query *q);

     int
     CGI_ExecQuery(CGI_Query *q, CGI_SessionOps *sess);

     void
     CGI_QueryDestroy(CGI_Query *q);

     void
     CGI_WriteHeader(CGI_Query *q, const char *contentType,
         const char *charset, int setCookies);

     void
     CGI_WriteHeaderHTML(CGI_Query *q);

     ssize_t
     CGI_WriteData(CGI_Query *q, void *data, size_t len);

     CGI_QueryInit() initializes a query structure.  CGI_QueryDestroy()
     releases resources allocated by a query structure.

     The CGI_ReadQueryHTTP() function accepts an HTTP request from the web
     server, parses any script arguments and initializes the CGI_Query
     structure argument according to the new request.  The function returns 0
     on success or -1 if an error occured.

     The CGI_ExecQuery() routine handles a query in the standard way, by
     invoking the appropriate module call.  It is assumed that standard percgi
     session management is used (see ``SESSION MANAGEMENT'' section).  It is
     not mandatory for queries to be processed by CGI_ExecQuery().

     The CGI_WriteHeader() function selects the specified Content-Type /
     character set, and writes HTTP response headers to the client.  If
     setCookie is 1, "Set-Cookie" headers are emitted (see CGI_SetCookie()).

     The CGI_WriteHeaderHTML() shorthand emits standard headers for text/html,
     and is equivalent to:

     CGI_WriteHeader(q, "text/html", "utf-8", 1);

     The CGI_Write() routine writes len bytes of data to the client.  If
     registered output filters match the current "Content-Type", those filters
     are applied before writing the data.


CGI ARGUMENTS

     const char *
     CGI_Get(CGI_Query *q, const char *key, size_t max);

     const char *
     CGI_GetTrim(CGI_Query *q, const char *key, size_t max);

     int
     CGI_GetBool(CGI_Query *q, const char *key);

     int
     CGI_GetInt(CGI_Query *q, const char *key, int *rv);

     int
     CGI_GetIntR(CGI_Query *q, const char *key, int *rv, int min, int max);

     int
     CGI_GetIntRange(CGI_Query *q, const char *key, int *rvMin,
         const char *sep, int *rvMax);

     int
     CGI_GetEnum(CGI_Query *q, const char *key, Uint *rv, Uint last);

     int
     CGI_GetFloat(CGI_Query *q, const char *key, float *rv);

     int
     CGI_GetDouble(CGI_Query *q, const char *key, double *rv);

     char *
     CGI_EscapeURL(CGI_Query *q, const char *url);

     char *
     CGI_UnescapeURL(CGI_Query *q, const char *url);

     CGI_KeySet *
     CGI_GetKeySet(CGI_Query *q, const char *key_pattern);

     void
     CGI_FreeKeySet(CGI_KeySet *set);

     The CGI_Get() function returns the value of the given CGI argument
     (either GET or POST).  If the argument does not exist, or it exceeds len
     - 1 bytes in size, CGI_Get() returns NULL and sets the error message
     accordingly.  The CGI_GetTrim() variant strips any leading and
     terminating whitespace from the token.  Bounds checking is performed
     against the stripped token.

     The CGI_GetBool() variant returns 1 if the given argument exists and has
     a value of "y".

     The CGI_GetInt(), CGI_GetIntR(), CGI_GetFloat() and CGI_GetDouble()
     functions parse and validate a numerical argument.  If the number is
     valid, they return 0 and write the value to rv.  If the number is
     malformed or out of range, they return -1 and set an error message.  The
     CGI_GetIntR() variant fails if the value lies outside of the specified
     range.

     The 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 sep (typically "-").  If the range is negative (pMin >
     pMax), the function will fail returning an error.

     The CGI_GetEnum() routine is a shorthand for CGI_GetIntR() with min=0,
     which also fails if the return value is greater than the last argument.

     The CGI_EscapeURL() function substitutes illegal URL characters as
     described by RFC1738.  CGI_UnescapeURL() substitutes escape codes for the
     character they represent, except for NUL sequences which are replaced by
     underscores to avoid truncation.

     The 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 CGI_KeySet structure is defined as:

     typedef struct cgi_keyset {
             char    **ents;
             int      nents;
     } CGI_KeySet;

     The application should use CGI_FreeKeySet() when done with the data.


CONTENT FILTERING

     void
     CGI_AddFilter(CGI_Filter *filter);

     void
     CGI_DelFilter(CGI_Filter *filter);

     The 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.

     The argument of CGI_AddFilter() is a pointer to the following structure:

     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;

     The CGI_DelFilter() function removes the specified content filter.


HTML OUTPUT

     The most common operation in a PerCGI query is the servicing of
     precompiled, performatted HTML data (with "$foo" style references in it).

     void
     HTML_SetDirectory(CGI_Query *q, const char *path)

     void
     HTML_Output(CGI_Query *q, const char *document)

     void
     HTML_OutputError(CGI_Query *q, const char *fmt, ...)

     void
     HTML_SetError(const char *fmt, ...)

     void
     HTML_SetSuccess(const char *fmt, ...)

     HTML_SetDirectory() can be used to set the default directory to search
     for HTML documents and fragments (defaults to html/).

     The HTML_Output() function writes an HTML document to the standard output
     (assuming the HTTP headers have already been emitted).

     The HTML_OutputError() function outputs an HTML document containing only
     the given error message.

     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).  HTML_SetSuccess() works the same, except $_error is set
     to a success-type message.


VARIABLE SUBSTITUTION

     PerCGI provides one standard content filter, which is an Input filter
     named varsubst.  This filter is used by HTML_Output() to substitute
     instances of "$foo" in the HTML input, for the value of the corresponding
     percgi variable (per the interface described below).  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).

     Variables are managed by PerCGI and described as:

     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;

     The API is as follows.  Note that the VAR_ prefix can be omitted if
     compiling with _USE_PERCGI_VAR defined.

     VAR *
     VAR_Set(const char *key, const char *fmt, ...);

     VAR *
     VAR_SetS(const char *key, const char *s);

     VAR *
     VAR_SetS_NODUP(const char *key, char *s);

     VAR *
     VAR_SetGlobal(const char *key, const char *fmt, ...);

     VAR *
     VAR_SetGlobalS(const char *key, const char *s);

     void
     VAR_Cat(VAR *v, const char *fmt, ...);

     void
     VAR_CatS(VAR *v, const char *s);

     void
     VAR_CatS_NODUP(VAR *v, char *s);

     void
     VAR_Wipe(const char *key);

     void
     VAR_Unset(const char *key);

     int
     VAR_Defined(const char *key);

     void
     VAR_Free(VAR *var);

     VAR_Set() sets the value of a variable from a format string argument.
     VAR_SetS() accepts a C string.  The VAR_SetS_NODUP() routine accepts a
     pointer to user memory (which should remain accessible as long as the
     variable is in use).

     The scope of variables set by VAR_Set() is limited to the current
     CGI_Query.  The VAR_SetGlobal() and 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 CGI_USERNAME_MAX,
     from the init() method of a CGI_Module.

     The VAR_Cat() and VAR_CatS() functions append a string to an existing
     variable.  The VAR_CatS_NODUP() variant frees the provided string after
     it has been appended.

     For variable substitution to work, variables should be set prior to
     calling 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:

             SetS("username", "nobody");
             SetS("password", "");
             HTML_Output("login_form");
             VAR_Wipe("password");

     The VAR_Wipe() routine wipes the memory currently used by the given
     variable.  It is recommended to call VAR_Wipe() on variables that have
     been storing sensitive information such as passwords, once the variable
     is no longer needed.

     VAR_Unset() searches for the named variable.  If the variable is found,
     it is deleted and freed.

     The VAR_Defined() function evaluates to 1 if the named variable exists,
     otherwise returns 0.

     The VAR_Free() routine frees all resources allocated by a variable.  Note
     that this is already done internally by PerCGI when VAR_Unset() is called
     or whenever a query has been completed.  VAR_Free() should only be used
     to free anonymous variables (variables with key = NULL which are not
     managed by PerCGI).  For example:

             VAR *v;
             v = SetS(NULL, "Foo");          /* Anonymous variable */
             VAR_CatS(v, " bar");
             VAR_Free(v);


OUTPUT AND LOGGING

     ssize_t
     CGI_Write(CGI_Query *q, const void *data, size_t len);

     void
     CGI_Printf(CGI_Query *q, const char *fmt, ...);

     void
     CGI_PutS(CGI_Query *q, const char *s);

     void
     CGI_PutC(CGI_Query *q, char c);

     The CGI_Write() function writes len bytes from data to the client.  It
     returns 0 on success, or -1 if an I/O error or EOF prevented all len
     bytes from being written.

     CGI_Write() applies any output filters matching the current "Content-
     Type".

     CGI_Printf() writes a printf(3) formatted string to the client,
     CGI_PutS() writes a C string, and CGI_PutC() writes a character.


LOGGING

     void
     CGI_Log(enum cgi_loglvl log_level, const char *fmt, ...);

     void
     CGI_LogErr(const char *fmt, ...);

     void
     CGI_LogWarn(const char *fmt, ...);

     void
     CGI_LogInfo(const char *fmt, ...);

     void
     CGI_LogNotice(const char *fmt, ...);

     void
     CGI_LogDebug(const char *fmt, ...);

     The CGI_Log() function appends an entry to the application's logfile.
     The log_level argument is one of:

     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
     };

     The CGI_LogErr(), CGI_LogWarn(), CGI_LogInfo(), CGI_LogNotice() and
     CGI_LogDebug() shorthands are also provided.


SESSION MANAGEMENT

     void
     CGI_SessionInit(CGI_Session *sess, CGI_SessionOps *ops);

     void
     CGI_SessionDestroy(CGI_Session *sess);

     void
     CGI_CloseSession(CGI_Session *sess);

     int
     CGI_SessionLoad(CGI_Session *sess, int fd);

     int
     CGI_SessionSaveToFD(CGI_Session *sess, int fd);

     int
     CGI_SessionSave(CGI_Session *sess);

     int
     CGI_SetSV(CGI_Session *sess, const char *key, const char *fmt, ...);

     int
     CGI_SetSV_S(CGI_Session *sess, const char *key, const char *s);

     int
     CGI_SetSV_ALL(CGI_SessionOps *ops, const char *user, const char *key,
         const char *value);

     The CGI_SessionInit() routine initializes the given CGI_Session
     structure.  The 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.

     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;

     The name is an arbitrary string which identifies the session manager.
     size should be set to the size of the CGI_SessionOps structure (or
     derivative thereof).

     The flags options apply to all session manager instances.  If the
     CGI_SESSION_PREFORK_AUTH flag is set, the auth() call will be made prior
     to 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.

     The init() callback is invoked at initialization time and is expected to
     initialize any extra members of structures derived from CGI_SessionOps.

     destroy() should release all resources previously allocated by init().

     The serialization routines load() and save() are invoked whenever the
     session file is read from, or written to the disk file referenced by 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.

     Password authentication is handled by the auth() operation, which should
     return 0 if user and pass are correct, or -1 otherwise.

     The 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 authRegConfirm() operation), to
     the user.

     The authRegConfirm() operation is expected to validate the token and
     complete the registration request.

     The following methods implement password recovery, to assist users in
     recovering lost passwords.  authAssist() is expected to display a
     password recovery form (which submits to authRequest()).  The
     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).

     The verification e-mail should be a link to the 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 authCommit() operation.

     The 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.

     sessClose() is invoked after a session has been terminated.  If a session
     has been terminated due to an inactivity time-out, sessExpired() is also
     invoked.

     The 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.

     The loginPage() method is expected to display the standard "Log in" form.
     When a user gracefully logs out using "Log out", the logout() method is
     called and is expected to display a confirmation message.

     addSelectFDs() and procSelectFDs() are hooks into the standard event loop
     of percgi (which is select(2) based).  addSelectFDs() can add additional
     file descriptors to rd or wr using FD_SET(2) (it should not modify the
     existing set).

     The procSelectFDs() callback is invoked following a return from
     select(2), and may test the returned sets using FD_ISSET(2).

     CGI_SessionDestroy() releases all resources allocated by a session.

     The CGI_CloseSession() routine closes the given session.

     The serialization routines CGI_SessionLoad() and CGI_SessionSave()
     respectively read and write session data (including all session
     variables) from/to file.

     The CGI_SetSV() routine sets the named session variable to the value
     (specified as a printf(3) format string).  The CGI_SetSV_S() variants
     accepts a C string argument.

     The CGI_SetSV_ALL() routine sets the named session variable similarly to
     CGI_SetSV(), except the change applies to all sessions currently opened
     by user.


HISTORY

     The percgi interface was first developed in 2003 (at csoft.net), under
     the name of csoft-cgi.

OpenBSD 5.9                     October 9, 2004                    OpenBSD 5.9

[Unix Hosting | Open-Source | Contact Us]
[Engineering & Automation | Software Development | Server Applications]