[next] [previous] [contents] [full-page]12.1 - Conditional Syntax
12.2 - Conditional Keywords
12.3 - Examples
Mapping (HTTPD$MAP) and authorization (HTTPD$AUTH) rules may be conditionally applied depending on request, server or other charactersistics. These include
Conditionals may be nested up to a maximum depth of eight, are not case
sensitive and generally match via string comparison,
although some tests are performed as boolean operations, by converting the
conditional parameter to a number before comparison, and IP address parameters
will accept a network mask as well as a string pattern.
String Matching
The basis of much conditional decision making is string pattern matching.
Both wildcard and regular expression based pattern matching is available
(11 - String Matching). Wildcard matching in conditional tests
is greedy. Regular expression matching, in common with usage
throughout WASD, is differentiated from wildcard patterns using a leading
"^" character.
12.1 - Conditional Syntax
Conditional expressions and processing flow structures may be used in the
following formats. Conditional and rule text may be indented for clarifying
structure.
if (condition) then apply rest of line
if (condition)
then apply one
or more rules
up until the corresponding ...
endif
if (condition)
then apply one
or more rules
else
apply one or more other rules
up until the corresponding ...
endif
if (condition)
then apply one
or more rules
elif (condition)
apply one or more other rules
in a sort or case statement
else
a possible default rule or rules
up until the delimiting
endif
Logical operators are also supported, in conjunction with precedence ordering parentheses, allowing moderately complex compound expressions to be applied in conditionals.
There are two more conditional structures that allow previous decisions to
be reused. These are unif and the ifif. The first
unconditionally includes rules regardless of the current state of execution.
The second resumes execution only if the previous if or
elif expression was true. The else statement may also
be used after an unif to continue only if the previous expression
was false. The purpose of these constructs are to allow a single decision
statement to include both conditional and unconditional rules.
if (condition)
then apply one
or more rules
unif
apply this block of rules
unconditionally
ifif
applied only if the original
if expression was evaulated as true
unif
apply another block of rules
unconditionally
else
and this block of rules
only if the original if was false
endif
CAUTION
Conditional syntax is checked at rule load time (either server startup or reload). Basic errors such as unknown keywords and unbalanced parentheses or structure statements will be detected and reported to the corresponding Admin Menu report and to the server process log. Unless these reports are checked after modifying rule sets syntax errors may result in unexpected mappings or access. Although the server cannot determine the correct intent of an otherwise syntactically correct conditional, if it encounters an unexpected but detectable condition during processing it aborts the request, supplying an appropriate error message.
The following keywords provide a match between the corresponding request or other value and a string immediately following the delimiting colon. White space or other reserved characters may not be included unless preceded by a backslash. The actual value being used in the conditional matching may be observed using the mapping item of the WATCH facility (19 - WATCH Facility).
|
The request notepad is a string storage area that can be used to store and retrieve ad hoc information during path mapping and subsequent authorization processing. The notepad contents can be changed using the SET notepad=<string> or appended to using SET notepad=+<string> (13.4.5 - SET Rule). These contents then can be subsequently detected using the notepad: conditional keyword (or the obsolescent 'NO' mapping conditional) and used to control subsequent mapping or authorization processing.
NOTE
Notepad information persists across internal redirection processing (13.4.2 - REDIRECT Rule) and so may be used when the regenerated request is mapped and authorized. To prevent such information from unexpectedly interfering with internally redirected requests a notepad="" can be used to empty the storage area.
At the commencement of each pass a new pseudo-random number is generated (and therefore remains constant during that pass). The rand: conditional is intended to allow some sort of distribution to be built into a set of rules, where each pass (request) generates a different one. The random conditional accepts two parameters, a modulas number, which is used to modulas the base number, and a comparison number, which is compared to the modulas result.
Hence the following conditional rules
if (rand:3:0)
do this
elif (rand:3:1)
do this
else
do this
endif
would pseudo-randomly generate base numbers of 0, 1, 2 and perform the
appropriate conditional block. Over a sufficient number of usages this should
produce a relatively even distribution of numbers. If the modulas is specified
as less than two (i.e. no distribution factor at all) it defaults to 2 (i.e. a
distribution of 50%). Hence the following example should be the equivalent of
a coin toss.
if (rand:)
heads
else
tails
endif
Request: Keyword
Looks through each of the lines of the request header for the specified
request field and/or value. This may be used to detect the presence of
specific or unknown (to the server) request fields. When detecting a specified
just field the name can be provided
if (request:"Keep-Alive:*")
matching any value, or specific values can also be matched for
if (request:"User-Agent:*Opera*")
Note that all request fields known to the server have a specific associated
conditional keyword (i.e. "user-agent:" for the above example). To
determine whether any request fields unknown to the server have been supplied
use the request: keyword as in the following example.
if (request:?)
map * /cgi-bin/unknown_request_notify.com*
endif
Time: Keyword
The time: conditional allows server behaviour to change according to the time of day, week, or even year. It compares the supplied parameter to the current system time in one of three ways.
if (time:0000-0000) it's midnight elif (time:0001-1159) it's AM elif (time:1200-1200) it's noon else it's PM endif
if (time:6 || time:7) it's the weekend else it's the working week endif
if (time:%%%%-05-*) it's the month of May endif
The trnlnm: conditional dynamically translates a logical name
and uses the value. One mandatory and up to two optional parameters may be
supplied.
trnlnm:logical-name[;name-table][:string-to-match]
The logical-name must be supplied; without it false is always
returned. If just the logical-name is supplied the conditional
returns true if the name exists or false if it does not. The default
name-table is LNM$FILE_DEV. When the optional
name-table is supplied the lookup is confined to that table. If
the optional string-to-match is supplied it is matched against the
value of the logical and the result returned.
Host Addresses
Host names or addresses can be an alpha-numeric string (if DNS lookup is
enabled) or dotted-decimal network address, a slash, then a dotted-decimal
mask. For example "131.185.250.0/255.255.255.192". This has a 6 bit
subnet. It operates by bitwise-ANDing the client host address with the mask,
bitwise-ANDing the network address supplied with the mask, then comparing the
two results for equality. Using the above example the host 131.185.250.250
would be accepted, but 131.185.250.50 would be rejected. Equivalent notation
for this rule would be "131.185.250.0/26".
12.3 - Examples
The following provides a collection of examples of conditional mapping and authorization rules illustrating the use of wildcard matching, network mask matching and the various formats in which the rules may be blocked.
if (query-string:*example*) exec /* /cgi-bin/example/*
if (service:the.host.name:80) pass /web/* /dka0/the_host_name_web/* pass /graphics/* /dka100/graphics/* pass * "404 Resource not found." endif
if (service:the.host.name:80) pass /web/* /dka0/the_host_name_web/* elif (service:next.host.name:80) pass /web/* /dka0/next_host_name_web/* elif (service:another.host.name:80) pass /web/* /dka0/another_host_name_web/* endif pass /graphics/* /dka100/graphics/* pass * "404 Resource not found."
if (server-name:the.host.name) if (scheme:"https") pass /secure/* /dka0/the_host_name_web/secure/* else pass * /dka0/the_host_name_web/secure/only-via-SSL.html endif endif
if (server-name:the.host.name) if (!SSL:) pass * /web/secure/only-via-SSL.html endif pass /secure/* /web/secure/* pass /other/* /web/other/* pass /web/* /web/web/* pass * "404 Resource not found." endif
if (path:/sensitive/* && !(remote-addr:131.185.250.0/24 || SSL:)) pass * 404 "Access denied (SSL only)." endif
[[*]] ["Your VMS password"=VMS] if (!request-scheme:https) * r+w,#0 endif
if (trnlnm:HTTPD_EXAMPLE) pass /* /example/* else pass /* /* endif