SRE2003 manual

## The SRE2003 Procedure Library

### Description of The SRE2003 functions

The following lists the functions contain in the SRE2003 procedure library. Note that filters (such as SRELite2 or SREhttp/2) may have their own set of functions -- in many cases these provide additional capabilities that addon/script creators may find useful.

Some of the more important functions are: | SRE_AUDIT, SRE_AUTH_RESPONSE, SRE_COMMAND, SRE_DATADIR, SRE_ERROR_RESPONSE, SRE_REQFIELD, SRE_SERVER, SRE_SERVERNAME, SRE_WRITE_ERROR, and SRE_WRITE_MESSAGE.

Alphabetical list of procedures
`ADD_TH` | add "st", "nd", "rd", or "th" to a number
`SRE_ADDCOMMA` | Add commas to a number
`SRE_APPEND_FILE` | append a string to the end of a file
`SRE_AUDIT` | write lines to the AUDIT.LOG file
`SRE_AUTH_RESPONSE` | return an authorization required response
`SRE_CACHE` | manipulate "caches"
`SRE_CACHED` | return whether the current request was satisfied from the cache
`SRE_CACHE_DATA` | work with the SRE2003 database daemon
`SRE_CHECK_USERNAME` | check username & password against authorization
`SRE_CHUNK` | chunk encode a string
`SRE_COMPLETED` | return whether current request has been completed
`SRE_CLIENTNAME` | do a DNS lookup of an IP name
`SRE_CLIENTS` | lookup number, or list, of currently active clients
`SRE_COMMAND` | recieve and send information to the client, etc.
`SRE_COUNTVARS` | manipulate counter variables
`SRE_DATADIR` | return the default (or host specific) data directory
`SRE_DATESTAMP` | compute a time & date string
`SRE_ETAG` | automatically generate an Etag
`SRE_EVENTVARS` | manipulate event variables
`SRE_ERROR_RESPONSE` | return a server error response
`SRE_EXTRACT` | returns settings of several SRE2003 variables.
`SRE_EXTRACT_USERNAME` | extract username from authorization header
`SRE_FIX_URL` | construct a fully qualified URL
`SRE_GET_URL` | get contents of URL
`SRE_GET_URL_ADV` | get contents of URL -- advanced version
`SRE_GMT` | compute a GMT time, incorporating an additional offset
`SRE_HTML_ENCODE` | replace special charaters with HTML entity references
`SRE_HTML_REPLACE` | replace comments in an HTML file
`SRE_HOSTINFO` | read & set host information
`SRE_LIST` | manipulate "lists"
`SRE_LIST_STATS` | compute statistics on values stored in a list
`SRE_MD5` | compute and MD5 of a file or string
`SRE_MOVE_RESPONSE` | return a resource moved response
`SRE_PACK64` | unpack a "pack64" encoded string
`SRE_PACK64_MAKE` | create a "pack64" encoded string
`SRE_PACKUR` | unpack a URL-encoded string
`SRE_PACKUR_MAKE` | create a URL-encoded string
`SRE_PAUSE` | check & set PAUSE status of SRE2003
`SRE_PMPRINTF` | write a message to the PMPRINTF window
`SRE_REPLACESTRG` | replaces occurences of a substring
`SRE_READ_FILE` | read the contents of a file
`SRE_REPLACEWILD` | compare strings & replace portions
`SRE_REQFIELD` | returns the value of a request header
`SRE_REQUEST_INFO` | read "id" info for a request.
`SRE_SAY` | write a message to the bottom of the status screen
`SRE_SERVER` | return descriptive name of the server software
`SRE_SERVERNAME` | return the domain name of the server
`SRE_SHUTDOWN` | shutdown SRE2003
`SRE_TEMPFILE` | return a filename for use as a temporary file
`SRE_TRACKIT` | set and get client specific tracking info
`SRE_UNCHUNK` | unchunk a chunk-encoded string
`SRE_VALUE` | read & set SRE2003 variables
`SRE_WRITE_ERROR` | write a message to the error log and to the status screen
`SRE_WRITE_MESSAGE` | write a message to the status screen
`SRE_WILD_MATCH` | multiple wild card string comparisons

> Advanced Users Notes | SREAPI.TXT contains further details on working with SRE2003. SRE_DMN.TXT discusses how you to user SRE's functions that create and manipulate `daemons, flags, and queues`.

### The SRE2003 functions: full descriptions

Technical Note: | Many of these procedures include an `id_info` parameter. This parameter is a special `transaction identifier` that is automatically generated by SRE2003. If you have its current value (it is one of the arguments sent to the filter), providing `ID_INFO` can speed up processing a bit. However, if you do not have it's current value, then you must leave these `ID_INFO` parameters blank.

ADD_TH: Write "audit messages"
  Return a "st", "nd", "rd" or "th" (as appropriate).

  `Syntax:
  asuffix=add_th(numeric_value)`

  Examples:

           say 'This is the 21 '||add_th(21)||' birthday'
           app1=add_th(user_ct) ; say 'You are the 'user_ct||app1' visitor'

SRE_ADDCOMMA: Add commas to a number
  Insert commas into a long number:
  Syntax:
  newval=sre_addcomma(oldval)

  Examples:

        newval=add_comma(1512563)
        which yields:newval = 1,512,563

SRE_APPEND_FILE: Append a string to the end of a file
  Append a string to the end of a file (or create the file if it does not exist). Can also be used to overwrite an existing file.

  `Syntax:
  astat=sre_append_file(filename,astring,ntries,addcrlf,overwrite)`
  where:

  `filename` | the file to append to
  `astring` | the arbitrarily long string to append
  `ntries` | Optional. How many times to try and open the file (with a 1 second delay between attempts). The default is `1` (just try once)
  `addcrlf` | Optional. If `1`, then astring will always be preceded by a crlf (a `'0d0a'x`): if filename does not end with crlf, a crlf will be added, and then astring if filename DOES end with a crlf, an extra crlf is NOT added Notes: The default is 0 (do not add crlf) crlfs at the beginning of `astring` are never removed. if a '1a'x (Ctrl-Z) currently ends the file, it will be removed. If filename does not exist, a crlf is not added at the beginning A crlf is always added at the end of astring (even if one is already there)
  `overwrite` | Optional. If `1` then instead of appending, overwrite any existing file (that is, delete an older version, and then write `astring` to `filename`).
  `astat will be:` | if succesful: the size of filename after appending if an error occurs: an error code followed by an error message. The error codes are: -1 = could not open file -2 = problem writing to file

SRE_AUDIT: Write "audit messages"
  Write a message to the audit file (or to the screen or pmprintf window)

  `Syntax:
  astat=sre_audit(mess_hdr,message,whereto,brief)`
  where:

  `mess_name` | a short string used to form a message header. The message header helps identify the time and origin of the message.
  `message` | the message
  `whereto` | where to write the message to
  `brief` | Optional. If 1, then only use the mess_name in the message header (suppress the time and process identifers).
  `astat` | SRE_AUDIT always returns a `1`

  `whereto` should be a 3 character long string of 0's and 1's

  - character 1: audit file
  - character 2: pmprintf window
  - character 3: status screen
  For example: 101 means write to audit_file and to screen

  Special values of whereto:

  - `' '` = write to audit_file and to pmprintf (the default)
  - `'0'` = write to audit_file only
  - `'1'` = write to audit_file and to screen

  Notes:

  - To write a simple message (without any header information) to the audit file and to the pmprintf window, you can use the alternate form of:
    `foo=sre_audit(message)`
  - SRE_WRITE_MESSAGE and SRE_PMRINTF also can be used to write message to the status screen, audit file, and pmprintf window

  Examples:

        foo=sre_audit('This is a simple message to the audit file')
        foo=sre_audit('PROC1','Starting loop in proc 1 ',0)
        foo=sre_audit('HELP',' generating new help files ','011',1)

