Table of Contents
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.
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++.
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++.
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.
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.
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.
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.
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.
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.
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";
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";
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.
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.
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.
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)
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;
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.
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 ''