WebHooks
 

Table of Contents

Introduction
Associating a WebHook with a Resource
Global WebHook Reference Encryption Implement a new encryption algorithm.
Encoding Implement a new encoding algorithm for packing data.
TraceLog Store trace information where and how you want to.

Server WebHook Reference ServerInitialisation Perform initialisation tasks when the server starts up.
ServerTermination Perform termination tasks when the server shuts down.
ResourceNameTranslation Translates a virtual URL into a physical filename.
ErrorLog Store error log information where and how you want to.
AuditLog Store audit trail information where and how you want to.

Resource WebHook Reference UserAuthentication Authenticates the user.
AccessControl Determines whether the client has access permission.
ResourceType Determines the MIME type and MIME encoding of the resource.
CommandProcessing Executes the extended equivalent of a CGI script.
ServerInclusions Processes unrecognised Web Macros and server-side includes.

Mail WebHook Reference Deliver Manipulates a mail file received by SMTP.
Receive Locally delivers a mail message.
Resolve Determines which host to connect to to deliver mail.
Rewrite Accepts or Rewrites a recipient mail address.

Introduction

WebHooks provide a method of altering and extending the main PowerWeb server engine. You can override its behaviour on a global basis, or on a per-resource basis. WebHooks operate not just for HTTP, but FTP, SMTP and POP3 also (all protocols supported by PowerWeb).

Typical WebHooks would include customised user authentication and access control, file presentation filters and database applications.

With WebHooks, you can create your own custom server applications that build upon the HTTP, FTP, SMTP or POP3 protocols, using the powerful, reliable, multi-threaded PowerWeb engine as the basis for your server.

WebHooks can be written in any language supported by PowerWeb, such as WebMacros, compiled languages, Perl or Rexx.


Associating a WebHook with a Resource

If you want to write an WebHook for purposes other than CommandProcessing, or if you want to associate that Hook with specified Resources, then you will need to configure the PowerWeb Server++ to tell it under what circumstances to call your new hook.
Global WebHooks
Define these by selecting "Global Settings" from the Admin Root page and then selecting "Hook".

Server WebHooks
Define these by selecting "Service Settings" from the Admin Root page, and then selecting "API Hooks" for the relevant Service.

Resource WebHooks
Define these by selecting "Resource Editor" from the Admin Root page, then selecting either the relevant template or the resource, and finally selecting "API Hooks" from the configuration wizard.

In each case, you will be able to specify the implementation language and the location of your module, as well as the name of the function to call. The default is to cache calls to WebHooks, so you may wish to switch caching off during debugging, so that you don't have to restart PowerWeb Server++ to test each new version of your module.

Global WebHook Reference

Global WebHooks apply across all services and resources.
Encryption
PowerWeb Server++ is not limited to its built-in encryption algorithms. With the Encryption hook, you can define new methods, making PowerWeb an excellent platform for testing and evaluating new security models.

Arguments In: To Be Documented with PowerWeb Secure Server++.

Arguments Out: To Be Documented with PowerWeb Secure Server++.


Encoding
Data transmission can be encoded as well as encrypted. Encoding is defined as a mechanism for compressing or translating data, such as used by popular ZIP programs. The ability to define a hook to handle custom encoding methods means you can write specialised client-server software without losing the advantages of the HTTP framework and server.

Arguments In: To Be Documented with PowerWeb Secure Server++.

Arguments Out: To Be Documented with PowerWeb Secure Server++.


TraceLog
Informational and debugging messages are sent to the Trace Log. This hook allows such messages to be redirected, ignored, or formatted differently.

Arguments In:

Argument:/Message
The text that is to be output to the trace log.
Arguments Out: None.

Server WebHook Reference

Server WebHooks apply to a specific service, such as HTTP or NNTP. Multiple services can share the same WebHook by pointing to the same library module.
ServerInitialisation
This hook is called when the service is started and allows for the extension library to initialise itself. A typical initialisation might be the establishment of a link to a database server, to avoid the overhead of logging in and out for every service request.

Arguments In: None.

Arguments Out: None.


ServerTermination
This hook is called when the service shuts down. It is not guaranteed to be called if the PowerWeb Server++ is aborted abnormally. The main purpose of this hook is to allow cleanup and relinquishing of resources obtained during the "ServerInitialisation" hook.

Arguments In: None.

Arguments Out: None.


ResourceNameTranslation
Resource Name Translation converts a logical (or virtual) name into a physical resource name. PowerWeb Server++ has a built-in function which does this according to the Aliases defined in its server configuration. With this hook, you can override or modify this behaviour. If you need to access the Alias information, it is stored in the variable directory "Config:/Security/Alias".

Arguments In:

Argument:/VirtualName
The name of the resource, as specified by the remote client.
Arguments Out:
Argument:/PhysicalName
The translated physical name of the resource, typically a filename accessible via the server's file system.

Argument:/Type
The object type of the resource. Refer to the list of object types.