SRE_AUTH_RESPONSE: Return an authorization response to the client
  SRE_AUTH_RESPONSE will send a Basic and/or Digest request for authorization `401` response to the client. Typically, the client's browser will then ask for a username and password, and resend the request.

      Syntax:
          rcode=sre_auth_response(realm_name,servername,dodigest,message,id_info,sht_mess)

  where:

  `realm_name`: | the realm name. This is displayed in the username/password request box displayed by the client's browser.
  `servername`: | optional. Used in the text of the response (not typically displayed) If not included, it will be looked up
  `dodigest`: | Possible values: -1 : do NOT include Digest authentication info 1 : include Digest authentication info, and tell client to recompute his Digest authentication key (tell the client his key is "stale") This is especially useful if the clients prior Authorization header did not work. `Otherwise:` include Digest authentication info (but don't tell client his key is "stale")
  `message`: | Optional. If specified, this should be a full html response (including `< / html > ... </html >`) Otherwise the body of a response will be created. Note that this "body" is only displayed if the client cancels out of filling in the authorization box.
  `id_info`: | Optional the "id_info"
  `sht_mess`: | Optional If specified, and if `message` is NOT specified, then this should be a short description (it will be placed in a `<blockquote>`).

  Rcode is the response from a SRE_COMMAND('VAR ..') call. It contains the "response code".

  Note that if the client is http/1.0, then digest authentication info is not sent (regardless of the value of dodigest).

SRE_CACHE: Write/read entries in a cache
  Caches are used to store semi-permanent variables. Each cache is allocated a fixed number of slots (one slot per variable), As you add variables, eventually all the slots will be taken. At that point, a LRU (least recently used algorithim) is used to remove the oldest variables, thereby freeing up slots for new variables (about 30% of the oldest variables are removed during this "pruning").

  For example, SRE_CACHE is used to implement the `MD5`, `Request`, and `IPNAME` caches of SRE2003. Note that "lists" and "queues" are also implemented in SRE2003 -- caches differ from lists and queues in several ways: you can lookup specific entries, and an LRU algorithim is used to discard old values.

  `Syntax:
  val=sre_cache(cache_name,action,varname,avalue,time_to_live,ownid)
  ` where

  `cache_name` | The name of a cache. Examples of cache_names:`MD5 IPNAME REQUEST` Note: if `cachename` equals `!LIST`, then a space delimited list of currently active caches is returned.
  `action` | What to do. Possible actions include:`CREATE RESET WRITE ADD READ PRUNE REMOVE STATUS LIST`
  `varname` | variable name to store in the cache. Case insensitive, and must NOT contain spaces.
  `avalue` | value of this variable
  `Time-to-live` | In fractions of a day, is the desired lifespan of the cache entry. This can be used to remove cache entries, even if they are not necessarily the "least recently used". It can NOT be used to protect a "least recently used" entry.
  `Ownid` | Optional, it's the daemon_id of the caller (or, you can use the ID_INFO). Or, set to 0 to mean "don't bother responding" (typically used with action of WRITE or ADD). Caution:If calling SRE_CACHE from a non-request thread (say, from an initialization procedure), you must create an `ownid`, or use `0`. This is easily done with the SRE_DMN_OWN procedure. Example |
      /* create an "ownid" */
      ownid=sre_dmn_own(,,'CACHEIT')
      /* code using ownid, such as ...  */
       astat=sre_cache('CHK_404','CREATE',,,,ownid)
      /*    more code    */
      /* and, to recycle resources, remove the ownid */
       foo=sre_dmn_command(ownid,'DISCONNECT')

  The supported "actions" are:

  `CREATE` | create a cache varname should be the length of the cache. If varname is not specified, a default size of 500 is used. Returns: 1 on success
  `RESET` | clear all items in acache. If varname is specified, reset the size of the cache to varname. Returns: 1 on success
  `WRITE` | create, or change value of, varname; using avalue Returns either 'OK 'value or 'ERROR 'error_message
  `WRITE_CT` | Same as WRITE, but also write (to an SRE environment variable) the current number of variables currently defined in the cache (after "writing" this variable). The SRE environment variable name will be cache_name_CT. For example: If you WRITE_CT a variable to the FOOBAR cache, you can read the total number of variables in the FOOBAR cache using `kt=sre_value('FOOBAR_CT',,'SRE')`
  `APPEND and PREPEND` | If `varname` does not exist, these are the same as WRITE. Otherwise, either append the `avalue` to the end of the current value of `varname`, or prepend to the beginning.
  `ADD` | create a numeric variable, or add avalue to existing numeric variable Returns either 'OK 'value or 'ERROR 'error_message Note that if you try to ADD to a non-numeric value, an error occurs.
  `READ` | return the value of avar. If avar is not defined, return avalue (if avalue is not specified, return ' '). Returns the value
  `PRUNE` | remove 30% of the cache, using a LRU algorithim Returns 'Ok 'Num_left_in_cache
  `REMOVE` | remove the entry for varname. REMOVED entries are deleted when a PRUNE is issued (till then, they just occupy space, but are not read) Return 'Ok removed' or 'Error no entry'
  `REMOVE_CT` | Same as REMOVE, but also write (to an SRE environment variable) the current number of variables currently defined in the cache (after "removing" this variable). The SRE environment variable name will be cache_name_CT. For example: If you REMOVE_CT a variable to the FOOBAR cache, you can read the total number of variables in the FOOBAR cache using `kt=sre_value('FOOBAR_CT',,'SRE')`
  `STATUS` | returns 1 line of status info: `'Active_entries='nactive', Max_entries='cache_size', Last_reset='last_reset`
  `LIST xxx` | returns list of items in a cache. Syntax depends on the value of `xxx`:
      If xxx=' '
         #entries_in_cache (crlf)
         varname','last_read_timestamp','expiration_time','#reads','value (crlf)
         ...
      IF xxx='VAL'
         #entries_in_cache (crlf)
         value (crlf)
         ...
      IF xxx='VAR'
         #entries_in_cache (crlf)
         varname (crlf)
         ...

      IF xxx='BOTH'
         #entries_in_cache (crlf)
         varname','value (crlf)
         ...

      IF xxx='THREE'
         #entries_in_cache (crlf)
         varname','#reads','value (crlf)
         ...
  Note: if you specify a `varname`, it will be used as a seperator. For example, using '09'x will use a TAB as a seperator (this is useful if variables stored in a cache might contain multiple lines of text). There is one proviso: you can not use '01'x as a seperator.

  Examples: `
  - goo=sre_cache('REQUEST','WRITE','REQ1','foo/bar/hello',0.1,0)
  - aval=SRE_CACHE('REQUEST','READ','VAR1',,,own_id)
  `

SRE_CACHED: return whether current request was resolved from the request cache
  SRE_CACHED will return a 1 if the current request was resolved using information from the request cache.
  Otherwise, it returns a 0.

      Syntax:
         iscached=SRE_cached()

SRE_CACHE_DATA: work with the SRE2003 data daemon
  The SRE2003 data-cache daemon provides permanent storage of small to moderate sized collections of small data records. It's strengths are relatively quick lookup and recording of data, using a caching mechanism to reduce disk access.

  For a full description, see SRE_DCSH.TXT.

SRE_CHECK_USERNAME: Check if a username and password match
  SRE_CHECK_USERNAME checks to see if a username and password matches the username and "password" contained in an authorization header.

  Syntax:
  `okay=sre_check_username(username,password,auth_header)`
  where:

  `username:` | the username to check
  `password:` | the password of this username
  `auth_header:` | the value of the Authorization: request header. This can be obtained either by using the SRE_REQFIELD function, or by using the AUTH argument sent to the filter. Alternatively, a `SIMPLE` type of auth_header is also recognized: `SIMPLE username password`.
  `okay:` | okay=1 if the username and password match what the client provided, Otherwise, okay=0

  A typical use of this is:
  1. use SRE_EXTRACT_USERNAMEto extract the "username" of a client,
  2. lookup (in an internal database) the password corresponding to this username,
  3. use SRE_CHECK_USERNAME to see if this username/password combination has been supplied by the client (in the `authorization` header).

  This function is particularly useful when the DIGEST method of authorization is used.

  Example:

            aa=SRE_reqfield('Authorization')
            username=sre_extract_username(aa)
            /* insert code lookup  "username's" password in a database */
            okay=sre_check_username(username,password,aa)

  Note that a password must be supplied (if it's not, a password of ' ' is used).

SRE_CHUNK: Chunk encode a string
  Convert a text string to a "chunked" string. Typically, one would call sre_chunk several times (say, as content becomes available, you send it to a client), with the final call being the "final" call.

  `Syntax:
  cstuff=sre_chunk(stuff,final,trailer)`
  where:

  `stuff:` | the string (text or otherwise) to be chunked
  `final:` | if final=1, this is the last chunk (end with a terminator)
  `trailer:` | if final=1, the contents of trailer will be added as "trailers" to the chunked message

  `Cstuff` is the "chunked" version of stuff, perhaps with the trailer added at the end (as a "trailer")

  Example:

          aa=sre_chunk(a_string)

SRE_COMPLETED: return whether current request has been completed
  SRE_COMPLETED will return a 0 if the current request is still open.
  Otherwise, it returns a 1.
  Syntax:

         iscompleted=sre_completed()
         iscompleted=sre_completed(transaction_tid)

  transaction_tid is optional-- if used, it should be the thread id of a transaction (not the transaction's daemon-id).
  . It is used if you want to lookup the completion status of the request running under a given transaction. If not specified, then the "current request" is checked.

SRE_CLIENTNAME [ipaddress]) : Do a DNS lookup of an IP name
  Returns the ip name of the current client, or of the numeric ipaddress (if ipaddress is specified).

      Syntax:
        cname=SRE_clientname()
        cname=SRE_clientname('151.22.51.76')

  SRE2003 uses a "IPname" cache to avoid unnecessary calls to a DNS -- the most recent several hundred IP name lookups (are retained) -- see the description of MAXCLIENTNAMES.

SRE_CLIENTS Number of active transactions
  SRE_CLIENTS returns the current number of active transactions; where there is one active transaction per connected client. SRE_CLIENTS can also be used to list the currently active transactions.

  `Syntax:`

  `cname=SRE_clients()` | Total number of active clients
  `cname=SRE_clients('!CT_T')` | Total number of active clients. This uses an SRE environment variable.
  `cname=SRE_clients('!CT_R')` | Total number of active requests. This uses an SRE environment variable.
  `cname=SRE_clients('!LIST_TRAN')` | Returns a list of currently active transactions
  Notes: The `transaction id` is the thread (under the SRE2003 process) that the `transaction daemon` is running under. Some active transactions may be waiting for a second or latter request (on a `maintained connection`), in which case there will be fewer active requests then active transactions. The !CT options retrieve information from SRE environment variables. These are quick to retrieve, but (on rare occasions) they may not be completely up-to-date. The list of currently active transactions will be a CRLF ('0d0a'x) delimited list; the first line will have the number of active tranactions (possibly 0), and the subsequent lines will contain the transaction ids of these active transactions (one per line).

SRE_COMMAND: Recieve and send information to the client, etc.
  SRE_COMMAND is used to recieve and send information to the client and to set certain server variables.

  SRE_COMMAND follows the syntax used in several of GoServe's "completion codes" -- many of the GoServe "completion codes" are implemented via calls to SRE_COMMAND (upgraders may want to refer to GOSERVE.DOC for alternative descriptions).

  Syntax:
  `STATUS=SRE_COMMAND('ACOMMAND OPTION',amessage,id_info)`
  where:

  - `ACOMMAND` can be one of: ALIVE AUDIT CLOSE CONTROL FILE HEADER IMINFO NODATA QUERY READ REPSONSE SEND SET VAR
  - `OPTION` is an option list that depends on ACOMMAND.
  - `amessage` is an argument that is required for the VAR and other options
  - `id_info` is optional (if known, it can speed things up a bit)

  The following describes the `ACOMMAND` modes of SRE_COMMAND in greater detail.

  > Note that several of these modes (FILE, VAR, CONTROL, NODATA, and STRING) are "completion commands" -- by default, performing the action entails finishing the request (and possibly closing the connection). This default may be modified if you've enabled `SEND` mode.

  ALIVE | Checks to see whether the socket (for this connection) is still alive. `Syntax: sre_command('ALIVE')` Returns: -3 = SockSelect error -2 = Could not determine current connections socket -1 = Socket has been closed 0 = Socket is inactive > 0 = Bytes pending on socket Note that if a client dies, or otherwise uncleanly breaks a connection, then a 0 may be returned. Thus, 0 indicates, but does not guarantee, that the client is waiting. Notes: The STILL_ALIVE function can also be used to check connection status.
  AUDIT | Write information to the audit log file. `Syntax: vv=sre_command('AUDIT message')` Will write the message to the SRE2003 audit log file. Example: foo=sre_command('AUDIT FOOBAR used on '||date('n')) Notes: * The SRE_AUDIT function can also be used to write to the audit log file.
  CLOSE | The `CLOSE` command is used to close down SRE2003/SREhttp/2. You can also instruct SRE2003 to attempt to reboot the machine, or to restart SRE2003. `Syntax: vv=sre_command('CLOSE [REBOOT | RESTART]')` where ... `REBOOT` and `RESTART` are optional -- you can specify one (but not both) of them (or neither of them). `RESTART`: after closing down, SRE2003 will restart `REBOOT`: after closing down, SRE2003 will reboot the computer Note: for more complicated status monitoring and re-start capabilities, see the SREWATCH.CMD program (that comes with SRE2003).
  CONTROL | Compute statistics, and reset counters. `Syntax: vv=sre_command('CONTROL [NOWAIT] [VAR] option')` The possible options are: RESET [BYTES] [REQUESTS] [RESPONSE] [TRANSACTIONS] [LIMITS] [ERRORS] [BROKEN] [ALL] The specified SRE2003 counters and statistics are reset (after auditing, if appropriate). Any or all of the keywords may be given, in any order. RESPONSE refers to the response time record. If ALL is used, all of the items are reset, and the current time is noted as the "time of last reset" -- the last reset time is shown on the display window and in any statistics requests. STATISTICS Current statistics and settings are returned. These include: Transaction, error, limits, byte, and client counts, with response time averages Certain settings and options (not including audit selections) The local time of certain events (if an event has not occurred, it is shown as the SRE2003 start time). Examples: `status=sre_command('CONTROL STATISTICS ') val1=sre_command('CONTROL RESET LIMITS VAR')` The result of a CONTROL command is a single string, which may include multiple lines, separated by Carriage Return-Line Feed (CR-LF, ASCII '0d0a'x) sequences. The result string is either placed in a variable or returned to the client: If 'VAR' was specified, the result string is returned to the caller. If 'VAR' was not specified, a document containing the string is returned to the client (just as though the STRING mode of SRE_COMMAND were used), so in this case, CONTROL is a completion command. A response_code' 'byte_sent (or an 'error error_message') is returned to the filter (or to whatever procedure called SRE_COMMAND). The NOWAIT keyword may be used to force the current connection to be closed after any response is sent, even if a persistent connection had been requested. Upgraders note: The following GoServe CONTROL options are not supported:`MOVEAUDIT RESET PEAK SAY`
  FILE Syntax NAME CHUNK ERASE ETAG ETAG_APPEND ETAG_AUTOn and ETAG_SIMPLE EXPIRES IM MD5 NOWAIT NOCACHE NOIF NORANGE QUICKPOST TYPE TE_GZIP NAME | Send a file to the client. This is similar to the GoServe FILE command, with several new options (such as CHUNK and ETAG) and without the BINARY option. Syntax:
  `vv=sre_command(` | `'FILE [CHUNK] [ERASE] [ETAG etag] [ETAG_AUTOn] [ETAG_SIMPLE] [ETAG_APPEND] [EXPIRES offset] [IM im-type] [MD5] [NOWAIT] [NOCACHE] [NOIF] [NORANGE] [QUICKPOST] [TYPE content-type] [TE_GZIP] NAME filespec')`
  The only required option is `NAME filespec` | `FILESPEC` must be a fully qualified name of an existing file. This file will (possibly after some encodings and instance manipulations) be sent to the client. If the filename includes spaces, filespec should be enclosed within double quote (") characters.
  - The remaining options (none of which are required) may be specified in any order. They have the following effects: `CHUNK` -- send the file using a chunked format, This is ignored if the client does not understand chunking (the client must be http/1.1, or must send a `TE:` request header that includes `chunked`). `ERASE` -- the file is a temporary file, and should be erased after being sent. `ETAG eee` -- eee is the etag associated with this response. If used, an Etag: `eee` response header will be added. For example: `Etag gxyq1` will cause a `Etag: "gxyq1"` response header to be added. `ETAG_APPEND eee2` -- `eee2` is appended to the Etag, where Etag can be specified (with an ETAG) or automatically generated (with an ETAG_AUTOn or ETAG_SIMPLE). Typically, `eee2` should start with a `;`. `ETAG_AUTO,` `ETAG_AUTO1`, `ETAG_AUTO2`, and `ETAG_SIMPLE` -- SRE2003 will generate an etag for this file. `ETAG_AUTO`: use the filename, size, and date; and use values of some headers `ETAG_AUTO1`: use the filename, size, and date; and use the contents of the file; and use values of some headers `ETAG_AUTO2`: use the contents of the file, and use values of some headers `ETAG_SIMPLE` just use the filename, size, and date; On rare occassions, or on sites where simple changes to dynamic resourcess can occur very rapidly (in less then a second), the ETAG generated by ETAG_AUTO may not be unique. In such cases, you can use ETAG_AUTO1 or ETAG_AUTO2, which causes SRE2003 to compute a more complex (and more time consuming) ETAG
    Notes | For all values of variants of ETAG_AUTO, the values of the entity-headers are also used. if any of the `ETAG_AUTO` variants are used, and `ETAG eee` is also used, then the explicit etag (the `eee`) is used. `ETAG_SIMPLE` generates a simple, and perhaps not quite spec, ETAG. It is best used with static resources. In particular, it can be used with resources that may have been placed on your site via a PUT request. If `ETAG_APPEND zzz` is also included, the `zzz` will be appended to the automatically generated etag. See the description of SRE_ETAG for details on how SRE2003 computes etags.
  `EXPIRES offset` -- add an `Expires:` response header. `offset` is when this file expires, as measured from the current time. There are several formats for offset: `xx.yy` xx number_of_days, yy fraction_of_a_day `xxH` xx hours `xxM` xx minutes For example, the following all mean 12 hours from now: `EXPIRES 0.5`, `EXPIRES 12h`, `EXPIRES 720m` `IM im_name` -- Specify what IM (instance manipulation) module to use. The `im_name` option is an identifer defined in the IM_TYPES parameter (specified in SRE2003.CFG). If IM is not specified, the default IM algorithim (say, the built-in Range extraction algorithim) is used. Examples: `IM STRING_RANGE` `IM DELTAS` `IM 0` (IM 0 means suppress IM ) `MD5` Create a Content-MD5 response header. This is created after range extraction, but before transaction-encoding GZIP. `NOCACHE` -- prevents this FILE URI from being added to the request cache. See Appendix 2 (of the main documentation) for more details. `NOIF` -- do not check for `If-` request headers. If NOIF is not specified, then SRE2003 will look for `If-Modified, If-Match, If-Unmodified-Since,` and `If-None-Match` request headers. If any of these request headers are binding, then an appropriate 304 (not modified) response will be returned. If NOIF is specified, then this check will not occur (a 304 response will not be automatically generated). `NOWAIT` -- forces the current connection to be closed after any response is sent, even if a persistent connection had been requested. `NORANGE` -- do not check for `Range` request headers. `NORANGE` is ignored when a non-`RANGE` im_name is specified (either in the IM_DEFAULT configuration parameter, or in an IM option) If NORANGE is not specified, then on `FILE` commands SRE2003 will look for `Range` and If-Range request headers. If a Range: header is found, the SRE2003 will attempt to return the requested byte ranges in 206 (Partial Content) response. If NORANGE is specified, then this automatic generation of a range response will not occur, even though the client may desire such a range. Reminder: range responses are automatically generated only with the `FILE` command (of SRE_COMMAND) -- responses generated using VAR and STRING commands are not checked for Range. Of course, you can always create your own range response using VAR (and adding the appropriate response headers). `QUICKPOST` --immediately return "anticipated status" information prior to responding to the client. This can speed up throughput, since the filter can exit (releasing memory) prior to completion of response. Though potentially wrong (say, if a client kills a connection) this "anticipated" information is often sufficient for logging purposes. `TE_GZIP` If supported by the client (as indicated in a TE request header), on-the-fly GZIP the file before sending it to the client. SRE2003's on-the-fly GZIP is done as a transfer-encoding. In general, only http/1.1 clients will be capable of recieving GZIP as a transfer-encoding. The entity tag is computed before GZIPping. The request-cache will flag selectors when a TE_GZIP was specified. On future requests for this selector, if the client understands GZIP as a transfer-encoding, the cache will not handle the request. The idea is that the filter is given a chance to order a transfer-encoding of this request. `TEXT` -- Treat the response as a text file. Currently, this has one effect: if the file ends with a Ctrl-Z, the Ctrl-Z in stripped. The TEXT option is ignored if the file is larger then 500,000 bytes. In general we do not encourage use of this TEXT option -- it reduces the useability of the request (and content-md5) caches. `TYPE xxx` -- xxx is the "mimetype" of this resource. SRE2003 will include a Content-type response header that uses xxx. For example: `type text/plain` will cause SRE2003 to add a `Content-type: text/plain` response header. Examples: `stat=sre_command('file type text/html etag fae94 name d:\sre\index.htm') stat=sre_command('file erase type image/gif name d:\sre\temp\$7681.80') stat=sre_command('file chunk type application/octet-stream e:\arc\fo.zip')` Notes: The FILE mode of SRE_COMMAND will always return two numbers, seperated by a space -- a status code and the bytes sent. For example: `200 15161` The filespec may not include an 'upwards reference' sequence ("..\") as such a sequence could possibly allow clients access to any file on the server machine. SRE2003 will generate a header automatically if the TYPE option is specified. You can also use the HEADER option to specify a content-type (note that a content-type specified by the TYPE option will override a content-type specified specified by the HEADER command). The Content-Length and Transfer-Encoding headers are always generated by SRE2003. Don't bother trying to specify them with SRE_COMMAND! CHUNK can also be used with `SRE_COMMAND('VAR ...` FILE is a "completion code"
  HEADER | Add or remove a response header. Syntax: `aa=sre_command('HEADER [ADD|APPEND|DROP|PLACE|REPLACE] [CLEAR] [NOAUTO] [NOTIME] [READ] hdr_name : hdr_value')` where:
  `ADD, APPEND, DROP. PLACE, or REPLACE` | ADD (the default):The header specified in `hdr_name` is added. If a header with this name already exists, a new response header is added. Thus, the client will recieve two (or more) response headers with this name, each with (possibly) different values. APPEND: The header specified in `hdr_name` is added. If a header with this name already exists, value is appended to the end of the already existing value (with a comma seperating the existing value from this value). In contrast to ADD, only one response header is sent, with the two (or more) values seperated by commas. DROP Removes a with name specified by hdr_name. Hdr_value is ignored, and the trailing : (after hdr_name) need not be included. REPLACE Similar to ADD, but instead of appending to a pre-existing value, it will replace a pre-existing value. PLACE Similar to ADD, but only if a pre-existing value does not exist (that is, PLACE will not overwrite a pre-existing value ).
  `CLEAR` | Remove all existing response headers. Turn off NOAUTO and NOTIME.
  `NOAUTO` | Optional. If specified, then the automatically generated headers (time, servername, etc.) will NOT be added.
  `NOTIME` | Optional. If specified, then Last-Modified and/or Expires: headers will not be included
  `READ` | Read the current value of hdr_name. When READ is used, all other options (except CLEAR) are ignored. The current value is returned as: `hdr_name: current_value`. if their is no hdr_name response header currently defined, a ' ' is returned. If you do not specify any hdr_name, a space delimited list of currently defined response headers is returned. The various automatically generated response headers can not be READ -- they are generated when the response is sent to the client.
  `hdr_name and hdr_value` | Define the name of the response header, and it's contents. For example: `x-new-header: This is my new header`
  Examples:`foo=sre_command('Header add X1: This is x1 ') foo=sre_command('Header add X2: This is X2 ') ... foo=sre_command('Header drop x2:') foo=sre_command('Header NoAuto Add Simple: this is the only header')` Notes: NoAuto and NoTime can be included with ADD or DROP. But you should only use it once per response. HEADER DROP only examines the portion of aheader that precedes the first ":". You can specify multiple "aheaders" by concatenating several of them, with each aheader seperated by a '0d0a'x. For example: `rh='Header Add H1: my name is Gus ' rh=rh||'0d0a'x||'Header Add S1: Her name is Sally' foo=sre_command(rh)` `sre_command('Header ...')` always returns a '1'.
  IMINFO | Specify some information to be sent to an IM module. See IM_USE.HTM for details on how IM modules can use this information. `Syntax: vv=sre_command('IMINFO [CLEAR| [PLACE] [READ] ',im_message)` where one (or none) of the options may be used: CLEAR = remove prior message(s) and replace with this one. If `im_message`= ' ', then just clear prior messages(s) PLACE = add this message only if no prior message has been specified READ = read current set of messages to be sent to IM. If READ is used, the im_message argument is ignored otherwise (if no options are specified), add this message (on a new line) after existing messages Examples: `foo=sre_command('IMINFO ','Strings=Section+1 - Section+2') bybbye=sre_command('IMINFO CLEAR')`
  NODATA | Send a null response. `Syntax: vv=sre_command('NODATA [NOWAIT] [NORESPONSE]')` No data are to be sent; the response is complete. This command is intended to be used when only a header, or nothing at all, is to be returned to the client. If NORESPONSE is specified, then no response line and header will be sent either, even for an HTTP/1.0 or later request; the connection will be closed (unless persistent). This option could be used for testing, or if (say) a faulty client was sending repeat messages. The NOWAIT keyword may be used to force the current connection to be closed after any response is sent, even if a persistent connection had been requested. Notes: NODATA is a completion command
  QUERY | Lookup one, or several, SRE2003 variables. This is an alternative to the SRE_EXTRACT procedure. Its advantage is that you can lookup several variables at once. Their values will be returned in a CRLF (`'0d0a'x`) delimited list. Example `stuf=sre_command('QUERY ',' Username Servername Request_Line') parse var stuf uname'0d0a'x sname '0d0a'x rline`
  READ | Read the request headers or the request body. `Syntax: status=sre_command('READ HEADER|BODY [ENABLE_CE_GZIP] [SUPPRESS_TE_GZIP]')` where:
  `READ` | is used to read the request `HEADERS`, or the request `BODY`.
  The two options are only used with `BODY`
  `ENABLE_CE_GZIP` | enables UnGZIP of a request body that is gzipped, and that contains a Content-Encoding: GZIP header.
  `SUPPRESS_TE_GZIP` | disables UnGZIP of a request body that is gzipped, and that contain a Transfer-Encoding: GZIP header.
  `status` contains the result of the READ. If BODY is being read, `status` will have the following syntax: If no error occurred: `length`||CRLF||request_body where length is the length (in bytes) of request_body If an error occured `error_code`||CRLF||error_message `error_code` will be a negative value. Its absolute value corresponds to an http error response. These include: `400 408 411 413 415 501` By default, ungzip is done for "GZIP as a transfer encoding", but not for GZIP as a content encoding. Example:
           hdrs=sre_command('READ HEADER')
           abody=sre_command('READ BODY ENABLE_CE_GZIP')
           parse var abody nsize '0d0a'x params
           if nsize<0 then do          /* some kind of error on request body read */
              amess=SRE_Extract('REQUEST_ERROR')
              rcode=sre_error_response(abs(nsize),,servername,amess,id_info)
              return rcode
           end
  - Notes: when SUPPRESS_TE_GZIP is not specified, and an unknown transfer-encoding is encounted, a 501 Unimplemented response is automatically generated. when ENABLE_CE_GZIP is specified, and an unknown content-encoding is encountered, a 415 Unsupported Media Type response is automatically generated. `SRE_EXTRACT('READBODY_STATUS')` can be used to check, and returns ...
    `none` | the request is not POST or PUT
    `pending` | the request body has not yet been read
    `completed` | the request body was successfully read
    `error` | an error occurred when reading the body, and the connection was closed
  In addition, A REQUEST_ERROR variable contains the "error status" of this connection. It can be checked with SRE_Extract('REQUEST_ERROR'). REQUEST_ERROR will have a number of possible values, with a value of ' ' meaning "no error".
  RESPONSE | RESPONSE is used to change the response line, or to retrieve its current value. `Syntax: aa=sre_command('RESPONSE response line ')` where `response_line` is your desired response line. or ... `aa=sre_command('RESPONSE')` Examples: `aa=sre_command('RESPONSE http/1.1 206 Partial Content')` `the_respline=sre_command('RESPONSE')` Notes: By default, SRE2003 sends a response line of: http/1.1 200 Ok sre_command('RESPONSE xxx) always returns a '1' sre_command('RESPONSE ') returns the current value of the response line. If the response line has not been modified, this will be the default value of `HTTP/1.1 200 Ok`
  SET | SET is used to set "connection specific" values of several variables. `Syntax: status=sre_command('SET option',avalue)` where option is one of:`LIMITTIMEINACTIVE LIMITTIMEWAIT LIMITTIMETOTAL LIMITBODY DATADIR TEMPFILE` and `avalue` is the new "connection specific" value Examples: `status=sre_command('SET DATADIR','e:\special\doc') status=sre_command('SET LIMITTIMETOTAL ',1000)` Notes: these do NOT effect the default values -- they only effect the current (possibly multiple request) transaction. EXTRACT can be used to read these "modified" values to permanently change these variables, you must change SRE2003.CFG (say, by running`SRE2003 -m` from an OS/2 prompt). `TEMPFILE` is special -- its default value is ' '. If `TEMPFILE` is set to a filename, SRE2003 will attempt to close this `TEMPFILE` when the transaction is completed. This avoids problems when a request time's out.
  - - SEND | SEND is used to build multipart messages, or to send pieces of a response as it is being built. `Syntax:` result=sre_command('SEND [NOWAIT][EXPIRES offset] [TYPE content-type] ') ... various FILE, VAR, STRING and other SRE_COMMAND calls ... result=Sre_command('SEND COMPLETE [NOWAIT]') The basic idea is that all "completion codes" (STRING, VAR, FILE, CONTROL, and NODATA) between a 'SEND ' and a 'SEND COMPLETE' will NOT mean "end of response". Instead, the start of a response (the response line and response headers) is sent to the client when the first SEND is issued, and the response is completed when a 'SEND COMPLETE' is recieved. Typically, the response headers (and perhaps the response line) are specified before the first call to SEND. However, you can specify the type/subtype (and perhaps a boundary string) in the SEND command by including a TYPE modifier. Examples:`` status=sre_command('SEND TYPE text/plain') status=sre_command('SEND TYPE multipart/mixed; boundary=This_string_sePerates') SEND COMPLETE ends the response. For example:`` response_code=sre_command('SEND COMPLETE') response_code=sre_command('SEND NOWAIT COMPLETE') The NOWAIT option can be used in either the first or final SEND. If used in the first SEND, then a `Connection: Close` response header is added, and the connection is closed (after a SEND COMPLETE). If NOWAIT is only used on the final send (i.e.; SEND NOWAIT COMPLETE) then the connection will be closed, but a `Connection: Close` response header will not be sent. The EXPIRES option can be used to create an `Expire:` response header. `offset` is when this file expires, as measured from the current time. There are several formats for offset: `xx.yy` xx number_of_days, yy fraction_of_a_day `xxH` xx hours `xxM` xx minutes For example, the following all mean 12 hours from now: `EXPIRES 0.5`, `EXPIRES 12h`, `EXPIRES 720m` Notes: Within the boundaries of a SEND and a SEND COMPLETE: All header specifications are ignored (including TYPE), and NOWAIT is ignored. If you want to specify different types for each part of a multipart response, you can use VAR (you can also use VAR to include boundary lines). The status returned is either the number of bytes sent, or a negative error code. The ERASE modifier of a FILE command is ignored (temporary files will not be deleted).
      Reminder: | SEND is not used to return responses to multiple requests on a single "maintained" connection. Instead, SEND can be used to return multiple "parts" within a single "multi-part aware" request.
  You can specify the response-line, and additional response headers, by using (on the first SEND call) the `response_line` and `header` arguments in the advanced form of SRE_COMMAND. If you use the `TYPE` option with SEND, it must be the last option. That is, `NOWAIT` and `EXPIRES` must preceed `TYPE`. When `SEND` is enabled, all Instance Manipulations (including Range extraction) are disabled.
  STRING | STRING is used to send a short string to the client. `Syntax: vv=sre_command('STRING string',header)` The single string is returned to the client as a simple text/html response. The `header` is optional. If included, it should be a short sentence to display at the top of the screen. The STRING command can be used to return a simple message to the client. Multiple lines can be sent, if necessary, by embedding a CR-LF sequence ('0d0a'x) to separate lines. Example:`stat=sre_command('STRING Hello World!')` Notes: STRING is a completion command The STRING mode of SRE_COMMAND will always return two numbers, seperated by a space -- a status code and the bytes sent. For example: `200 15161`
  VAR command | Return the contents of a "variable" to the client. `Syntax: ff=sre_command(' VAR [NOWAIT][CHUNK] [ETAG etag] [ETAG_AUTOn] [ETAG_APPEND] [QUICKPOST] [MD5] [TE_GZIP] [EXPIRES offset] [TYPE content-type] ', varname]` The contents of the Rexx variable named by `varname` will be sent to the client. `varname` is a standard REXX variable, as it would be written in the filter. The optional keywords may be specified, in any order, and have the following effects: `CHUNK` -- send the contents of the variable using a chunked format `EXPIRES offset` -- add an `Expires:` response header. `offset` is when this file expires, as measured from the current time. There are several formats for offset: `xx.yy` xx number_of_days, yy fraction_of_a_day `xxH` xx hours `xxM` xx minutes For example, the following all mean 12 hours from now: `EXPIRES 0.5`, `EXPIRES 12h`, `EXPIRES 720m` `ETAG eee` -- eee is the etag associated with this response. If used, an Etag: `eee` response header will be added. For example: `Etag gxyq1` will cause a `Etag: "gxyq1"` response header to be added. `ETAG_APPEND eee2` -- `eee2` is appended to the Etag, where Etag can be specified (with an ETAG) or automatically generated (with an ETAG_AUTO). Typically, `eee2` should start with a `;`. `ETAG_AUTO,` `ETAG_AUTO1`, and `ETAG_AUTO2` -- SRE2003 will generate an etag for this response. ETAG_AUTO: use the current date and the length of string ETAG_AUTO1: use the current date and the length of string, and use the contents of the string ETAG_AUTO2: use the contents of the string On rare occassions, or on sites where dynamic resources can occur very rapidly (in less then a second), the ETAG generated by ETAG_AUTO may not be unique. In such cases, you can use ETAG_AUTO1 or ETAG_AUTO2, which causes SRE2003 to compute a more complex (and more time consuming) ETAG Notes: For all values of variants of ETAG_AUTO, the values of the entity-headers are also used. if any of the `ETAG_AUTO` variants are used, and `ETAG eee` is also used, then the explicit etag (the `eee`) is used. See the description of SRE_ETAG for details on how SRE2003 computes etags. `MD5` Create a Content-MD5 response header. This is created after range extraction, but before transaction-encoding GZIP. `NOWAIT` -- forces the current connection to be closed after any response is sent, even if a persistent connection had been requested. `QUICKPOST` --immediately return "anticipated status" information prior to responding to the client. This can speed up throughput, since the filter can exit (releasing memory) prior to completion of response. Though potentially wrong (say, if a client kills a connection) this "anticipated" information is often sufficient for logging purposes. `TE_GZIP` If supported by the client (as indicated in the TE request header), GZIP the file before sending it to the client. Notes: SRE2003's on-the-fly GZIP is done as a transfer-encoding. The entity tag is computed before GZIPping. GZIPed variants of a file are NOT cached (since they are created on the fly, and then erased) In general, only http/1.1 clients will be capable of recieving GZIP as a transfer-encoding. `TYPE xxx` -- `xxx` is the "mimetype" of this resource. SRE2003 will include a Content-type response header that uses xxx. For example: `type text/plain` will cause SRE2003 to add a `Content-type: text/plain` response header. Example (returning an HTML document to a Web client) :
        /* This is Rexx code */
        mydoc=' Hello world! '          /* may be large */
        stat=sre_command('var type text/html  ', mydoc)
        return
  Notes: The VAR mode of SRE_COMMAND will always return two numbers, seperated by a space -- a status code and the bytes sent. For example: `200 6236` SRE2003 will generate a header automatically if the TYPE option is specified. You can also use the HEADER option of SRE_COMMAND to specify a content-type. When using CHUNK, you should NOT include a content-length header, and you SHOULD specify a "transfer-encoding: chunked" header. VAR is a "completion code"

  There is an advanced form of sre_command that can be used with completion codes (such as VAR, FILE and STRING).
  | Syntax: `stuff=sre_command(acommand,amessage,id_info,response_line,headers)` where:
  `acommand`: | a command, such as FILE or VAR
  `amessage`: | a message, which depends on acommand. Some values of `acommand` do not use `amessage` (VAR uses amessage, but FILE does not)
  `id_info`: | optional. info used to communicate with daemons. If known, it can speed things up.
  `response_line`: | optional. response line (if acommand is a completion code) Example of `response_line`: `'HTTP/1.1 301 Moved Permanently'` Note that you must include the `HTTP/x.x` token when specifying a response line.
  `headers`: | optional. CRLF ('0d0a'x) delimited list of headers (if acommand is a completion code) Example of `headers`: `'Foobar: this is foo bar '|| '0d0a'x||'Barfoo: and this is bar foo'` Note: headers specified by this argument override headers specified by `SRE_COMMAND('HEADER ...')`. However, they do not override a content-type header set by a TYPE option. Furthermore, don't bother trying to set Content-Length or Transfer-Encoding headers (SRE2003 insists on determining when and how to use these two headers).

SRE_COUNTVARS: set and get "counter" variables
  This is used to set global counters variables (such as a running count of bytes sent). Several special counter variables are stored in the OS/2 environment for quick (though not totally up-to-date retrieval).
  These "quicklist" variables are: `BYTESREADTOTAL BYTESSENTTOTAL TRANSACTIONS REQUESTS LIMITS ERRORS CACHEHITS`

  `Syntax:
  foo=sre_countvars(varname,avalue,ownid)`

  where:

  `varname` | the counter variable. If you begin varname with a "=" (without the ") then "force" a read from the cache (rather then from the enviroment) -- this only applies to the quicklist variables.
  `avalue` | the value to add If avalue is not specified, then return current value of varname If avalue = RESET, then reset the counter to 0.
  `ownid` | optional, the clients "own_id". This is used ONLY if you are reading the value of a non "quick list" counter. If not specified, an own_id will be generated automatically.

SRE_DATADIR: return the default data directory
  SRE_DATADIR will return the default data directory. This may be a host specific directory. In fact, it may be dynamic to the request.
  Syntax:

         sname=SRE_datadir()
         sname=SRE_datadir('host')
         sname=SRE_datadir('default')

  If 'host' is specified, then the default host-specifc data directory (as set in SRE2003.CFG, or as specified by a calls to SRE_HOSTINFO) is returned.

  If 'default' is specified, the default data directory is returned (as specified in SRE2003.CFG).

  If no argument is given, then either:

  - a request specific datadir (as may be set by a SRE_COMMAND)
  - a host specific data directory
  - the default data directory (with the request specific datadir returned if available, otherwise the host specific, otherwise the default)

  Notes:

  - `SRE_COMMAND('SET DATADIR ',adir)` can be used to set the "request- specific" value returned by datadir().

SRE_DATESTAMP: Create a time & date string
  Compute a datestamp, of the form: `Fri, 20 Jul 2001 12:28:09`

  `Syntax:`
  `adate=sre_datestamp(filedate,gmtoff)`
  where:

  `filedate:` | a date in one of two formats: yy/mm/dd/hh/mm/ss Example: 01/11/25/13/32/02 mm-dd-yy hh:mn:ss Example: 11-22-01 16:52:16 If not specified, use the current date and time
  `gmtoff:` | Optional, the offset from GMT time, in seconds. If not specified, SRE_DATESTAMP will lookit up (using the GMTOFFSET computed by SRE2003).

  Examples:

                t1=sre_datestamp()
                edtoffset=14400
                t2=sre_datestamp(,edtoffset)

                a=sysfiletree('C:\CONFIG.SYS','aa.')
                parse var aa.1 adate .
                t3=sre_datestamp(adate,edtoffset)

              which could yield:

                 t1:       Fri, 20 Jul 2001 12:30:10 GMT
                 t2:       Fri, 20 Jul 2001 16:30:10 GMT
              adate:       01/06/29/16/15
                 t3:       Fri, 29 Jun 2001 20:15:00 GMT

  Note: See SRE_GMT for a more complicated version of SRE_DATESTAMP

SRE_ERROR_RESPONSE: Return a server error response to the client
  SRE_ERROR_RESPONSE will return send a server error response to the client.
  - A number of 4xx and 5xx responses are supported (see below)
  - Optionally, SRE_ERROR_RESPONSE can write an error messages to the error log file.

      Syntax:
         rcode=sre_error_response(type,amessage,servername,log_message,id_info)

  where all the variables are optional:

  `type` | The type of the error. The currently supported types are: 400 or BAD: Some kind of problem 403 or FORBIDDEN : the server is refusing to honor this request (authorization will not help) 404 or NOTFOUND : The default. Resource can not be found 405 or NOTALLOWED : The method is not allowed 408 or TIMEOUT: A time occured while reading request body 409 or CONFLICT: A conflict with the current state of the resource 410 or GONE: The resource has been permanently removed. 411 or NOLENGTH: Length missing from request body (and not chunked) 412 or PRECONDITION: A precondition failed 413 or LARGEBODY : Request entity too large (i.e.; POST request with huge body) 414 or LARGEURI: Request URI too large. 415 or UNSUPPORTED: Unsupported media type 500 or ERROR : Server error 501 or NOTIMPLEMENTED : not implemented (the server does not support this request method) 503 or BUSY: service unavailable (try again later). 503 xxx: same as 503, with xxx the number of seconds the client should wait before retrying 506 or ALSONEGOTIATES: content negotiation resolves to another content negotiation 510 or NOTEXTENDED: Server does not support extended http method
  `amessage` | Optional. If specified, this should be a full html response (including `<html> ... </html>)` If not specified, a response message will be automatically generated (depending on the `Type` and the `Log_message`).
  `servername` | optional. The DNS (or ip address) of this server. Looked up if not provided.
  `log_message` | Optional. If provided, and if `amessage` is not provided, then `log_message` will be added to an automatically generated response. Also, if `type=500`, then `log_message` is written to the SRE2003 error log file.
  `id_info` | Optional, the "id_info"
  `Rcode` | is the response from a SRE_COMMAND('VAR ..') call. It contains the "response code".

SRE_EVENTVARS: set and get "event" variables
  This is used to store event variables.

  Event variables are variables whose value changes frequently (such as the time the most recent connection was accepted). These are NOT necessarily numeric values (i.e.; it could be a timestamp, or a client a IP address).
  As with Counter variables, a "quicklist" is maintained of events that are also stored in the environment.
  These are:`LASTACCEPT LASTIDLE LASTRESET LASTADDRESS`

  `Syntax:
  foo=sre_eventvars(varname,avalue,ownid)`
  where:

  `varname` | the event variable. If you begin varname with a "=" (without the ") then "force" a read from the cache (rather then from the enviroment) -- this only applies to the quicklist variables.
  `avalue` | the value to store If avalue is not specified, then return current value of varname
  `ownid` | optional, the clients own_id. This is used only if you are reading the value of a non "quick list" event. If not specified, an own_id will be generated automatically.

  Notes:
  - One could also use SRE_VALUE for event-like variables

SRE_ETAG: automatically generate an Etag
  SRE_ETAG is used to automatically generate an Etag, given a file or a variable.
  Syntax:
  `an_etag=sre_etag(in_type,filename_or_var,use_contents,more_stuff)`
  where:

  `in_type` | What type of input. 0 = the contents of a variable 1 = a fully qualified file name
  `filename_or_var` | The filename, or string, to compute an etag for. If in_type=0, uses the actual value of `filename_or_var` If in_type=1, treats `filename_or_var` as a filename, and uses the contents of this file.
  `use_contents` | `use_contents` controls whether to use the actual contents, of the file or message, when creating an etag.
  | `0` | do no use contents. Instead, use length and date information. | This is the fastest alternative. Its disadvantages are that on rare occassions it may not produce a properly unique etag. In addition, it may also produce etags that differ even though the entity's contents are the same.
  | `1` | use contents and and use length and date information. | This is the slowest, but most robust alternative. It may also produce etags that differ even though the entity's contents are the same.
  | `2` | use contents only (do not use length and date information) | This is robust, and will not not produce etags that differ when the actual contents are the same.
  `more_stuff` | An arbitrary string. This is typically the values of a set of the entity-headers (since etags are formally defined as covering both entity body and entity headers). It will be used, along with the information dictated by `use_contents`, to generate the ETAG.

  `an_etag` will be the value of the etag.

  Notes:

  - In all cases, a CRC is used to create the etag. The value of `use_contents` and `more_stuff` control just what information is used when creating this CRC.
  - Basically, `1` is the most robust etag: it is least likely to create an improper etag.
  - `2` is nearly as robust as `1`, but is more likely to correctly produce etag matches (say, on requests that use If-None, If-Range, or IM request headers)
  - On sites where minor changes to files are occurring very rapidly (several times per second), you might need to use 1 (or 2) to generate the more robust etags.
  - For the etag of a request-URI to be properly unique, its value must uniquely describe the contents (and headers) of an entity. In other words, the same etag value should never be assigned to different responses if any part of the entity-body (the contents), or any of the entity-headers, is not byte-wise equivalent.
  - Etags are properly unique only within a request-Uri. You can use the same etag for completely different entities, if these entities are responses to different request-URIS.
  - Actually, due to inconsistencies in how RFC2616 defines entity-headers, SRE2003's auto-etag creation feature allows you to selectively relax the requirement that all entity-headers must be the same. See the description of ENTITY_HEADERS_IGNORE for the details.

SRE_EXTRACT: returns settings of several SRE2003 variables.
  SRE_EXTRACT is used to obtain values of the SRE2003 variables, several of which are request (or connection) specific. The syntax of SRE_EXTRACT closely follows the GoServe EXTRACT function, with several additional fields supported (and a few not supported).

  Syntax:
  `avalue=SRE_EXTRACT(varname,id_info)`
  where:

  `id_info` | optional -- the id info of the transaction/request you want information from. If not specified, information about the current transaction/request.
  `varname` is one of the following variables.
  `BYTESREAD` | the number of bytes received from the network, so far during the current transaction.
  `BYTESREADTOTAL` | the total number of bytes received from the network. You may need to increase the Rexx NUMERIC DIGITS setting if you wish to do arithmetic on this count. 16 digits should be sufficient.
  `BYTESSENT` | the number of bytes sent to the network, so far during the current transaction.
  `BYTESSENTTOTAL` | the total number of bytes sent to the network. You may need to increase the Rexx NUMERIC DIGITS setting if you wish to do arithmetic on this count. 16 digits should be sufficient.
  `CLIENTADDR` | the client's address used for the connection, in numeric form (for example, 12.34.56.78). For a symbolic name for the address, see the CLIENTNAME function.
  `CLIENTMETHOD` | the method (verb) being invoked by the client. For example, "GET" or "POST".
  `CLIENTPORT` | the client's port number used for the connection.
  `CLIENTPROTOCOL` | the protocol being used by the client. For example, "HTTP/1.0".
  `CLIENTS` | the number of clients currently connected.
  `DATADIR` | The connection specific default data directory. You can also use the datadir() function to return this value. In addition, the filter is called with `datadir` as one of the components of the `hostinfo` argument.
  `DATADIR_DEFAULT` | The default value of datadir (as set in SRE2003.CFG).
  `ELAPSED` | the elapsed time, in seconds, since the current transaction started (that is, when the network connection was accepted).
  `ERRORS` | the count of errors detected.
  `BROKEN` | the count of broken connections (connections closed by the client)
  `FILTER` | the name of the Rexx filter.
  `HOST_NICKNAME` | the "host nickname" assigned to this "host" If no host nicknames are assigned, returns a ''
  `GMTOFFSET` | the GMT offset (in seconds).
  `LASTADDRESS` | IP address (numeric) of the most recent client
  `LASTACCEPT` | timestamp of the last accepted connection [format: yyyy.mm.dd hh:mm:ss].
  `LASTIDLE` | timestamp of when SRE2003 last entered an idle state, with no connections [format: yyyy.mm.dd hh:mm:ss]. Note that this is only as accurate as the "update rate" (set in SRE2003.CMD).
  `LASTSECOND` | time now, in the same format [yyyy.mm.dd hh:mm:ss] as the other LASTxxxx items.
  `LASTSTART` | timestamp of when this instance of SRE2003 was started [format: yyyy.mm.dd hh:mm:ss].
  `LASTRESET` | timestamp of last RESET ALL "CONTROL" command [format: yyyy.mm.dd hh:mm:ss].
  `LIMITS` | the count of limits exceeded (that is, the count of transactions that were ended due to a limit being exceeded). The limits counted are the total connection timeout (LIMITTIMETOTAL), the incoming data measures (LIMITBODY and LIMITHEADER), and maximum clients exceeded (LIMITCLIENTS). The latter is only counted once for each non-idle burst of connections.
  `LIMITBODY` | Connection specific maximum size of request body (as sent by a POST or PUT request), in kB
  `LIMITBODY_DEFAULT` | Default value of LIMITBODY
  `LIMITCLIENTS` | maximum number of client connections allowed concurrently [1 through 200 -- to increase max size, set the MAXCLIENTS value in SRE2003.CFG).
  `LIMITHEADER` | Maximum size of headers (including the request line), in kB
  `LIMITTIMEINACTIVE` | Connection specific maximum time, in seconds, for which SRE2003 will allow a client to remain connected but inactive (that is, without sending or reading data) [0 through LIMITTIMETOTAL].
  `LIMITTIMEINACTIVE_DEFAULT` | The default value of the above.
  `LIMITTIMETOTAL` | Connection specific maximum time, in seconds, for which SRE2003 will allow a client to remain connected, even if active [LIMITTIMEINACTIVE through 1E+9].
  `LIMITTIMETOTAL_DEFAULT` | default value of the above
  `LIMITTIMEWAIT` | Connection specific maximum time, in seconds, for which SRE2003 will keep a client connection open waiting for a new request. This applies for all http/1.1 requests, and for all http/1.0 requests that contain a 'Connection: keep-alive' header with the previous request [0 through 1E+9].
  `LIMITTIMEWAIT_DEFAULT` | default value of the above
  `LISTEN_SOCKET` | the socket bound to the http port. This is the socket that SRE2003 `SOCKLISTEN`'s to
  `NUMSENDS` | number of VAR, FILE, CONTROL, STRING, and NODATA commands issued after a SEND command (0 if no SEND command was ever issued). Note that the initial SEND will set NUMSENDS=1.
  `PEAKCLIENTS` | the maximum number of clients that were connected simultaneously.
  `READWAITTIME` | average read wait time (seconds).
  `READBODY_STATUS` | The status of a read of the request body. If not POST or PUT, then returns 'none'. Otherwise, returns 'pending','completed', or 'error'.
  `REQUEST and REQUEST_NUMERIC` | the unique number for this HTTP request. This is incremented as each HTTP request is read. This can differ from the TRANSACTION (connection) number if a connection fails to send a request, or if there is more than one request in a transaction. REQUEST is structured as TRANSACTION_NUMBER || REQUEST_AS_LETTER REQUEST_NUMERIC is structured as TRANSACTION_NUMBER || REQUEST_AS_DIGITS Thus, for transaction # 115, request 1 would yield: REQUEST: 115A REQUEST_NUMERIC: 1151 For transaction # 4312, request 3 would yield: REQUEST: 4312C REQUEST_NUMERIC: 43123
  `REQUESTS` | the number of HTTP requests read since SRE2003 was started.
  `REQUEST_ERROR` | most recent connection error (for this connection) or '', if no connection.
  `REQUEST_LINE` | the request line (for this request). For example:`GET /INDEX.HTM HTTP/1.0`
  `RESPONSE_CODE` | the response code (i.e.; 200, 404, 301). If response not yet send, returns '000'.
  `RESPONSETIME` | average response time (seconds).
  `RESPONSEOVER` | number of connections over which RESPONSETIME and READWAITTIME have been averaged.
  `SELECTOR` | the selector string: the Universal Resource Indicator, as recieved from the client (that is, the leading / is retained, and without url unpacking)
  `SERVERADDR` | the server's address used for the connection, in numeric form (for example, 11.22.33.44). For a symbolic name for the address, see the SERVERNAME function.
  `SERVERPORT` | the server's port number used for the connection (for example, 80 for default HTTP).
  `SERVERPROTOCOL` | always returns "http/1.1"
  `SERVERSOFTWARE` | the level of the server software (for example "SRE2003 ver 1.12d"). This is the same as returned by the function calls SRE_SERVER() .
  `STARTTIME` | The time that this transaction was started
  `STARTTIME_REQ` | The time that this request was started (note that transactions may incorporate multiple requests)
  `TEMPFILE` | The `TEMPFILE` value. By default, this is ' '. However, you can set it using `SRE_COMMAND('SET TEMPFILE',a_file_name)`.
  `TRANSACTION` | the unique number for this transaction (connection). This is incremented as each client connects to the server. Note that each transaction may yield several requests (though not concurrently).
  `TRANSACTIONS` | the number of transactions since SRE-http was started.
  `USERNAME` | the username, as provided in an Authorization: request header. If no Authorization: request header, this returns ' '. Note that you can also use SRE_EXTRACT_USERNAME to obtain the username.

  Notes:
  - The following "GoServe EXTRACTABLE" variables are not supported.
    - GMTSET -- GMT MUST be available
    - FASTFILE -- Instead, see the REQ_CACHE* parameters in SRE2003.CFG
    - FASTFILTER -- Instead, see the REQ_CACHE* parameters in SRE2003.CFG
    - NETBUFFER -- May be supported later
    - TRACE -- Instead, see the AUDIT_ITEMS parameter in SRE2003.CFG.
  - There are a number of other variables (such as the various AUDIT and DIAG variables) for which no support is currently planned. However, the AUDIT_ITEMS parameter (in SRE2003.CFG) can be used to obtain much of this information.
  - Also note that the GOSERVE QUERY command is NOT supported by SRE2003.

SRE_EXTRACT_USERNAME: extract the username from an authorization header
  Extract the username from an authorization header

  `Syntax:`
  `username=sre_extract_username(auth_header)`
  where:

  `auth_header` | auth_header is the value of the Authorization: request header. This can be obtained either by using the SRE_REQFIELD function, or by using the AUTH argument sent to the filter.

  SRE_EXTRACT_USERNAME will extract the "username" from either a BASIC or a DIGEST Authorization: request header. If the auth_header is empty, malformed, or otherwise does not contain username information, then a ' ' is returned.

  Example:

            aa=SRE_reqfield('Authorization')
            username=sre_extract_username(aa)

  Note: a `SIMPLE` type of auth_header is also recognized:
  `SIMPLE username password`. While asking sre_extract_username is hardly necessary to extract the username, we provide it for completeness.

SRE_FIX_URL: Make a fully specified url
  Make a fully specified url; such as `http://a.b.net/xxx/yyy`

  `Syntax:`
  `theurl=sre_fix_url(aurl,servername,serverport)`
  where:

  `aurl:` | a relative or absolute url.
  `servername:` | optional. The ip name (domain name) or numeric ip address of the server. If not specified, use the local domain name.
  `serverport:` | optional. The serverport. If not specified, use the local port (if servername not specified), or use port 80.

  `theurl` will be a fully qualified url.

  Examples (assuming SRE2003 is running on server with a domain name of foo.bar.net):

          aa=sre_fix_url('/files/index.htm')
          aa ==> http://foo.bar.net/files/index.htm

          bb=sre_fix_url('/animals/images/tiger.jpg','www.funplaces.org')
          bb ==>  http://www.funplaces.org/animals/images/tiger.jpg

  #### Notes

  - if aurl starts with `http://`, then nothing is done
  - The following rules are used

            1) Temporarily remove anything after a ?
            2) Strip any leading /
            3)  Look for a /
                If no / found,
                   Look for periods.
                      If > 1 period found, it's an ip address
                      If <2 found, it's a local uri (say, a file on the
                      local server)
                If / is found
                  Check stuff before first /.
                     If it has any periods, its an ip address (stuff after
                     is the "selector")
                     If no periods, it's a local url (say, stuff after the /
                     contains subdirectory & file specifiers)

SRE_GET_URL: Get contents of a url
  Use socket calls to retrieve the contents of a url.

  `Syntax:`
  `stuff=sre_get_url(aurl,maxchars,verbose,headers)`
  where:

  `aurl:` | a relative or absolute url. If it's a relative URL (no domain name), then use the local host and local port.
  `maxchars:` | Optional. Maximum # of characters to read. If not specified, then get up to 10 million
  `verbose:` | Optional. If 1, then pmprintf some status messages
  `headers:` | Optional. A CRLF delimited list of request headers to add to the request.

  `Stuff` is the full contents (including response line) from the server hosting `aurl`

  Examples:

         stuff=sre_get_url('family/doglife.html')
         stuff=sre_get_url('foo.bar.net/pictures/maple_tree.jpg')
         stuff=sre_get_url('http://foo.bar.net/pictures/apple_tree.jpg')
         stuff=sre_get_url('www.goo.org:8080/class8/lessons.shtml')
         stuff=sre_get_url('www.goo.org:8080/class8/lessons.shtml')
         stuff=sre_get_url('www.junkstuff.com/biglist.txt',10000,,'X-limit:10 pages')

  #### Notes

  - This is a fairly simple procedure -- it uses default timeouts. Thus, it is not very robust against flakey connections, etc.
  - The AURL can start, or not start, with `http://`
  - To specify a port other then 80, use the standard `:nnnn` syntax (after the domain name in AURL).

SRE_GET_URL_ADV: Get contents of a url -- advanced version
  Use socket calls to retrieve the contents of a url. This version is more robust than SRE_GET_URL -- it will detect and gracefully recover from broken connections and other errors.

  `Syntax:`
  `stuff=sre_get_url_adv(maxtime,maxbytes,type,server,req, ,
  mehost,upwd,mhdrs,verbose,qs,trn_Id,sock_time)`

  where ...

  maxtime | Optional. max time (in seconds) to allocate for this request. If this time is exceeded, close the connection and return an error message. If not specified, 30 seconds is used
  maxbytes | Optional. max bytes to allocate for this request. If this size is exceeded, close the connection and return whatever results you've gotten, with a status code of `6`. If not specified, 100M is used.
  type | Type of request. Typically, `HEAD` or `GET`. However, three special proprietary types can be specified: DNS = lookup ip address of server. Return the IP address, perhaps with :port appended HEADGET = Use a GET request, but only return the HEAD (or the first 999 characters, whichever is less) DSCGET = Use a GET request, but only return the first 1499 characters
  server | the server to send the request to. This can be a dns name, or an ipaddress. Alternatively, you can use the following more complete syntax: `dom_name,ip_address,proxy_address` where: dom_name : the domain name (or number) to send the request to. If a non-80 port is used, append :port_number (i.e.; foo.bar.net:8082) ip_address : optional, the dotted numeric IP addres for the domain. If not included, a DNS request is done to resolve `dom_name` to an ip address. (thus, use of ip_address is a time saver), Do NOT append the ip port (if needed, it should be appended to dom_name) proxy_address: Ip address of this proxy. If possible, give the numeric address. If a name is given, then a DNS request is done (thus, use of a numeric address is a time saver) If the proxy is using a port other then 80, append `:port_number` to the`proxy_address` (even if it's numeric). For example: ``foo.bar.net:8080` or `152.15.22.16:8080`` #### Notes: If you are NOT using a proxy server, leave proxy_address blank. For example: `foo.bar.net, 189.12.51.62` If you specify a proxy, then IP_address is ignored dom_name is required, even if it's the same as the ip_address (it is used to form a Host: header)
  req | the request string. For example, the `/mydir/index.sht` portion of `http://foo.bar.net/mydir/index.sht`
  upwd | Optional. `Username password,` If specified, a Basic Authentication request header will be added. These should be seperated by a space. For example: `Joe Xegi3` Alternatively you could add an explicit header, in `mhdrs`, using:
                   aa=sre_pack64_make(strip(username)':'strip(passwd))
                   mdirs='Authentication: Basic '||aa
  mehost | Optional. the callers domain name or ip address. This is used in a `REFERER` request header,
  mhdrs: | optional A crlf delimited list of headers, where each line has the form `Header_NAME: a string`
  verbose : | Verbosity of intermediate output. Intermediate output is written to the PMPRINTF "window" (which can be displayed using PMPRINTF.EXE). 0 = NO intermediate output (the default) 1,2, or 3 signal various levels (minimal, some, too much)
  qs | A two component argument, containing: the queue to send results back on, and the semaphore to use for forcing timeouts. This is not required if this is "called as a procedure", though the semaphore component of the argument can be used (though it is less likely to be useful) The queue component is required if this is "called as a daemon"; the semaphore component is not required, but if available it will be used (it makes much more sense to use the semaphore when calling as a deamon). The syntax of qs_info must be: `Queue_name semaphore_name` For example:`QCH_0193 /SEM32/SRE2003_32_02` The optional semaphore_name should be an open and posted 32 bit semaphore. When launched as a daemon, this procedure will poll this semaphore before all socket calls, and if is not posted (or if it has been closed), then an immediate timeout is forced. If you do not include a `semaphore_name`, then you won't be able to force a timeout. Otherwise, if you do not specify a semaphore, everything else will work (though the polling will not occur).
  trnid | Not required if a procedure call. a transaction thread id. Should be unique to this transaction -- it's used to identify the response when returned through a queue. Therefore, it is not needed when calling this as a procedure.
  sock_time | max time per socket call This must be less then `tottime`. If not specified, 30 seconds is used.
  - Returns: | If no error: When called as a procedure: If maxbytes is not binding: `0' 'ip_address||'0d0a'x||stuff` If maxbytes is binding: `6' 'ip_address||'0d0a'x||stuff` When called as daemon, sre_get_url_adv will push `trnid||' 0 '||ip_address||'0d0a'x||stuff` or, if maxbytes is binding, `trnid||' 6 '||ip_address||'0d0a'x||stuff` to `queue_name` Note: `stuff` is response from the server If error: Procedure call: return an error-code Daemon call: push `transaction||' '||error_code||' '||error_message`
        Error codes:
                0 = no error
                1 = ioctl error
                2 = connection error
                3 = problem encountered in sockrecv
                4 = sockgethostbyname error
                5 = coding error in this procedure
                6 = maxbytes limit is binding
  Examples:
       Call as procedure:
          moo=sre_get_url_adv
                (50,'GET','foo.bar.net,125.22.251.2','/abc/alpha.htm','mysite.net',,
                 'myname mypwd',,1,,,20)

       as procedure, using a proxy:

         oo=sre_get_url_adv(50,'DNS','proxy.wow.com')
         parse var oo . aproxy '0d0a'x .
         moo=sre_get_url_adv(50, ,
                 'GET','foo.bar.net,,'||aproxy,'/abc/alpha.htm','mysite.net',,
                 'myname mypwd',,1,,,20)

SRE_GMT: Compute a new GMT time
  Given a time & date string, and an offset, compute a new GMT time.

  `Syntax:`
  `newtime=sre_gmt(offset,basetime,outtype,gmtoffset)`
  where:

  `offset:` | offest in days, hours, seconds, or minutes
  `basetime:` | in several formats
  `outtype:` | format of output
  `gmtoffset:` | Optional, the size of gmt offset (in seconds). If not provided, it will be looked up.

  `newtime` the new time (incorporating the GMT offset and "user supplied" offset), in the desired format

  #### Details

  `Offset` | Add an offset to the "current time". Format can be: `days` : the default. Use a real number. i.e.; `1.3` (1.3 days), or `0.05` (1/20 day) Or, or you can add a d; say, `1.3d` `hours:` use an integer followed by an h. i.e.; `1h` `minutes:` an integer followed by an m. i.e.; `60m` `seconds:` an integer followed by a s. i.e.; `3600s` The default offset is 0 (no offset) If not specified (or '' is specified) then compute current GMT time (for supplied basetime)
  `basetime:` | The time to add the offset to. The input format can be any of the following (SRE_GMT will recognize the format)
  julian | 728882.887731 (days since 0/0/00 . fraction of day)
  internet | Sat, 12 Aug 1996 21:18:20 GMT
  old internet | Saturday, 12-Aug-96 21:18:20 GMT
  ansi c | Sat Aug 12 21:18:20 1996
  query datetime | 08-12-96 21:18:20
  sysfiletree | 96/08/12/21/18 or 96/09/12/21/18/22
  If not specified, the default is to use the current time
  `Outtype` | The output format
  I | (the default) internet style
  J | julian, from 0/0/00
  JS | julian, from 1/1/1990. Note: JS time equals J time + 726467.
  C | cookie -- similar to internet, but use 12-Aug-1994 (suitable for expires field of set-cookie)
  F | sysfiletree
  `GMT_OFFSET` | If 0, do NOT add a GMT offset (and do NOT add the `GMT` to I or C outtype) If >0, then use this as the GMT offset (in SECONDS) If not specified, use the TZ environment variable (via the SRE2003 sre_gmtoffset function)

  Examples:

          say sre_gmt(,728882.88773)
          say sre_gmt(.12,'Sat, 12 Aug 1996 21:18:20 GMT','J')
          say sre_gmt(.12,'Sat, 12 Aug 1996 21:18:20 GMT','JS')
          say sre_gmt('18000s','Saturday, 12-Aug-96 21:18:20 GMT')
          say sre_gmt('300m','Sat Aug 12 21:18:20 1996 ')
          say sre_gmt('5h','96/08/12/21/18','C',0)
          say sre_gmt('5h','03/08/12/21/18','C',0)
          say sre_gmt(,,'F',0)
        yields ....
          Tue, 13 Aug 1996 02:18:19 GMT
          728883.216064
          2415.216064
          Tue, 13 Aug 1996 07:18:19 GMT
          Tue, 13 Aug 1996 07:18:19 GMT
          Tue, 13-Aug-1996 02:17:59
          Wed, 13-Aug-2003 02:17:59
          01/11/25/16/54

  Note: SRE_DATESTAMP is a simpler version of this procedure.

SRE_HTML_ENCODE:replace special charaters with HTML entity references
  SRE_HTML_ENCODE will replace reserved HTML characters with their entity references.

  `Syntax:
  newmess=sre_html_encode(oldmess)`

  Precisely,

  all instances of | ... are replaced by
  --- | ---
  < | &lt;
  > | &gt;
  & | &amp;
  " | &quot;

  Also, any character with ascii value > 127 is replaced with `&#nnn;`

SRE_HTML_REPLACE: replace comments in an HTML file
  SRE_HTML_REPLACE is used to replace special HTML comments with a string. SRE_HTML_REPLACE is a useful tool for peforming simple server side includes.

  `Syntax:
  nustuff=sre_html_replace(stuff,sub1,...,sub15)`
  where:

  `stuff` | a string containing html
  `sub1,...,sub15` | Up to 15 substitution strings. Each `subN` has the structure: `code_to_replace replace_with_string` For example, if sub1 equals: `#LINK <a href="/hello.htm">Hello world!</a>` then any occurence (in stuff) of: `<!-- #LINK -->` will be replaced with `<a href="/hello.htm">Hello world!</a>`

  #### Notes:

  - `code_to_Replace` must not contain a space
  - the `replace_with_string` can be arbitrarily long and can contain any characters (it can contain CRLFS).
  - All occurences (not just the first) of a `code_to_replace` will be replaced by the corresponding `replace_with_string`
  - `code_to_replace` uses a case-insensitive matching algorithim

SRE_HOSTINFO: read & set host information
  SRE_HOSTINFO is used to read the host-nickname and `default data directory` for a host name. Host names are typically domain names (such as `foo.bar.net`), but they can also be dotted IP addresses (such as `125.221.51.2`), or "intranet" addresses (such `mymachine`).

  To support multi-hosting (one server supporting multiple domains), SRE2003 uses the idea of a "host nickname". Every request is compared against the list of defined hosts. If a match is found, the host-nickname and the `default data diretory` are returned. The filter can then use this information to determine where to get a file from, where to store logging information, etc etc etc.

  Although SRE2003 supplies the filter with this information (see section 5a of the main documentation), you can also use SRE_HOSTINFO to look it up. Furthermore, although you can use the INITHOST.RXX initialization procedure INIT_PROC (see INITHOST.RXX in the BIN subdirectory) to define Host entries, you can also use SRE_HOSTINFO.

  SRE_HOSTINFO has several modes:

  - READ: To search for a host-nickname for a specified host:
    `match=sre_hostinfo(a_host)`
    If a match is found, the following is returned:
    `a_host,host_nickname default_datadir`
  - SET: To add an entry to the list of hosts:
    `astat=sre_hostinfo(a_host,host_nickname,default_datadir)`
    For example:
    `astat=sre_hostinfo("MYSITE.FOO.ORG","MYSITE_X",'E:\WEBS\ME")`
    ASTAT will be 1 if success, 0 if falure.
  - !LIST: To list the currently defined hosts:
    `hinfo_list=sre_hostinfo('!LIST')`
    The number of defined hosts, and a list of hosts is returned (you can then lookup each host using READ calls to SRE_HOSTINFO). Each item in this list is seperated by a `CRLF`.
    For example:

        2
        foo.bar.net
        goo.bar.net

  - !LIST_NICK: To list the currently defined hosts nicknames:
    `hinfo_list=sre_hostinfo('!LIST_NICK')`
    A space delimited list of host-nicknames is returned.
  - CLEAR: To remove all host definitions, use: `astat=sre_hostinfo('!CLEAR')`
  - REMOVE: To remove 1 host definition:
    `astat=sre_hostinfo(a_host,0)`
  - MATCH: To match a host-nickname to a host, and return the host:
    `astat=sre_hostinfo('!SEEK',host_nickname)`

    Note: | If several hosts (servernames) have the same `host-nickname`, then the first match will be returned. To return all hosts that match a host-nickname, use ... `astat=sre_hostinfo('!SEEKALL',host_nickname)` a space delimited list of matching hosts will be returned .

SRE_LIST: Write/read entries in a randomly accessible list
  Lists are used to store semi-permanent variables. Each list is allocated a fixed number of slots (one slot per variable), As you add variables, eventually all the slots will be taken. At that point, a LIFO (last in first out) algorithim is used to free up space -- with one value removed. Items on a list are NOT referenced by variable name, though they can be read by position number (however, this position number will change as items are added to the list).

  `Syntax:
  val=sre_list(list_name,action,avalue,ownid)`
  where:

  `list_name` | The name of a list. Examples of list_name:`BYTES TOTAL_TIME START_TRANSMIT_TIME`
  `action` | Possible actions: `CREATE RESET PUSH QUEUE POP PEEK READ STATUS LIST`
  `avalue` | A value to store. If you intend to use SRE_LIST_STATS on this list, these values must be numeric.
  `ownid` | optional, it's the own_id of the caller. Or, set to 0 to mean "don't bother responding" (typically used with action of PUSH or QUEUE)

  The supported actions are:

  `CREATE` | create a list aval is the length of the list. If aval is not specified, a default of 600 is used. Returns: 1 on success
  `RESET` | clear all items in alist If avalue is specified, reset the size of the list to avalue. Returns: 1 on success
  `PUSH` | add aval to top of list (will be first out on a pop) Returns either 'OK 'value or 'ERROR 'error_message
  `QUEUE` | add aval to bottom of list (will be last out on pops) Returns either 'OK 'value or 'ERROR 'error_message
  `POP` | pop top value from list (remove the value). If list is empty, return '' or the value of aval.
  `PEEK` | look at top value from list (do not remove) If list is empty, return '' or the value of aval.
  `READ nnn` | look at the nnn'th value from list; where 1 is the bottom value (the last value before list is emptied)
  `STATUS` | returns 1 line of status info: `'#_entries='nentries', Max_entries='list_size`
  `LIST` | returns list of lists, using `#entries_in_list (crlf) value (crlf) ...`

  #### Notes

  - SRE2003 "queues" are similar to SRE2003 "lists", but are less flexible (for example, you can not read elements in the middle of a SRE2003 "queue"). See SRE2003.HTM for details.
  - SRE2003 "caches" are similar to "lsits, but are more flexible (they are accessible by variable name, and use a LRU mechanism to remove old entries). See SRE2003.HTM for details.
  - SRE_LIST is used to implement the various statistics reported on SRE2003's status screen.
  Examples: `
  foo=sre_list('REQUEST','QUEUE',request_line,0)
  nextval=sre_list('DELETEME','POP')`

SRE_LIST_STATS: Compute statistics on values stored in a list
  SRE_LIST_STATS is used to compute simple statistics on values stored in a list. Of course, this should only be used with lists that are known to contain ONLY numeric values!

  `Syntax:
  val=sre_list_stats(list_name,action,nentries,ownid)`
  where:

  `list_name` | name of list. Examples include: BYTES TOTAL_TIME START_TRANSMIT_TIME If the list_name doesn't exists, error
  `action` | stat to compute. Currently supported:`NUM MEAN MAX MIN SD SUM`. If nentries specified, NUM is <= NENTRIES
  `nentries` | Number of entries to use. If not specified, then use all entries available in the list.
  `ownid` | optional.

  Examples:
  `foo=sre_list_stats('TOTAL_TIME','MEAN',100,own_id)`

SRE_MD5: Compute an MD5 hash
  SRE_MD5 is used to compute the MD5 of a string or a file.
  SRE_MD5 also maintains a "cache", which can help with both speed and stability.

  `Syntax:`
  `md5val=sre_md5(var_or_file,file_flag,nocache)`
  where:

  `var_or_file:` | either a variable containing the string you want the hash of, or a fully qualified file name
  `file_flag:` | If 1, then var_or_file is a file name. Otherwise, var_or_File is a variable.
  `nocache:` | if 1, then do NOT look in the SRE2003 "MD5 of files" cache. This can be used to force recomputation of the MD5 of a file.

  Examples:

             amd5=sre_md5('hello world ')
             bmd5=sre_md5('D:\CONFIG.SYS',1)

  #### Notes

  - The size of the "MD5 of files" cache is set by the MAXMD5S variable in SRE2003.CFG
  - SRE_MD5 uses procedures in SRXFUNC.DLL
  - When the MD5 cache is enabled, then SRE_MD5 will "serialize" the computation of MD5s.

    > This helps system stability: the MD5 procedures in SRXFUNC.DLL can sometimes CRASH THE PROCESS (i.e.; kill SRE2003), a phenomemnon that seems to happen when its functions are called simultaneously.

    > Thus, use of SRE_MD5 (rather then the SRXFUNC functions directly), in conjunction with MD5 cache, will bolster system stability (as well as possibly improve speed).

SRE_MOVE_RESPONSE: Return an resource-moved response to the client
  SRE_MOVE_RESPONSE is used to send a this resource has been moved response to the client.

      Syntax:
         rcode =sre_move_response(movetype,selector,servername,port,age,sel0)

  where

  `movetype` | (optional) Type of move. Can be `301 302 303 200` or `307` or, equivalently, `MOVE TEMP REDIRECT NOTIFY` or `REPOST`. If not specified, a 301 (permanent move) response is returned to the client.
  `selector` | the selector (or fully qualified uri) to "move" to. If no domain name (or IP address) is specified in selector, and `servername` and `port` are not specified, then the redirection is back to this site (that is, to the servername and port of this request).
  `servername` | (optional) If no ip address listed in the selector argument, "servername" is used
  `port` | (optional) If specified, redirect to this port (otherwise, redirect to the standard http port)
  `age` | (optional) Length of time proxy caches should store this response (in seconds)
  `sel0` | (optional) The "original selector". It is used only with `NOTIFY` (it is written in the body of the response).
  and
  `rcode` | the return code from SRE_COMMAND('VAR ..)

SRE_NOTFOUND_RESPONSE: Returns a not found response to the client
  SRE_NOTFOUND_RESPONSE returns a `not found` (403,404, or 410) response to the client.

      Syntax:
         rcode=sre_notfound_response(type,message,servername,sel,id_info)

  where:

  `type` | Either 403,404 or 410. Or, FORBIDDEN, NOTFOUND, or GONE 403 or FORBIDDEN = the server is refusing to honor this request (authorization will not help) 404 or NOTFOUND= The default. Resource can not be found 410 or GONE = The resource has been permanently removed.
  `message` | Optional. If specified, this should be a full html response (including `< / html > ... </html >`) Otherwise the body of a response will be created (depending on type).
  `servername` | optional. Looked up if not provided
  `sel` | Optional. The requested resource (if not provided, it will be looked up)
  `id_info` | Optional. The "id_info"

  Rcode is the response from a SRE_COMMAND('VAR ..') call. It contains the "response code".

SRE_PACK64: Unpack a "mime-encoded" string

  `Syntax:`
  `text_val=SRE_pack64(encoded_string)`

SRE_PACK64_MAKE: Create a mime-encoded string.
  Create a mime-encoded string.

  `Syntax:`
  `encoded_string=sre_pack64(some_text)`

SRE_PACKUR: Unpack a URL-encoded string:

  `Syntax:`
  `uval=sre_packur(pval)`

  Example:
    `pval='DOG+%26+CAT+%3D%3D+FUN%21+%0D%0A%24+%2F+TIME+%3D+%25+%3F+'
    uval=sre_packur(pval)`

  yields
    uval=`DOG+&+CAT+==+FUN!+$+/+TIME+=+%+?+`

  Note that + are NOT converted to spaces!

  You can use
    `uval=sre_packur(translate(pval,' ','+'))`
  to convert + to spaces (do + conversion first, otherwise you might transform true "+" characters into spaces).

SRE_PACKUR_MAKE: Create a URL-encoded string:

  `Syntax:`

  - `pval=sre_packur_Make(uval)`

    URL-encode the most common special characters, and all characters with ascii values <32 or > 127.

    > These most common special characters are:

    >          Character   hex-value
    >          ----------------------
    >              tab        09
    >             space       20
    >             "           22
    >             <           3c
    >             >           3e
    >             [           5b
    >             \           5c
    >             ]           5d
    >             ^           5e
    >             `           60
    >             {           7b
    >             |           7c
    >             }           7d
    >             ~           7e

  - `pval=sre_packur_Make(uval,1)`

    When a `1` is used as a second argument, a more aggressive URL-encoding is computed. In particular, the percent (%), forward slash (/), semi-colon (;), comma (,), plus (+) and hash (#) characters are also URL encoded.
    Since these characters can have special meaning in URLS, this feature should be used carefully!

  - `pval=sre_packur_Make(uval,2,'xyz')`

    Only encode the characters in the 3rd argument (the `xyz`). This is useful if you just want to encode spaces, or some other small set of characters.

    Example::
    `uval='DOG+&+CAT+== FUN! +$+/+TIME+=+%+?+' pval=sre_packur_make(uval)` | `pval` will equal: `DOG+&+CAT+==%20FUN!%20+$+/+TIME+=+%+?+` Note that spaces are converted to %20, but `+` are not converted.
    Hence, for this example you probably should use:

  `pval=sre_packur_make(uval,1)` pval will equal:
  `DOG%2B%26%2BCAT%2B==%20FUN!%20%2B$%2B%2F%2BTIME%2B=%2B%25%2B%3F%2B`

SRE_PAUSE: Pause & unpause SRE2003
  Report on pause status of SRE2003; or pause, or unpause, When paused, SRE2003 will not accept new connections (but will continue processing current connections).

  `Syntax:`

              pstate=sre_pause()   -- pstate=1 if curently paused, 0 otherwise
              call sre_pause(0)   -- unpause SRE2003
              call sre_pause(1)   -- pause SRE2003

SRE_PMPRINTF:
  Write a message to the PMPRINTF window.

  SRE_PMPRINTF basically uses the PMPRINTF function, but it first checks for some possible bugs; for example, it won't try to write overly long lines.

  Note: to view the PMPRINTF window, you can use the PMPRINTF program

  `Syntax:`

           call sre_pmprintf(message)
        or
           foo=sre_pmprintf(message,all)

  where:

  `message:` | is the text message to write to the pmprintf window
  `all:` | optional. If message is > 110 characters, write on several 80 character lines

  Examples:

             call sre_pmprintf('a message here')
             foo=sre_pmprintf(' this is a long message .... ',1)

SRE_READ_FILE:
  Read a file. Returns file length and date, and file contents; or returns an error code.

  `Syntax:
  stuff=sre_read_file(filename,n_tries,stype,stripcz,nchars,offset)`

  where:

  `filename` | file to read
  `n_tries` | Optional # of times to try to open file (if temporarily locked). If not specified, only 1 attempt is made to open the file.
  `stype` | Optional Effects what is returned. `1` : status only -- do not return contents `11`: same as 1, but do not close the file `2` : contents only, or '' if an error occurred `3` : same as 2, but try harder (retry if file exists but is 0 length). Also, if file does not exist, wait a second and try again `4` : Same as default (' '), but use FILEREXX procedures `5` : Same as 2, but use FILEREXX procedures `otherwise` : return status and contents (as described below)
  `stripcz` | Optional If 1, then strip trailing Ctrl-Z (and anything that may follow).
  `nchars` | Optional. If specified, this number of bytes will be read from `filename.`. If filename is less then or equal to `nchars` bytes long, then all of the bytes in filename will be read. Note that the size variable reported (say, if status='') is the size of the file, and not the number of bytes read from the file.
  `offset` | Optional. Where to start reading after. Thus, an `offset` of `10` means the 11th character of the file is the first character read. If `offset` is greater then the file size, a ' ' or a `-4 error message` is returned (depending on stype). If `offset` + `nchars` > `file_size`, return the final `file_size - offset` characters.
  `stuff` | status code and contents of file, or an error response

  The structure of `stuff` is:

  If file was successfully read | `file_length file_date fully_qualified_filename '0d0a'x file_contents` Notes: `file_length` can be 0 (in which case there is nothing after the '0d0a'x. file contents can be anything (binary or text, with or without additional '0d0a'x). Exceptions: `stype=1 or 11` : Return "status" only: do not return file_contents (there will be nothing after the '0d0a'x). `stype=2` or `3` : Return contents only: do not return status info (the first character of `stuff` is the first character of the file).
  file could not be read | `error_code error_message` The `error_codes` are always negative valued integers: `-1` = no such filename `-2` = filename exists, but size was not produced `-3` = unable to open this file, even after trying several n_tries times Exceptions: `stype=2` or `3` : Return a blank string.

  Notes:

  - There is a one second delay between attempts; hence n_tries is essentially the max seconds to keep trying to open filename.
  - If stype=2 or 3, there is no way to distinguish between an error, and an empty or 0-length file. If you use stype=2 and the returned value is '', it is a good idea to try again with a stype=0 call.
  - Error code -2 occur when stream(filename,'c','query size') returns ''. This should never happen (if the file does not exist, a -1 is immediately returned).
  - Error code -3 occurs when stream(filename,'c','open read') returns NOTREADY.
  - The file_date is returned as nnn.ffff, where nnn is days since Jan 1 1990), and fff is a fraction of a day (accurate to 1 second, when 0.fff is multiplied by 86400).
    For example,`01-20-02 21:27:32` will be `4402.89412037`
  - The FILEREXX procedures, used in `stype` of 4 or 5, will read locked files (files that are opened-for-writing by other processes). This can be convenient if you want to read the current contents of dynamic files (such as log files).

  Examples:

       parse value sre_read_file('fname.1',4) with ilen fdate fname2 '0d0a'x content
       if ilen<0 then signal error_read

       content=sre_read_file('fname.1',4,2)
       if content='' then signal error_read

SRE_REQFIELD: Read request headers
  Reads one (or several) request header(s).

  `Syntax:
  avalue=SRE_reqfield(header_name,ith,id_info)`

  where:

  `header_name` | the name of a request header. For example:`"User-Agent", "Authorization", "If-Modified-Since", or "X-Option1"` Header_name is case insensitive
  `ith` | Optional. Ith instance of this header_name. If not speciifed, all instances of header_name will be concatenated and returned.
  `id_info` | Optional. Including the "id_info" (say, as supplied to the filter) will speed things up a bit.

  Actually, header_name can be a space delimited list of names.
  For example:
  `oo=SRE_reqfield('TE ACCEPT-ENCODING')`
  Note that you can NOT combine "list of headernames" with "ith instance"

  When asking for several headers, each header will be seperated by a '01'x character. Thus, in the above example you could use:
  `parse var oo is_te '01'x accept_enc`
  to obtain the "TE" and the "ACCEPT-ENCODING" request headers.

  Note:

  - If header_name='!ALL', then a list of all the request headers is returned

SRE_REQUEST_INFO
  Read "id" info for a request.

  `Syntax:
  aval=sre_request_info(avar,usetid,id_info)`
  where:

  `avar` | variable to lookup. If `avar` is not specified, then return the id_info variable for this request.
  `usetid` | optional. The thread-id of the request you need information about. If not specified, lookup info for the current request.
  `id_info` | optional. The id_info (say, as is provided to the filter). This can speed processing a bit.

  The supported variables include:

  `!LIST` | return comma delimited list of `request-number transaction-tid request-tid`, For example:`251C 12 26,353A 15 23`
  `!LISTALL` | Return a crlf delimited list of: `clientIP,own_id, transaction_daemon_id,socket,starttime,host_nickname,transaction_tid,transaction_num,request_num,selector`
  `CLIENT` | the client's IP address
  `OWN` | the own_id
  `TRAN` | the transaction's daemon_id
  `NTH` | the transaction number (which will be the same for several requests delivered over a single maintained-connection)
  `SOCK` | the TCP/IP socket
  `HOST` | host nickname
  `REQ` | the request number, in `nnnAA` format
  `SEL` | selector
  `START` | starttime (date & second)
  `PARENTID` | the thread-id of this request's "parent" (the thread-id of the transaction daemon that is handling this request)

  Note that these variables all refer to either the current request, or to the request pointed to be `usetid`.
  Also note that these are "abbreviation matches". For example, CLIENTADDR is the same as CLIENT.

  Example:

  - `parse value sre_request_info('CLIENT SOCK START ') with aclient ',' asock ',' started_at`

    Notes:

    - If `usetid` is not specified, look up info from the current request. This assumes that sre_request_info is called as part of "request processing", and NOT as part of a non-request related daemon.
      Otherwise, it must be the thread-id of a currently-active request daemon (not the thread-id of a transaction daemon, and not a daemon_id).
    - You can specify multiple variables names (in a space delimited list) -- a comma (",") delimited list of values will be returned (in the order specified).

SRE_REPLACESTRG: Replaces substrings in a string
  Replace one, or all, substrings in a string with a new substring.

  `Syntax:`
  `newstring=sre_replacestrg(astring,target,putme,type,exact)`
  where:

  `astring:` | the string to change
  `target:` | the substring to replace
  `putme:` | the substring to use as a replacement
  `type:` | `not specified` : replace first occurence of target `BACKWARD` : replace last occurence of target `ALL` : replace all occurences of target
  `exact:` | if 1, then do not capitalize during search (exact match only)

  `newstring` will be astring with occurences of target replaced by the putme

  Example:

              nustg=sre_replacestrg('This is too big ','too','very')
                   yields: 'This is very big '
              nustg=sre_replacestrg('This is also small, also ','also')
                   yields: 'This is small, also '
              nustg=sre_replacestrg('This is also small, also ','also',,'ALL')
                   yields: 'This is small, '
              nustg=sre_replacestrg('Is Also small, also','also',',maybe','ALL',1)
                   yields: 'Is Also small, maybe'

  #### Notes

  - If putme is not specified, then simply remove occurences of target
  - In contrast with SRE_REPLACEWILD, sre_replacestrg does not recognize wildcards.

SRE_REPLACEWILD:
  SRE_REPLACEWILD checks if the non-wildcarded portion of "template" matches the "needle". If so, copy the portions of the needle "covered" by wildcards in the template to the corresponding wildcarded portions of the "replacement". Note that the non-wildcarded portions of the replacement do NOT have to match the needle or template!

  This permits quite extensive transformations of the needle.

  `Syntax:`
  `new_string=SRE_REPLACEWILD(needle,template,replacement)`
  where:

  `needle:` | the string to examine. It should not contain any * (wildcard) characters
  `template:` | compare needle to this string. `template` usually contains one or more * (wildcard) characters
  `replacement:` | substitute portions of `needle`, that are wildcard matches to `template`, into the corresponding wildcarded portions of `replacement` If replacement is not specified, set `replacement=template`

  `new_string` will equal:
  - ' ' = no match (the template was NOT a match to the needle)
    or,
  - string_with_replacements = the "replacement", with suitable replacements.
    Note that if the needle and the template are exact matches, then return the replacement as is (*'s and all)

  Examples:

                     needle =  /proj1/mine/joe.htm
                   template =  /proj1/*
                replacement =  /work2/project8/ver1/*
                 would yield:  /work2/project8/ver1/mine/joe.htm

                  needle=   /proj1/eek/mine/joe.htm
                 template=  /proj1/*/joe.htm
              replacement=  /work2/project/*/joe.htm
              would yield:  /work2/project/eek/mine/joe.htm

  #### Note

  - In contrast with SRE_REPLACESTRG, sre_replacewild does not replace all target substrings with replacement substrings.

SRE_SERVER: return descriptive name of the server software
  SRE_SERVER will return a short descriptive name of the server. In particular, it will return the value of either the SERVER_SOFTWARE, SERVER_SOFTWARE_SHORT, or FILTER_VERSION parameters (that are set in SRE2003.CFG).
  `Syntax:
  sname=SRE_server(which)`

  where `which` is optional, and should be one of:

  - N= The value of the SERVER_SOFTWARE parameter. This is the default.
  - S or H= The value of the SERVER_SOFTWARE_SHORT parameter.
  - F= The value of the FILTER_VERSION parameter
  - NF, SF= The concatenation of a pair of these parameters

SRE_SAY: Write message to bottom of status screen
  Write to the bottom of the SRE2003 status screen. The message will also be written to the PMPRINTF window.

  In general, we recommend using SRE_WRITE_MESSAGE instead of SRE_SAY.

  Example:
  `call sre_say("this is my message to you, rudy. ")`

SRE_SERVERNAME: return the domain name of the server
  SRE_SERVERNAME will return the servername. This may be a host specific servername.
  `Syntax:
  sname=SRE_servername()
  sname=SRE_servername('default')`

  If `'default'` is specified, then the "canonical" (default) servername for this computer is returned: either as determined from TCP/IP calls, or as set in the SERVERNAME_USE configuration parameter.

  For what TCP/IP reports as the servername, check (using SRE_VALUE) the SRESYS variable `SERVERNAME_CANONICAL`

SRE_SHUTDOWN:
  Tell SRE2003 to shutdown, or see if a shutdown has been signalled (say, by another process).

  `Syntax:`

              call sre_shutdown(1)   -- tell SRE2003 to shutdown
              isdown=sre_shutdown()   - returns 1 if "shutdown" has been signalled,
                                        0 otherwise

  On SHUTDOWN, SRE2003 will stop accepting new connections, and will give current connections up to 90 seconds to finish.

SRE_TEMPFILE:
  Returns a name for use as a temporary file, said name being (by default) in the SRE2003 temporary directory.
  SRE_TEMPFILE can also delete a "junk" temporary file that may already exist and that has a suggested temp file name.

  `Syntax:`
  There are two modes: thread-specific file name mode, and random file name mode

  - Thread-specific (recommended for creating short-life temporary files)
    `tempfile_name=sre_tempfile(str1,str2,tempdir,del_opt)`
  - Random (recommended for creating archive and backup files)
    `tempfile_name=sre_tempfile(qname,harsh,tempdir)`

  Parameters usage:

  - Thread-specific mode -- all of the arguments are optional

    `str1` | a ?, or a unique identifier (unique to the process). It is used to form the first part (left of the .) of the tempfile name. If ?, a temporary filename will be randomly generated If not specified, the current process id is used Otherwise, `str1` is used
    `str2` | a "unique to thread" id. If not specified, the current thread id is used. It is used to form the second part (right of the .) of the tempfile name.
    `tempdir` | directory where temporary file will reside. If not specified, use the SRE2003 TEMP directory.
    `delopt` |

  - 0 or not specified: delete existing temp file.
    If undeleteable, try alternate names
  - 1 : delete existing temp file.
    If undeleteable, return ' ' (do not try alternate name)
  - 2 : if file exists, try alternate names (do NOT delete)
  - 3 : if file exists, return ' '
    (do not delete, and do not try alternate names)

  - Random-name mode the 2nd and 3rd arguments are optional

    `qname` | a filename that contains at least one ?. If relative filename, it will be relative to the `tempdir` parameter (or to the SRE2003 TEMP directory, if `tempdir` is not specified). A non-existent file name that matches the pattern in `qname` will be looked for. If such a non-existent filename is found, it is returned. If there are no non-existent files matching this pattern, `harsh` determines what to do.
    `harsh` | if `harsh` is a `?` , then the oldest file matching the pattern in `qname` is deleted, and its file name is returned. Otherwise, a blank (a ' ') is returned.
    `tempdir` | directory where temporary file will reside. If not specified, use the SRE2003 TEMP directory.

  Examples:

              tname=sre_tempfile()
              tname=sre_tempfile("PX"||dospid(),dostid())
              tname=sre_tempfile('?')
              tname=sre_tempfile('?','CSH','F:\WWW\TEMP\CACHE\',3)
              tname=sre_tempfile('FOO.???','?')

SRE_TRACKIT: set and get "tracking" variables
  For more details on tracking, see Appendix 5 (of the main documentation).

  `Syntax:
  aval=sre_trackit(varname,avalue,record_id,record_name,ownid)`
  where

  `varname` | the "tracking" variable to set/get
  `value` | the value. If '', then "get" value; otherwise set the value
  `record_id` | the id of the record to read variables from. If not specified, use the current thread id.
  `record_name` | optional. Record_name if included, will be compared to the "assigned name" for this "record" -- an error is returned if there is no match.
  `ownid` | optional. You can include this "ownid" if READING tracking info from a request thread (i.e.; from a filter) Or, set to 0 to suppress reply (i.e.; on !CLEAR or a variable set)

  Notes:
  - To set "record_name", use either:
    1. `foo=sre_trackit('!NAME',assigned_id,record_name)`
    2. `foo=sre_trackit('!INIT',assigned_id,record_name)`
  - Special Varnames include:
    - `!INIT` = initialize a record (possibly with a record_name)
    - `!CLEAR` = clear all variables assigned to record
    - `*` = list variables
    - `**` = list variables and their values (crlf delimited list)
    - `!NAME` = set the "record_name" of this record
  - Multiple variable names. You can set, or read multiple variables on a single call. To do this, use a space delimited list of varnames.

    `Setting` | : if setting multiple variables, use a space delimited list of values. Thus, setting multiple variables can only be used with "1 word values"
    `Reading` | when reading multiple variables, each value will be seperated by a crlf ('0d0a'x). Thus, you read have multiple word values, but not multiple line values.

    Thus, if you want to set multiple word (or multiple line) values, you can must do it one variable at a time. Similarly, you must read multiple line values one variable at a time.
  - Special record_id
    - `*` = list all active record_ids (space delimited list)
    - `**` = list all record ids, and currently defined variables Each record & varnames-for-record are on a seperate (CRLF delimited) line. List of varnames are space delimited.
    - `***` = list all record ids, and currently defined variable and their values. Each record's variables/value pairs are in a block of lines, with each block seperated by a blank line.
      Thus, the structure is
      `record_id
      var1 = val1
      var2 = val2
      ..
      varn = valn
      record_id
      etc.
      `
  Examples: `
  - foo=sre_trackit('READHEAD','END' ,mytid,mytid,0)
  - foo=sre_trackit('VAR1 VAR2 ','125 MARS',25)
  - aval=sre_trackit('VAR10',,,,ownid)
  `

SRE_UNCHUNK:
  UnChunk a chunked message.

  `Syntax:`
  `stuff=sre_unchunk(cstuff,inct)`
  where:

  `cstuff:` | a chunked message
  `inct` | if 1, add trailers (if any are found at the end of the message) at beginning of returned value (trailers blank_line entity).
  `` |

  `stuff` will be the "unchunked" version of cstuff, with trailers possible added to the beginning.
  Note that trailers (if added) always end with a blank line.

SRE_VALUE:
  Lookup a variable in one of several "environments".

  `Syntax:`
  `avalue=sre_value(varname,value,enviro,ownid,transaction_id)`
  where:

  `varname:` | variable name to get or set
  `value:` | value to set. If empty, then lookup value
  `enviro:` | where to get value from. There are six environments: `OS2, SRESYS, SRE, GLOBALS, SRELARGE, SREBEST,` and `REQ`
  `OS2` | from the os/2 environment. In this case sre_value is just like the VALUE function
  `SRESYS` | SRE2003 "system" variables. These are set when SRE2003 is started. In general, they are not meant to be changed "on the fly".
  - `SRE` | The default. A general sre variable. These are semi-permanent SRE variables --once set, they can be read by later transactions. They can also be read quickly. Their values can not be over 200 characters long, Their values MUST NOT contain non-text characters. Value setting and reading are not serialized. Thus, SRE variables should be set by just one daemon, but they can be read by many simultaneously running daemons. SRE2003 reserves the following SRE variables for internal use: `
    TRAN_INFO_CT, REQ_INFO_CT
    CLIENTNAME_CACHE, HOSTNAME_CACHE
    several versions of REQ_nn_INFO (where nn are integer "thread ids")
    CT_varname (where varname is one of: BYTESREADTOTAL BYTESSENTTOTAL TRANSACTIONS REQUESTS LIMITS ERRORS BROKEN CACHEHITS)
    EVENT_varname (where varname is one of: LASTACCEPT LASTIDLE LASTRESET LASTADDRESS PEAKCLIENTS )
  `
  `GLOBALS` | Very similar to `sre` variables. The only difference is that the `GLOBALS` environment is isolated from the `SRE` environment; when using `GLOBALS` one does not have to worry about accidentally changing internal SRE2003 variables. Hence ... there are no reserved global variables. GLOBALS is well suited for use by casual programmers (such as script writers)
  `SRELARGE` | A general sre variable. These are semi-permanent SRE variables --once set, they can be read by later transactions. Their values do NOT have a size or contents restriction (they do NOT have to contain only text characters). However, they are not as quickly retrieved as SRE variables Value setting and reading ARE serialized. Thus, SRELARGE variables can be both set and read by several simultaneously executing daemons. As of this implementation, they are stored using the SRE_VAR daemon
  `SREBEST` | A general sre variable. Use either SRE or SRELARGE, depending on the length and contents of the value. Basically, if the length is less then 132 characters, and all the characters are text, then store the value using the SRE environment. Otherwise, store the value using the SRELARGE environment.
  `REQ` | transient, request specific variables. These are removed after a request is completed. Hence: Their values can be large, and have no contents restriction As of this implementation, they are stored using the "transaction daemon" that services the request
  `ownid` | Optional. The "own id", used for daemon communication. This is optional; if not provided, an "own id" will be created
  `transaction_id:` | only use if enviro=REQ. If specified, then this is the daemon_id of the transaction for which you want request specific info (note that transaction daemons launch request daemons in a sequential fashion; a transaction is responsible for one request at a time, but it may be responsible for several sequential requests over the same connection) If not specified, then use the transaction associated with the current request -- this REQUIRES that sre_value be called from a procedure running under a request daemon (that is, be called by the filter or a script launched by a filter, but not by a "support" daemon).

  Examples:

              vv=sre_value('DPATH',,'OS2')
              vv2=sre_value('TEMP_DIR',,'SRESYS')
              vv3=sre_value('SMALL_VAR_1','this is a small var ','SRE')
              vv4=sre_value('FILE_X',charin('C:\CONFIG.SYS',1,1000),'SRELARGE')
              vv5=sre_value('REQ_Z','request is running ','REQ')
              vv6=sre_value('ADDON_2_V10',,'GLOBALS')
              vv7=sre_value('RECENT_USERS',,'SREBEST')

  Note: OWNID and TRANSACTION_ID are ignored when reading or writing to the OS2, SRE, and SRESYS "environments".

SRE_WRITE_ERROR
  Write an error message (up to 2 lines, 70 characters per line).
  `Syntax: astat=sre_write_error(error_message,nofile,doprint)`
  Where:
  - `error_message`: the error message
  - `nofile`:Optional. If 1, then do not write this message to the SRE2003 Error log.
  - `doprint`::Optional. If 1, then write error message to the PMPRINTF window

  - `astat` = a 1 is always returned

  Examples:`
  call sre_write_error('Foo1: got a BAR error')
  call sre_write_error('This silly error message will also be pmprintfed',,1)
  `

SRE_WRITE_MESSAGE
  Write a text message string to the message-area of the SRE2003 status screen. The string can be up to 140 characters long; characters from 71 to 140 will be wrapped onto a second line. Characters beyond the 140th are discarded.

  Syntax: `foo=sre_write_message(messge_string,toaudit)`

  Where:

  - `message`: a text string.
  - `toaudit`: write `message` to the AUDIT log file.
    0 = do not write to audit log file
    1 = write to audit log file
    Otherwise = if the SRE2003 AUDIT_ITEMS parameter contains a `MESSAGE` option, then write to audit log file

  Examples:
  `call sre_write_message(' Hello cruel world? ')
  call sre_write_message(' Not ready to quit ',1)`

SRE_WILD_MATCH:
  Wild card match, with comparison against prior wild card match

  `Syntax:`
  `resu=SRE_WILD_MATCH(needle,haystack,oldresult,suppress_noslash)`
  where:

  `needle:` | what to look for
  `haystack:` | what to compare it to. Haystack may contain numerous * wildcard characters
  `oldresult:` | prior return from sre_wild_match; or ' ' (if no prior match was made)
  `suppress_noslash:` | if 1, suppress the "no slash" special feature (see below)

  `resu:` The returned value depends on `oldresult`...
  - `If needle is exact match to haystack:` resu will equal -1
  - `If needle does not match haystack (even with wild card checking):` resu will equal 0
  - `If needle wildcard matches haystack, and oldresult='':` returns match information.
    This match information can be used as the "oldresult" in subsequent calls to sre_wild_match.
  - `If needle wildcard matches haystack, and oldresult<>''` (oldresult is the result of a prior call to sre_wild_match),
    1. compare the current match to the "oldresult" match
    2. if current is "better", return the match result
    3. otherwise (current match is not an improvement), return 0
  Note: a "better" match has more matching characters early in the string

  Basically, -1 means "exact match", 0 means "no match" or "not better match" (if oldresu not specified, 0 always means "no match"), and everything else means "better wild card match".

  Example:

         a.1='This is *'
         a.2='This is a *'
         a.3='This is a funny * story'
         a.4='* is * '
         a.5='Th* fun*'
         a.6='This is funny *'

         say "Enter string : "
         parse pull ans
         oldresu=''; isit=0
         do mm=1 to 6
            resu=sre_wild_match(ans,a.mm,oldresu)
            if resu=-1 then do
               isit=mm
               leave
            end
            if resu=0 then iterate
            isit=mm
            oldresu=resu
         end
         if isit=0 then
             say " no match "
          else
            say " match= "a.isit

  #### SPECIAL FEATURE

  if haystack ends with a |, then no "slash" is allowed in the final wildcarded portion of the needle. That is, the portion of the needle "covered" by the final (or only, if there is just one *) in the haystack can NOT contain a / or a \. If it does, it's a NO MATCH

  For example, using a needle of: animal/cats/food.1
  The follwing haystacks yield:

               animal/*candy  --  no match
               anim*/*.1      --  match
               animal/*.1|    --  no match (* covers cats/food, which contains a /)
               anim*/food*|   --  match (final * covers ".1")
               */cats*|       --  no match (final * covers "/food.1")

Updated 4 Sept. 2002