Skip site navigation (1)Skip section navigation (2)

FreeBSD Manual Pages

  
 
  

home | help
AG_WEB(3)		     Library Functions Manual		       AG_WEB(3)

NAME
     AG_Web -- Agar HTTP/1.1 application server

SYNOPSIS
     #include <agar/core.h>
     #include <agar/net/web.h>

DESCRIPTION
     The  AG_Web  interface  provides  the  components needed to create a multi-
     process, privilege-separated HTTP/1.1 application server in C.   AG_Web  is
     included in the Agar-Core library if compiled with `--enable-web'.

     An  HTTP  application server using AG_Web might be deployed as a set of in-
     stances running behind an external facing HTTP server (such as Apache httpd
     with mod_proxy_balancer).	AG_Web may also be integrated into  an	existing
     application in need of an HTTP interface.

     AG_Web  spawns  (and expires) one worker process per authenticated session.
     Queries can be processed (and responses compressed) in parallel.

     AG_Web handles:
     *	 Authentication and session management
     *	 Content and language negotiation
     *	 Parsing of HTTP requests
     *	 Forwarding of requests to the appropriate worker
     *	 Chunking and zlib(3) compression of worker responses
     *	 Multiplexing Push events into text/event-stream

     The AG_Web API also facilitates web development with a basic  template  en-
     gine  and methods for input parsing and validation of URLs / query strings,
     JSON and FORMDATA.  Forms encoded as multipart/form-data may include binary
     BLOBs.

     The GET argument "op" specifies the method that a client wishes to  invoke.
     Methods  execute  in  worker  processes,  and are organized in modules (see
     WEB_RegisterModule() below).

INITIALIZATION
     void WEB_Init(WEB_Application *appData, int clusterID, int eventSource)

     void WEB_RegisterModule(WEB_Module *mod)

     void WEB_CheckSignals(void)

     void WEB_Exit(int exitCode, const char *fmt, ...)

     void WEB_SetLanguageFn(int (*fn)(const char  *langCode,  void  *arg),  void
     *arg)

     void  WEB_SetMenuFn(void  (*WEB_MenuFn)(WEB_Query *q, WEB_Variable *V, void
     *arg), void *arg)

     void WEB_SetProcTitle(const char *title, ...)

     void WEB_QueryLoop(const char *hostname, const char *port,  const	WEB_Ses-
     sionOps *sessOps)

     The WEB_Init() routine initializes the AG_Web library.  clusterID is a num-
     ber which should identify this instance uniquely in the cluster of servers.
     If  the  eventSource  flag is non-zero, this instance will be able to serve
     requests for text/event-stream, multiplexing Push events to the client  un-
     til  the  connection is closed.  The app structure should be partially ini-
     tialized:

     typedef struct web_application {
	     const char *name;			     /* Description */
	     const char *copyright;		     /* Copyright notice */
	     const char *availLangs[WEB_LANGS_MAX];  /* Available languages */
	     const char *homeOp;		     /* Default operation */
	     Uint flags;			     /* Option flags */
	     void (*destroyFn)(void);
	     void (*logFn)(enum web_loglvl, const char *s);
	     /* ... */
     } WEB_Application;

     name is an arbitrary string identifier for the application.   copyright  is
     an  optional  copyright  notice.	availLangs is a NULL-terminated array of
     ISO-639 language codes which are valid for this application.  homeOp speci-
     fies the default AG_Web operation	to  invoke  after  a  successful  login.
     flags  should be set to zero (none are currently defined).  destroyFn is an
     optional cleanup function to be run when the server terminates.   logFn  is
     an  optional  callback  to receive log messages produced by WEB_Log*() (see
     `LOGGING' section).

     For example:

     WEB_Application myExampleApp = {
	     "ExampleApp",
	     "Copyright (c) my name",
	     { "en", "es", "fr", NULL },  /* English, Spanish, French */
	     "main_welcome",
	     0, 	     /* flags */
	     NULL,	     /* destroy */
	     NULL	     /* log */
     };

     The WEB_RegisterModule() function registers a new module (and  invokes  the
     module's  init()  method).   The  mod argument must point to an initialized
     WEB_Module structure:

     typedef struct web_module {
	     char *name;		     /* Short name */
	     char *icon;		     /* Icon (HTML) */
	     char *lname;		     /* Long name (HTML) */
	     char *desc;		     /* Description (HTML) */
	     int  (*init)(void *sess);	     /* App initialization */
	     void (*destroy)(void);	     /* App cleanup */
	     int  (*sessOpen)(void *sess);   /* Session opened */
	     void (*sessClose)(void *sess);  /* Session closed */
	     int (*indexFn)(WEB_Query *q);   /* Default op */
	     void (*menu)(WEB_Query *q,      /* Menu override */
			  WEB_Variable *V);
	     WEB_MenuSection *menuSections;  /* Menu sections or NULL */
	     WEB_Command *commands;	     /* Command map */
     } WEB_Module;

     The name string is a short identifier and operation prefix for this module.
     It should not exceed WEB_OPNAME_MAX bytes in length.  icon is  an	optional
     icon  for	the module.  lname is the full title of the module to display to
     the user.	desc is a description of the module's  operation.   icon,  lname
     and desc may contain HTML code.

     All function pointers below are optional and may be set to NULL.

     The  init() function is invoked after the module has been registered (typi-
     cally when the application server is first started).  destroy() is  invoked
     to  clean	up the module's resources (typically when the application server
     is shutting down).

     sessOpen() is called when a new user session is created, where  sess  is  a
     pointer  to  newly created WEB_Session.  It is a good place for a module to
     initialize its session variables (see WEB_SetSV()).  On success, this func-
     tion should return 0.  If it returns -1, session creation is  aborted  (and
     the user will be unable to log in).

     The sessClose() routine is called when a user closes a session.

     indexFn()	points	to  the  default method to invoke when the "op" argument
     contains the module name but does not map onto a specific method.

     If set, menu() will be called to render the menu entry for this module, al-
     lowing dynamically generated contents.  This method is  expected  to  write
     HTML code into V.

     The commands table maps method names to a module's functions:

     typedef struct web_command {
	     char *name;			 /* Method name */
	     int (*fn)(void *mod, WEB_Query *q); /* Function */
	     const char *type;			 /* MIME type (or NULL) */
     } WEB_Command;

     name is the full method name (the matching "op" argument).  fn is a pointer
     to the function implementing the method.  If type is not NULL, it indicates
     the Content-Type of the data returned by the method.  For example:

     static WEB_Command mymodCommands[] = {
	     { "mymod_hello",	     mymod_hello,    "text/html",     "Pi" },
	     { "mymod_image",	     mymod_image,    "image/png",     "" },
	     { "mymod_json",	     mymod_json,     "[json]",	      "" },
	     { "mymod_status",	     mymod_status,   "[json-status]", "" },
	     { "mymod_customtype",   mymod_custtype, NULL,	      "" },
	     { NULL,		     NULL,	     NULL,	      "" }
     };

     For  a  method  that does not output anything other than a return value and
     error code, the special type "[json-status]" can be used.	On success,  the
     JSON code {"code":0} will be emitted.  If the function fails and return -1,
     the following will be emitted:

     { "code": -1,
       "error": "<text from AG_GetError()>",
       "backend_version": "<agar version>" }

     The special type "[json]" may be used if the function emits JSON content of
     its own.  Then the following will be emitted:

     { "lang": <language code>,
       <extra JSON emitted by function>,
       "code": <return code from function>,
       "error": "<text from AG_GetError() on failure>",
       "backend_version": "<agar version on failure>" }

     If  the type field of a method is NULL, the function is invoked without any
     additional processing, and will be expected to set at least  "Content-Type"
     using WEB_SetHeader() or WEB_SetHeaderS().

     The flags string defines per-method options.  It may contain characters:

     `P'   Public method.  Make accessible to both authenticated and non-authen-
	   ticated clients (in the latter case, q->sess will be NULL).

     `i'   Index method.  Invoke by default when no specific "op" given.

     WEB_CheckSignals()  handles  a  previous SIGTERM, SIGPIPE and SIGCHLD.  The
     SIGCHLD handler issues a control command to notify server processes that  a
     particular  worker  process  has  terminated.   Internally,  AG_Web invokes
     WEB_CheckSignals() whenever system calls in the main server process are in-
     terrupted.  Ideally, the same should be done at the application level  when
     an interruptible system call fails with EINTR.  This important for code ex-
     ecuting  under  the  main server process (e.g., authentication module meth-
     ods).  This is not needed for code running inside worker  processes  (e.g.,
     module methods).

     The  WEB_Exit()  routine immediately cleans up resources and terminates the
     running process returning the specified  exit  code  and  optional  message
     string.

     WEB_SetLanguageFn() sets a callback routine (and optional user pointer) for
     switching	between  different  locales  based on language preferences.  The
     langCode argument is an ISO-639 language code.

     WEB_SetMenuFn() sets a callback routine (and  optional  user  pointer)  for
     constructing  the menu.  It is expected to return the dynamically-generated
     menu HTML into V.

     WEB_SetProcTitle() set the process title (as shown by ps(1)) of the current
     worker process.  If setproctitle(3) is not available, the function is a no-
     op.

     WEB_QueryLoop() is the standard event loop for the application server.   It
     listens  on one or more sockets under hostname and port as well as the con-
     trol socket.  WEB_QueryLoop() loops reading HTTP queries and forwarding re-
     quests to worker processes, spawning new workers when needed.  sessOps  de-
     fines  the  authentication  module to use (see `AUTHENTICATION' section for
     details).

HTTP RESPONSE HEADERS
     void WEB_SetCode(WEB_Query *q, const char *code)

     void WEB_SetCompression(WEB_Query *q, int enable, int level)

     void WEB_SetHeader(WEB_Query *q, const char *name, const char *value, ...)

     void WEB_SetHeaderS(WEB_Query *q, const char *name, const char *value)

     void WEB_AppendHeader(WEB_Query *q, const char *name,  const  char  *value,
     ...)

     void WEB_AppendHeaderS(WEB_Query *q, const char *name, const char *value)

     WEB_Cookie  *  WEB_SetCookie(WEB_Query  *q,  const  char  *name, const char
     *value, ...)

     WEB_Cookie * WEB_SetCookieS(WEB_Query *q,	const  char  *name,  const  char
     *value)

     WEB_Cookie * WEB_GetCookie(WEB_Query *q, const char *name)

     void WEB_DelCookie(WEB_Query *q, const char *name)

     WEB_SetCode() sets the HTTP response code of the output.  For example, "404
     Not  Found"  or  "500 Internal Server Error".  When a method is successful,
     the default is "200 OK".

     WEB_SetCompression() sets compression parameters  for  the  response.   The
     enable  flag  enables  or	disables compression, and level sets the zlib(3)
     compression level from 1 to 9 (1 = Best speed, 9 = Best compression).

     WEB_SetHeader() sets the value of the HTTP output	header	name  to  a  new
     value.   If  the header already exists, its value is updated.  Otherwise, a
     new header is created.  WEB_AppendHeader() appends the given header  uncon-
     ditionally (without checking for duplicates).

     WEB_SetCookie() sets the HTTP cookie identified by name to the given value.
     If  an  error (such as overflow) occurs, it returns NULL.	If the operation
     is successful, it returns a pointer to the following structure which can be
     used to change cookie attributes:

     typedef struct web_cookie {
	     char name[WEB_COOKIE_NAME_MAX];	  /* Name (RO) */
	     char value[WEB_COOKIE_VALUE_MAX];	  /* Value */
	     char expires[WEB_COOKIE_EXPIRE_MAX]; /* Expiration date */
	     char domain[WEB_COOKIE_DOMAIN_MAX];  /* Domain match */
	     char path[WEB_COOKIE_PATH_MAX];	  /* Path attribute */
	     Uint flags;
     #define WEB_COOKIE_SECURE 0x01		  /* Set Secure attribute */
     } WEB_Cookie;

     The caller can modify any member except name.

     WEB_GetCookie() returns a pointer to the value of cookie name or NULL if no
     such cookie exists.

     WEB_DelCookie() deletes the cookie identified by name.

HTTP ARGUMENT PARSING
     const char * WEB_Get(WEB_Query *q, const char *key, AG_Size maxLength)

     const char * WEB_GetTrim(WEB_Query *q, const char *key, AG_Size maxLength)

     void WEB_Set(WEB_Query *q, const char *key, const char *value, ...)

     void WEB_SetS(WEB_Query *q, const char *key, const char *value)

     const char * WEB_GetSV(WEB_Session *sess, const char *key)

     void WEB_SetSV(WEB_Query *q, const char *key, const char *value, ...)

     void WEB_SetSV_S(WEB_Query *q, const char *key, const char *value)

     void WEB_SetSV_ALL(const WEB_SessionOps *sessOps, const char  *user,  const
     char *key, const char *value)

     void WEB_Unset(WEB_Query *q, const char *key)

     int WEB_GetBool(WEB_Query *q, const char *key)

     int WEB_GetInt(WEB_Query *q, const char *key, int *dest)

     int WEB_GetIntR(WEB_Query *q, const char *key, int *dest, int min, int max)

     int  WEB_GetIntRange(WEB_Query  *q,  const  char *key, int *minValue, const
     char *separator, int *maxValue)

     int WEB_GetUint(WEB_Query *q, const char *key, Uint *dest)

     int WEB_GetUintR(WEB_Query *q, const char *key, Uint *dest, Uint min,  Uint
     max)

     int WEB_GetUint64(WEB_Query *q, const char *key, Uint64 *dest)

     int WEB_GetSint64(WEB_Query *q, const char *key, Sint64 *dest)

     int WEB_GetEnum(WEB_Query *q, const char *key, Uint *dest, Uint last)

     int WEB_GetFloat(WEB_Query *q, const char *key, float *dest)

     int WEB_GetDouble(WEB_Query *q, const char *key, double *dest)

     char * WEB_EscapeURL(WEB_Query *q, const char *url)

     char * WEB_UnescapeURL(WEB_Query *q, const char *url)

     WEB_Get() looks up the HTTP argument named key and returns a pointer to the
     value  as	a NUL-terminated string.  If no such argument exists, it returns
     NULL (with a "Missing argument" error).

     The WEB_GetTrim() variant of  WEB_Get()  implicitely  removes  leading  and
     trailing spaces (characters matching isspace(3)) from the argument value.

     WEB_Set() modifies the in-memory value associated with argument key.  If no
     such  argument  exists then one is created.  WEB_Unset() deletes the speci-
     fied argument from memory.

     Session variables are key-value pairs associated with an authenticated user
     session.  They are saved to disk and preserved across processes handling  a
     same  session.  WEB_GetSV() returns the value of the given session variable
     or NULL if no such variable exists.  WEB_SetSV() sets the session	variable
     key  to  value.   The WEB_SetSV_ALL() variant updates all session variables
     named key to value for every session opened by user.

     WEB_GetBool() returns 1 if argument key exists and its  value  is	not  the
     empty string (""), otherwise it returns 0.

     The  following  WEB_Get*() functions convert arguments to numerical values,
     returning 0 on success.  If no such argument exists, if the  input  is  in-
     valid  or the number is out of range, these functions return -1 with an er-
     ror message.

     WEB_GetInt() converts argument key to a signed integer, returning	the  re-
     sult  in  dest.   The  number must lie within the range INT_MIN to INT_MAX.
     The WEB_GetIntR() variant fails if the number is lower than min or  greater
     than max.

     The WEB_GetIntRange() function parses a range, specified as a string of the
     form  "<min><separator><max>", for example "1-10" (where separator would be
     "-").  The first number is returned into minValue and  second  number  into
     maxValue.	The function returns 0 on success or -1 if the argument is miss-
     ing or does not describe a valid range.

     WEB_GetUint()  converts  argument key to an unsigned integer, returning the
     result in dest.  The number must lie within the range 0 to  UINT_MAX.   The
     WEB_GetUintR()  variant  fails  if  the number is lower than min or greater
     than max.

     WEB_Get[SU]int64() converts argument key to a signed or unsigned 64-bit in-
     teger, returning the result in dest.  The number must lie within the  range
     [SU]INT64_MIN to [SU]INT64_MAX.

     The  WEB_GetEnum()  function  converts  argument key to an unsigned integer
     greater than 0 and less than or equal to last.

     WEB_GetFloat() and WEB_GetDouble() convert the argument to a single or dou-
     ble-precision floating point number and return the value in dest.

     The WEB_EscapeURL() function turns URL-unsafe characters (per RFC1738) from
     url into "%02x" format and returns a newly allocated string  with	the  re-
     sult.  WEB_UnescapeURL() transforms all instances of "%02x" escaped charac-
     ters  in  url back to the original character (except NUL which would be re-
     turned as '_') and returns a newly allocated string with the result.

LOGGING
     void WEB_SetLogFile(const char *path)

     void WEB_Log(enum web_loglvl logLevel, const char *msg, ...)

     void WEB_LogS(enum web_loglvl logLevel, const char *msg)

     void WEB_LogErr(const char *msg, ...)

     void WEB_LogWarn(const char *msg, ...)

     void WEB_LogInfo(const char *msg, ...)

     void WEB_LogNotice(const char *msg, ...)

     void WEB_LogDebug(const char *msg, ...)

     void WEB_LogWorker(const char *msg, ...)

     void WEB_LogEvent(const char *msg, ...)

     The WEB_SetLogFile() function sets an alternate destination  log  file  (by
     default the application name + ".log" in the working directory).

     The  WEB_Log() and WEB_LogS() functions generate a log entry with the given
     logLevel.	That the log file is unbuffered.  Log levels include:

     enum web_loglvl {
	     WEB_LOG_EMERG,   /* General panic condition */
	     WEB_LOG_ALERT,   /* Immediate attention required */
	     WEB_LOG_CRIT,    /* Critical conditions, I/O errors */
	     WEB_LOG_ERR,     /* General errors */
	     WEB_LOG_WARNING, /* Warning messages */
	     WEB_LOG_NOTICE,  /* Condition should be handled specially */
	     WEB_LOG_INFO,    /* Informational messages */
	     WEB_LOG_DEBUG,   /* Debugging information */
	     WEB_LOG_QUERY,   /* HTTP query (e.g., GET, POST) parsing */
	     WEB_LOG_WORKER,  /* Errors specific to worker processes */
	     WEB_LOG_EVENT    /* Errors related to Push events */
     };

     Alternatively, the WEB_Log<Level>() shorthand routines can be used to  gen-
     erate a log message under the implied log level.

HTTP RESPONSE OUTPUT
     void WEB_Write(WEB_Query *q, const char *data, AG_Size len)

     void WEB_PutC(WEB_Query *q, char c)

     void WEB_PutS(WEB_Query *q, const char *s)

     void WEB_Printf(WEB_Query *q, const char *format, ...)

     void WEB_PutJSON(WEB_Query *q, const char *key, const char *data, ...)

     void WEB_PutJSON_S(WEB_Query *q, const char *key, const char *data)

     void WEB_PutJSON_NoHTML_S(WEB_Query *q, const char *key, const char *data)

     void WEB_OutputHTML(WEB_Query *q, const char *template)

     void WEB_PutJSON_HTML(WEB_Query *q, const char *key, const char *document)

     void WEB_OutputError(WEB_Query *q, const char *msg)

     void WEB_SetError(const char *msg, ...)

     void WEB_SetErrorS(const char *msg)

     void WEB_SetSuccess(const char *msg, ...)

     WEB_Variable * WEB_VAR_New(const char *key)

     void WEB_VAR_Grow(WEB_Variable *v, AG_Size newLen)

     WEB_Variable * WEB_VAR_Set(const char *key, const char *value, ...)

     WEB_Variable * WEB_VAR_SetS(const char *key, const char *value)

     WEB_Variable * WEB_VAR_SetS_NODUP(const char *key, char *value)

     WEB_Variable * WEB_VAR_SetGlobal(const char *key, const char *value, ...)

     WEB_Variable * WEB_VAR_SetGlobalS(const char *key, const char *value)

     void WEB_VAR_Cat(WEB_Variable *v, const char *value, ...)

     void WEB_VAR_CatS(WEB_Variable *v, const char *value)

     void WEB_VAR_CatS_NODUP(WEB_Variable *v, char *value)

     void WEB_VAR_CatS_NoHTML(WEB_Variable *v, const char *value)

     void WEB_VAR_CatC(WEB_Variable *v, const char c)

     void WEB_VAR_CatN(WEB_Variable *v, const void *src, AG_Size len)

     void WEB_VAR_CatN_NoNUL(WEB_Variable *v, const void *src, AG_Size len)

     void WEB_VAR_CatJS(WEB_Variable *v, const char *value)

     void WEB_VAR_CatJS_NODUP(WEB_Variable *v, char *value)

     void WEB_VAR_CatJS_NoHTML(WEB_Variable *v, const char *value)

     void WEB_VAR_CatJS_NoHTML_NODUP(WEB_Variable *v, char *value)

     char * WEB_VAR_Get(const char *key)

     void WEB_VAR_Wipe(const char *key)

     void WEB_VAR_Unset(const char *key)

     int WEB_VAR_Defined(const char *key)

     void WEB_VAR_Free(WEB_Variable *v)

     The  following routines produce HTTP response data.  Upon query completion,
     this data will be compressed, chunked and written back to the HTTP client.

     WEB_Write() appends len bytes  from  data	to  the  HTTP  response  buffer.
     WEB_PutC() writes a single character c.  WEB_PutS() writes a NUL-terminated
     string s.	WEB_Printf() produces printf(3) formatted text.

     WEB_PutJSON()  produces  a JSON data pair from key and data.  WEB_PutJSON()
     escapes data for double quotes, backslashes,  "\r",  "\n"	and  "\t".   The
     WEB_PutJSON_NoHTML_S()  variant  additionally escapes "<" to "&lt;" and ">"
     to "&gt;".

     The WEB_OutputHTML()  function  invokes  the  template  engine  to  produce
     text/html output from the contents of a template file with "$variable" ref-
     erences  substituted  with  the  current set of WEB_Variable.  The template
     file should be located  under  WEB_PATH_HTML/<template>.html.<lang>,  where
     lang is the ISO-639 language code for the current session.  If no such tem-
     plate file exists, it fails and returns -1.

     The  WEB_PutJSON_HTML()  function	invokes  the  template engine to produce
     JSON-encapsulated text/html output from template and  the	current  set  of
     WEB_Variable.  If no such template file exists, it fails and returns -1.

     WEB_OutputError()	outputs  a  complete text/html document with a body dis-
     playing error message msg.  WEB_SetError() sets  the  $_error  variable  to
     contain  a dismissible HTML error message.  WEB_SetSuccess() sets the $_er-
     ror variable to contain a dismissible HTML "success" message.

     The WEB_Variable structure represents a variable holding a  C  string.   In
     template  files,  variables are referenced as "$variable".  Variable values
     are typically set by a method handler prior to  invoking  WEB_OutputHTML().
     Variables are linked to the current WEB_Query, except for globals which re-
     main persistent across queries.

     typedef struct web_variable {
	     char     key[WEB_VAR_NAME_MAX]; /* Name ("\0" = anonymous) */
	     char    *value;		     /* Value (C string) */
	     AG_Size  len;		     /* Content length (characters) */
	     AG_Size  bufSize;		     /* Buffer size */
	     int      global;		     /* Persistent across queries */
	     AG_TAILQ_ENTRY(web_variable) vars;
     } WEB_Variable;

     WEB_VAR_New() returns a pointer to a newly allocated WEB_Variable of an un-
     defined  value.  If the key argument is NULL, it returns an anonymous vari-
     able which must be freed explicitely by the caller after use.

     WEB_VAR_Grow() pre-allocates up to newLen bytes for the value of v.

     WEB_VAR_Set() sets the value of variable key to value.  If no such variable
     exists then a new one is created.

     The WEB_VAR_SetS_NODUP() variant accepts a pointer  to  user  memory  which
     must remain accessible and valid for as long as the variable is in use.

     The  scope  of  WEB_Variable variables is limited to the current WEB_Query.
     However, global variables which will remain persistent across  queries  can
     be declared using WEB_VAR_SetGlobal().  Since globals are allocated once in
     the  parent  process, globals can be shared between processes without extra
     memory usage.

     The WEB_VAR_Cat() and WEB_VAR_CatS() routines append a string to an  exist-
     ing variable.  The WEB_VAR_CatS_NODUP() variant frees value after appending
     its  contents.  The WEB_VAR_CatS_NoHTML() variant escapes "<" to "&lt;" and
     ">" to "&gt;".

     WEB_VAR_CatC() appends a single character c to the value of variable v.

     WEB_VAR_CatN() grows the value of v by len bytes,	performs  memcpy(3)  and
     NUL-terminates the result (the WEB_VAR_CatN_NoNUL() variant doesn't).

     WEB_VAR_CatJS() appends value to JSON data in v, escaping any backslash and
     double  quote  characters.  The WEB_VAR_CatJS_NoHTML() variant also escapes
     "<"  to  "&lt;"  and  ">"	to  "&gt;".    The   WEB_VAR_CatJS_NODUP()   and
     WEB_VAR_CatJS_NoHTML_NODUP() variants both free s after concatenation.

     WEB_VAR_Get()  looks for a variable key and returns a pointer to its value.
     If no such variable is defined, it returns NULL.

     WEB_VAR_Wipe() trivially overwrites the in-memory value of the variable.

     WEB_VAR_Unset() deletes and frees the variable named key, if it exists.

     WEB_VAR_Defined() returns 1 if the given variable exists, otherwise 0.

     WEB_VAR_Free() frees all resources allocated by an  anonymous  variable  v.
     It  is  used  internally by WEB_VAR_Unset() and called automatically on all
     variables after the WEB_Query has been processed.

     This example sets variables "username" and "password"  and  generates  HTML
     using  the "login_form" template.	Instances of "$username" and "$password"
     in login_form will be substituted for "nobody" and "test1234".

     WEB_VAR_SetS("username", "nobody");
     WEB_VAR_SetS("password", "test1234");
     WEB_OutputHTML("login_form");
     WEB_VAR_Wipe("password");

     Anonymous variables must be freed explicitely by the caller:

     WEB_VAR *v;
     v = WEB_VAR_SetS(NULL, "Hello, ");      /* Anonymous variable */
     WEB_VAR_CatS(v, "world!");
     WEB_VAR_Free(v);

AUTHENTICATION
     The sessOps argument passed to WEB_QueryLoop() sets the effective authenti-
     cation module.  The argument must point to  an  initialized  WEB_SessionOps
     structure:

     typedef struct web_session_ops {
	     const char *name;		   /* Session class name */
	     AG_Size size;		   /* Structure size */
	     Uint flags;
     #define WEB_SESSION_PREFORK_AUTH 0x01 /* Call auth() before fork() */
	     time_t sessTimeout;	   /* Session inactivity (s) */
	     time_t workerTimeout;	   /* Worker inactivity (s) */

	     void (*init)(void *sess);
	     void (*destroy)(void *sess);
	     int  (*load)(void *sess, AG_DataSource *);
	     void (*save)(void *sess, AG_DataSource *);
	     int  (*auth)(void *sess, const char *user, const char *pass);
	     WEB_CommandPreAuth preAuthCmds[10];
	     int  (*sessOpen)(void *sess, const char *user);
	     void (*sessRestored)(void *sess, const char *user);
	     void (*sessClose)(void *sess);
	     void (*sessExpired)(void *sess);
	     void (*beginFrontQuery)(WEB_Query *q, const char *op);
	     void (*loginPage)(WEB_Query *q);
	     void (*logout)(WEB_Query *q);
	     void (*addSelectFDs)(void *sess, fd_set *rd, fd_set *wr, int *max);
	     void (*procSelectFDs)(void *sess, fd_set *rd, fd_set *wr);
     } WEB_SessionOps;

     The  name field is a string identifier for the authentication module.  size
     is the size in bytes of the structure describing a session instance  (which
     may  be  a  WEB_Session  structure or a user-defined structure derived from
     it).  Currently the only flags option is WEB_SESSION_PREFORK_AUTH.  If this
     is set, the auth() method will run in the	parent	process.   Otherwise,  a
     worker process will be spawned first with fork(2), and the auth() code will
     execute in the worker process.  Pre-fork auth is best for fast, local file-
     based  authentication  methods, and auth() running in the worker process is
     best for network-based auth methods.

     sessTimeout sets the session inactivity timeout in seconds.   workerTimeout
     sess the worker process inactivity timeout in seconds.

     init()  initializes  a  the session instance structure.  destroy() releases
     resources allocated by a session instance.  load() and save() serialize the
     session instance structure to machine-independent format.

     The auth() operation verifies the given username and password.  On  failure
     it  should  return  -1 and set an error message with AG_SetError(3).  It is
     expected to return 0 on success.  If the WEB_SESSION_PREFORK_AUTH option is
     set, the operation will run in the parent server process  (best  for  fast,
     local auth methods).  Otherwise, it will run in a worker process which will
     terminate should authentication fail (best for network-bound auth methods).

     The  following preAuthCmds[] array maps the URL-provided "op" onto a method
     which will execute in the parent server process (as opposed to running  in-
     side  a  worker  process).   This is useful for pre-auth operations such as
     generating CAPTCHAs, processing POSTDATA from a user-submitted registration
     form, e-mail or mobile verification routines, and handling of password  re-
     covery requests.

     The sessOpen() method is invoked after successful authentication (the s ar-
     gument  will  point  to  the  newly  allocated session instance structure).
     sessRestored() is invoked whenever  a  previously	expired  worker  process
     restarts,	after  the  saved  session state has been successfully recovered
     from disk.  sessClose() is called when a session terminates and is about to
     be deleted from disk.  sessExpired() is called whenever a	session  expires
     due to its inactivity timeout.

     The  beginFrontQuery()  routine  is  invoked  as  a  prologue to any of the
     preAuthCmds[] methods.  It is useful for initializing  common  WEB_Variable
     elements such as $_user and $_theme (see `HTTP RESPONSE OUTPUT' section).

     loginPage()  returns text/html content to show unauthenticated users (typi-
     cally a login form).  The logout() operation is invoked when  a  user  logs
     out.  It is expected to clear the session ID from the "sess" cookie.

     Authentication  modules  which  use  a  polling mechanism such as select(2)
     should implement addSelectFDs().  This method registers extra file descrip-
     tors to be watched for read/write conditions.  procSelectFDs()  is  invoked
     to process a read or write condition on a watched file descriptor.

     The  code	below  illustrates a basic authentication module.  It declares a
     session structure derived from WEB_Session.  It also provides a backend for
     a registration form (regChallenge, regFinish and regConfirm).

     /* Per session data */
     typedef struct mySiteSession {
	     struct web_session _inherit;  /* WEB_Session->MySiteSession */
	     char username[32]; 	   /* Authenticated username */
	     time_t lastLogin;		   /* Last login */
	     /* ... */
     } MySiteSession;

     static void
     Init(void *pSess)
     {
	     MySiteSession *S = pSess;
	     S->username[0] = '\0';
	     S->lastLogin = 0;
     }
     static void
     Load(void *pSess, AG_DataSource *ds)
     {
	     MySiteSession *S = pSess;
	     S->lastLogin = (time_t)AG_ReadUint64(ds);
     }
     static void
     Save(void *pSess, AG_DataSource *ds)
     {
	     MySiteSession *S = pSess;
	     AG_WriteUint64(ds, S->lastLogin);
     }
     static int
     Auth(void *pSess, const char *user, const char *password)
     {
	     return AuthSuccessful(user, password) ? 0 : -1;
     }
     static void
     AuthRegChallenge(WEB_Query *q)
     {
	     GenerateCaptchaGif();
	     WEB_Write(q, captchaGif, captchaGifSize);
     }
     static void
     AuthRegFinish(WEB_Query *q)
     {
	     /* Process POSTDATA from registration form and create account */
     }
     static void
     AuthRegConfirm(WEB_Query *q)
     {
	     /* Complete e-mail or mobile verification */
     }
     static int
     SessOpen(void *pSess, const char *username)
     {
	     MySiteSession *S = pSess;
	     time_t t;

	     Strlcpy(S->username, username, sizeof(S->username));
	     time(&t);
	     S->lastLogin = t;
	     WEB_LogInfo("User %s logged in", username);
	     return (0);
     }
     static void
     SessRestored(void *pSess, const char *username)
     {
	     MySiteSession *S = pSess;
	     WEB_Session *WS = pSess;

	     Strlcpy(S->username, username, sizeof(S->username));
	     WEB_LogInfo("User %s recovered session %s", username, WS->id);
     }
     static void
     SessClose(void *pSess)
     {
	     MySiteSession *S = pSess;
	     WEB_LogInfo("User %s logged out", S->username);
     }
     static void
     BeginPreAuthCmd(WEB_Query *q, const char *op)
     {
	     /* Set common variables for all preAuthCmds[] methods */
	     WEB_VAR_SetS("_admin", "webmaster@example.com");
	     WEB_VAR_SetS("_user", "");
	     WEB_VAR_SetS("_theme", "Default");
	     WEB_VAR_SetS("_modules",
		 "<li><a href='/'>Sign in</a></li>"
		 "<li><a href='/register.html'>Create account</a></li>");
     }
     static void
     LoginPage(WEB_Query *q)
     {
	     const char *user = WEB_Get(q, "username", 32);
	     const char *pass = WEB_Get(q, "password", 32);
	     const char *op = WEB_Get(q, "op", WEB_OPNAME_MAX);

	     WEB_VAR_SetS("login_username", (user) ? user : "");
	     WEB_VAR_SetS("op", (op) ? op : "main_index");

	     WEB_SetCode(q, "200 OK");
	     WEB_SetHeaderS(q, "Vary", "accept-language,Accept-Encoding,"
				       "User-Agent");
	     WEB_SetHeaderS(q, "Last-Modified", q->date);
	     WEB_SetHeaderS(q, "Content-Type", "text/html; charset=utf8");
	     WEB_SetHeaderS(q, "Content-Language", q->lang);
	     WEB_SetHeaderS(q, "Cache-Control", "no-cache, no-store, "
						"must-revalidate");
	     WEB_SetHeaderS(q, "Expires", "0");
	     WEB_OutputHTML(q, "loginPage");
     }
     static void
     Logout(WEB_Query *q)
     {
	     WEB_Cookie *ck;

	     /* Clear the session ID cookie */
	     ck = WEB_SetCookieS(q, "sess", "");
	     ck->path[0] = '/';
	     ck->path[1] = '\0';

	     WEB_OutputHTML(q, "logoutPage");
     }

     WEB_SessionOps mySiteSessionOps = {
	     "My Site's Auth Module",
	     sizeof(MySiteSession),
	     WEB_SESSION_PREFORK_AUTH, /* Invoke auth() before fork */
	     7*24*60*60,	       /* Session inactivity timeout (s) */
	     1*60,		       /* Worker inactivity timeout (s) */
	     Init,
	     NULL,		       /* destroy */
	     Load,
	     Save,
	     Auth,
	     {
		     { "regChallenge", AuthRegChallenge, "image/gif" },
		     { "regFinish",    AuthRegFinish,	 "text/html" },
		     { "regConfirm",   AuthRegConfirm,	 "text/html" },
		     /*
		      * Declare more methods to handle password recovery
		      * and other administrative functions.
		      */
		     { NULL,	       NULL,		 NULL	     }
	     },
	     SessOpen,
	     SessRestored,
	     SessClose,
	     NULL,	       /* sessExpired */
	     BeginPreAuthCmd,
	     LoginPage,
	     Logout,
	     NULL,	       /* addSelectFDs */
	     NULL	       /* procSelectFDs */
     };

PUSH EVENTS
     int WEB_PostEvent(const char *match, WEB_EventFilterFn filterFn, const void
     *filterFnArg, const char *type, const char *data, ...)

     int WEB_PostEventS(const char  *match,  WEB_EventFilterFn	filterFn,  const
     void *filterFnArg, const char *type, const char *data)

     WEB_PostEvent()  generates  a Server-Sent (Push) Event.  The match argument
     indicates which of the running event listeners should receive the event:

     *		 All active event sources.
     username	 All sessions by the given user.
     L=lang	 All sessions in specified language.
     S=id	 The session with the given session ID.
     NULL	 Based on return value of filterFn.

     A custom event filter can be used by  passing  NULL  to  match  and  having
     filterFn point to a compare function of the form:

     typedef int (*WEB_EventFilterFn)(char *sessID, char *user,
				      char *langCode, const void *arg);

     The  compare function will be invoked for each running session.  If its re-
     turns 0, the event will be forwarded  to  the  associated	event  listener.
     filterFnArg is an optional user pointer (passed to arg of the compare func-
     tion).  type and data specify the contents of the Push event.  AG_Web auto-
     matically	adds  and  increments  the "id" field.	It also generates "ping"
     events at regular intervals.

SEE ALSO
     AG_Intro(3)

HISTORY
     The AG_Web interface is based on libpercgi, which	was  developed	over  at
     Csoft.net	 Hosting   (https://csoft.net/)  in  2003  and	originally  used
     CGI/FastCGI.  It was rewritten to become a standalone framework and finally
     integrated in Agar 1.5.1 as a component of ag_core.  It was moved to a sep-
     arate library ag_net in Agar 1.6.0.

Agar 1.7			December 21, 2022		       AG_WEB(3)

Want to link to this manual page? Use this URL:
<https://man.freebsd.org/cgi/man.cgi?query=AG_Web&sektion=3&manpath=FreeBSD+Ports+15.1.quarterly>

home | help