ErrorLog
Information sent to the "Server:/ErrorOutput" variable is written to disk by the default version of this hook. By defining your own hook, you can output different information (such as status from your own library module) or redirect the log to a different location or storage mechanism (such as a database).

Arguments In:

Argument:/Message
The text that is to be output to the Error Log.
Arguments Out: None.
AuditLog
Information sent to the "Server:/Audit/AuditOutput" variable is written to disk by the default version of this hook. By defining your own hook, you can output different information (such as status from your own library module) or redirect the log to a different location or storage mechanism (such as a database).

Arguments In:

Server:/Audit/AuditFile
The destination of the audit log information. The WebHook writer may choose to override this parameter.
Arguments Out: None.

Resource WebHook Reference

Resource WebHooks apply to a specific resource or template and are invoked when processing needs to occur for that resource. A resource is typically a document or data file, but can also be an item such as built-in command or API extension based on a URL.
UserAuthentication
Authentication and Access Control are two separate phases in PowerWeb Server++. Authentication refers to the checking of the validity of the user's identity, whereas Access Control defines whether the specified user is allowed access to a given resource from a given machine.

PowerWeb splits apart the authorization string provided by the client browser and stores the user name and password values in status variables.

A common use for this hook is to use an external database for verifying user names and passwords. The AccessControl hook can be overridden to allow specifying a user realm to use for authentication. The user realm name could be used to specify an SQL table name for lookup.

Arguments In:

Request:/Header/In/Authorization
The authorization string provided by the browser (if any). This is normally in an encoded format.

Request:/AuthenticateType
The type of authentication that was requested. For HTTP, this is typically the text "Basic".

Request:/AuthenticateUser
The user name to authenticate, as extracted from the "Authorization" string.

Request:/AuthenticatePassword
The password that was supplied, as extracted from the "Authorization" string.

Arguments Out:
Request:/StatusCode
The protocol-specific status code to return to the client if access is denied. This variable is automatically set to (authentication required - 401 for HTTP) if you return result code 3 from your WebHook.
Rexx Example:
/* User Authentication Example - Requires version 2.06 or later.
   This hook is normally used in conjunction with an AccessControl hook
   (see the example in that section).
*/

parse arg parcel

user = ServerReadText(parcel, "Request:/AuthenticateUser")
pwd  = ServerReadText(parcel, "Request:/AuthenticatePassword")

/* Substitute your own user name lookup here:

   So instead of:

      if user = "joe" & pwd = "secret" then

   use your own code.
*/

if user = "joe" & pwd = "secret" then
   return "0"

/* Authentication failed: either the user name or the password is invalid:
   Return code "3" tells PowerWeb that authentication failed.
*/

return "3";

AccessControl
Access Control defines whether the specified user is allowed access to a given resource from a given machine. By defining your own hook, you can implement other access control policies such as allowing access only during specified time periods during the day.

Arguments In:

Request:/Resource
The physical resource being accessed.

Request:/Protocol
The name of the protocol being used to access this resource.

Request:/Method
The protocol-specific method, such as GET or POST.

Request:/SubMethod
The protocol and method-specific sub-method, such as INCLUDE or EXEC.

Request:/AuthenticateUser
The authenticated user name.

Connect:/RemoteAddress
The remote client's IP address.

Connect:/RemoteHost
The remote client's machine host name, as determined by reverse domain name server lookup.

Arguments Out:
Request:/StatusCode
The protocol-specific status code to return to the client if access is denied.
Rexx Example:
/* Access Control Example - Requires version 2.06 or later.
   This hook can be used in conjunction with a UserAuthentication hook
   (see the example in that section).
*/

parse arg parcel

user = ServerReadText(parcel, "Request:/AuthenticateUser")
page = ServerReadText(parcel, "Request:/Resource")

/* Substitute your own resource lookup here:

   So instead of:

      if user = "joe" then

   use something like:

      call ServerWriteText parcel, "Config:/Semaphore/Global", "5000"
      rc = address sql 'if exists(select * from db..resources where name='user' and resource='page') return 1 else return 0'
      call ServerWriteText parcel, "Config:/Semaphore/Global", "-1"
      if rc = 1 then
*/

if user = "joe" /* & length(page) < 24 */ then
   return "0"

/* Access control failed: tell user he/she is forbidden.

   Code 403 means access is denied to that user. This information will
	be displayed by the client's browser.

   Return code "3" tells PowerWeb that access control denied access.
*/

call ServerWriteText parcel, "Request:/StatusCode", "403"

return "3";

ResourceType
The ResourceType hook tells PowerWeb Server++ the MIME type and encoding of the resource. The default handler bases its decisions on the filename extension of the resource.

Arguments In:

Argument:/Resource
The physical name of the resource to be accessed after resource name translation.
Arguments Out:
Argument:/ContentType
The MIME type of the resource.

Argument:/ContentEncoding
The MIME encoding of the resource.


CommandProcessing
The CommandProcessing hook is the closest equivalent to CGI. It provides a superset of CGI functionality because all server variables can be both queried and set (subject to access control permissions).

Custom applications can use this hook to perform tasks other than serving of documents or data files. Database searches, gateways to other systems and services, administration tasks, etc can all be performed by this hook.

The Guided Tour provides an example of using a CommandProcessing hook which filters ".CSV" files so that they are presented as HTML tables. This processing is invisible to the user, making it an ideal mechanism for implementing filters.

Arguments In: None.

Arguments Out: None.


ServerInclusions
The ServerInclusions hook allows the developer to define customised WebMacros, extending the existing set provided with PowerWeb Server++. Any unrecognised macro is passed to this hook for execution.

Arguments In:

Argument:/WebMacro
The name of the WebMacro to be interpreted.

Argument:/Attributes
The full text of the WebMacro to be interpreted, excluding the name. Attributes are typically space-delimited and are composed of "name=value" pairs where values can be contained in quotes.

Arguments Out:
Request:/Result
The processed output of the PowerWeb Macro should be appended to this variable. It will be automatically sent to the client's browser.

Mail WebHook Reference

Mail WebHooks apply to the SMTP service and allow for further customisation of the mail acceptance and distribution process.
Deliver
This hook is called whenever a new mail message has been delivered. It is an opportunity to manipulate the contents of the mail message (including any headers) prior to it being added to the queue for delivery.

Arguments In:

Request:/Resource
The name of the file containing the text of the mail message.
Arguments Out: (none)
Receive
This hook is called whenever a mail item is about to be delivered locally. If you return HOOK_NO_ACTION, normal mail delivery is attempted, whereas if you return HOOK_ERROR, mail delivery is postponed until the next queue processing scan. Returning HOOK_OK signals you have handled the mail delivery and PowerWeb need take no further action itself.

This hook is typically used to implement mailing list servers, such as a majordomo.

Arguments In:

Request:/Resource
The name of the file containing the text of the mail message.

Request:/AuthenticateUser
The name of the local user to whom mail is being delivered. This is always the name of a user, never a group, because groups have already been expanded by this stage.

Arguments Out: (none)

Rexx Example:

/* Test if a user id is one of the special mail list ids.
	If so, invoke the os2mail product, else perform normal delivery.
*/

parse arg parcel

user = ServerReadText(parcel, "Request:/AuthenticateUser");
msg  = ServerReadText(parcel, "Request:/Resource");

if (user = "majordomo") | isListID(user 'powerweb') then do
	call os2mail user msg
	/* mail delivered */
	return "0";
end
else do
	/* no action taken */
	return "1";
end

isListID: procedure

parse upper arg username listname

if username = listname					then return 1;
if username = listname'-REQUEST'		then return 1;
if username = listname'-DIGEST'		then return 1;
if username = listname'-OWNER'		then return 1;
if username = listname'-ERRORS'		then return 1;

return 0;

Resolve
This hook is called whenever a mail item is about to be delivered to an external host. It is an opportunity to revise the remote host name so that facilities such as dynamically changing gateways can be implemented.

Arguments In:

Argument:/Host
The name of the host machine to which delivery should be attempted.
Arguments Out:
Argument:/Host
The (potentially) revised name of the host to connect to to deliver the mail.

Rewrite
Define this API hook to modify the name of a recipient of a mail message. It is called for each recipient whenever a new incoming mail message is received. User name mapping can be performed at this stage to redirect mail elsewhere or to reject certain mail destinations or users.

Arguments In:

Argument:/Recipient
The user name and host of the recipient. Note that SMTP allows for surrounding angle brackets (such as "<user@host.com>"), as well as routing specifications (such as "@route1,@route2:user@host.com") so be sure your API hook can recognise all these valid formats.
Arguments Out:
Argument:/Recipient
The (potentially) revised name of the recipient.

Request:/StatusCode
The SMTP status code to return to the client if access is denied. Don't change this value unless you are intimately familiar with the SMTP protocol.

Request:/StatusText
The SMTP status text to return to the client if access is denied. Don't change this value unless you are intimately familiar with the SMTP protocol.

Rexx Example:
/* Filter out all mail being forwarded externally from an
   unwanted incoming domain.
*/

parse arg parcel

remote = ServerReadText(parcel, "Connection:/RemoteHost");
user   = ServerReadText(parcel, "Argument:/Recipient");
email  = getAddress(user);

if pos('compusource.co.za', remote) = 0 then
   return "3";  /* user rejected - bad remote host delivering mail */

if pos('@mailbomb.', email) <> 0 then
   return "3";  /* user rejected - unwanted destination host */

/* user accepted */
return "0";


getAddress: procedure

parse arg FullEMail

if pos('<', FullEMail) = 0 then do
   FullEMail = translate(FullEMail, '<', '(')
   FullEMail = translate(FullEMail, '>', ')')
end

parse var FullEMail Prefix '<' MainName '>' Suffix

if pos('@', MainName) <> 0 then
   return strip(MainName)

if pos('@', Prefix) <> 0 then
   return strip(Prefix)

if pos('@', Suffix) <> 0 then
   return strip(Suffix)

return ''