/*****************************************************************************
/*
                                  WASD.h

Main header file for WASD VMS HTTP daemon.


VERSION HISTORY
---------------
23-OCT-2017  MGD  v11.2.0, InstanceStatus..[]
02-AUG-2015  MGD  v11.0.0  HTTP/2
10-MAR-2015  MGD  v10.4.2, CONFIG_SERVER_LOGS logical names precede fixed locale
12-MAR-2012  MGD  v10.1.1, MATCH0..8() macro improves efficiency over memcmp()
                           SAME1..4() macro abstracts the *(USHORTPTR)s, etc.
14-MAR-2011  MGD  __unaligned directive added to pointer macros in a
                    (successful) effort to avoid alignment faults
20-JUL-2009  MGD  can't believe it but some PHP script paths are
                  exceeding a SCRIPT_NAME_SIZE of 128 - bump to 256!
06-JUL-2009  MGD  v10.0.0, accomodate v10 and pre-v10 logical names
22-JUL-2004  MGD  v9.0.0, HTTP/1.1 compliance
20-DEC-2004  MGD  v8.4.0, all "#ifdef __ALPHA"s changed to "#ifndef __VAX"
                          to support compilation for IA64
15-OCT-2002  MGD  v8.1.0, base compiler messages on WATCH_MOD not DBUG
12-DEC-2000  MGD  v7.2.0, remote user size changed for X509
                          major reorg of data types, etc.
06-MAY-2000  MGD  v7.0.0, reorganise data structures
23-DEC-1999  MGD  v6.1.2, DECC v6.2 warning control
31-OCT-1999  MGD  v6.1.0, CGIplus "agents"
16-OCT-1999  MGD  v6.0.3, DEC TCP/IP v5.n compatibility definitions
10-JAN-1999  MGD  v6.0.0, proxy serving
19-SEP-1998  MGD  v5.3.0, disperse to module headers :^)
14-APR-1998  MGD  v5.0.1, XSSI extensions
07-JAN-1998  MGD  v5.0.0, HTTPd version 5 (Secure Sockets Layer, using SSLeay)
05-OCT-1997  MGD  v4.5.0, file cache
06-SEP-1997  MGD  v4.4.0, multiple server host names and ports
08-JUN-1997  MGD  v4.2.0, CGIplus
01-FEB-1997  MGD  v4.0.0, HTTPd version 4
01-AUG-1996  MGD  v3.3.0, quite a few changes since 3.0.n
01-DEC-1995  MGD  v3.0.0, HTTPd version 3
20-DEC-1994  MGD  v2.0.0, multi-threaded version
20-JUN-1994  MGD  v1.0.0, single-threaded version
*/
/*****************************************************************************/

#ifndef WASD_H_LOADED
#define WASD_H_LOADED 1

#ifdef WATCH_MOD
#  if WATCH_MOD
#     ifndef __VAX
#        if (__DECC_VER > 60000000)
#           pragma message enable (ALL)
#           pragma message disable (CVTDIFTYPES)
#           pragma message disable (EMBEDCOMMENT)
#           pragma message disable (MAYLOSEDATA)
#           pragma message disable (LONGEXTERN)
#           pragma message disable (NORETURNVAL1,NOTYPES,NONEWTYPE,NOTCONSTQUAL)
#           pragma message disable (PTRMISMATCH,PTRMISMATCH1)
#        else
#           pragma message disable (ALL)
#        endif
#     else
#        pragma message disable (ALL)
#     endif
#  else
#     pragma message disable (ALL)
#  endif
#else
#  pragma message disable (ALL)
#endif

#include <types.h>

/* VMS headers */
#include <descrip.h>
#include <rms.h>
#include <ssdef.h>
#include <stsdef.h>

/* this definition is not available in VMS versions earlier than 7.0 */
#ifndef EFN$C_ENF
#  define EFN$C_ENF 128  /* Event No Flag (no stored state) */
#endif 

/* Alpha NO MEMBER ALIGNMENT unless otherwise specified */
#ifndef __VAX
#   pragma nomember_alignment
#endif

#include "regex.h"

#ifndef VERSION_H_LOADED
#   include "version.h"
#endif

/**********/
/* macros */
/**********/

#define boolean int
#define true 1
#define false 0

/* sentinal value allowing a pointer to be set with non-pointer function */
#define NOTPTR ((void*)(-1))

/* used to indicate when an array of [2] is used as a quadword (64 bit) */
#define QUAD2 2

#define FI_LI WASD_MODULE, __LINE__

/* enable features in WASDMON that rely on v10.4.0 */
#define WASDMON_SUPPORT_1040
/* enable features in alamode (aka WASDMON) that rely on v11.0.0 */
#define ALAMODE_SUPPORT_1100
/* ...that rely on v11.2.0 */
#define ALAMODE_SUPPORT_1120
/* ...that rely on v11.3.0 */
#define ALAMODE_SUPPORT_1130

/* an error severity equivalent of the warning severity status */
#define SS$_BUFFEROVF_ERROR (SS$_BUFFEROVF & 0xfffffffe)

/* these are scattered about so better $ SEARCH *.H """?" */
#define CONFIG_WASD_ROOT           "?WASD_ROOT:[000000]\0HT_ROOT:[000000]\0"

#define CONFIG_AUTH_FILE_NAME      "?WASD_CONFIG_AUTH\0HTTPD$AUTH\0"
#define CONFIG_FILE_NAME           "?WASD_CONFIG_GLOBAL\0HTTPD$CONFIG\0"
#define CONFIG_MAP_FILE_NAME       "?WASD_CONFIG_MAP\0HTTPD$MAP\0"
#define CONFIG_MSG_FILE_NAME       "?WASD_CONFIG_MSG\0HTTPD$MSG\0"
#define CONFIG_SERVICE_FILE_NAME   "?WASD_CONFIG_SERVICE\0HTTPD$SERVICE\0"
#define CONFIG_SERVER_LOGS \
        "?WASD_SERVER_LOGS:\0HT_SERVER_LOGS:\0WASD_ROOT:[LOG_SERVER]\0"
#define CONFIG_SITELOG_FILE_NAME \
        "?WASD_SITELOG\0HTTPD$SITELOG\0"
#define DEFAULT_SITELOG_FILE_NAME \
        "?WASD_ROOT:[LOCAL]SITE.LOG\0HT_ROOT:[LOCAL]SITE.LOG\0"

#define CONFIG_SSL_CAFILE          "?WASD_SSL_CAFILE\0HTTPD$SSL_CAFILE\0"
#define CONFIG_SSL_CERT            "?WASD_SSL_CERT\0HTTPD$SSL_CERT\0"
#define CONFIG_SSL_CIPHER          "?WASD_SSL_CIPHER\0HTTPD$SSL_CIPHER\0"
#define CONFIG_SSL_KEY             "?WASD_SSL_KEY\0HTTPD$SSL_KEY\0"
#define CONFIG_SSL_PARAMS          "?WASD_SSL_PARAMS\0HTTPD$SSL_PARAMS\0"

/* allows the HTTPd to be operated with SYSPRV permanently enabled */
#define OPERATE_WITH_SYSPRV 0

#define DEFAULT_HTTP_PORT          80
#define DEFAULT_HTTPS_PORT        443
#define DEFAULT_HTTP_PROXY_PORT  8080
#define DEFAULT_LISTEN_BACKLOG      5

/* this value limits concurrent client->server connections */
#define DEFAULT_CONCURRENT_CONNECT_MAX    200
/* this value limits the number of requests concurrently processed */
#define DEFAULT_CONCURRENT_PROCESS_MAX    100

#define DEFAULT_TIMEOUT_INPUT_MINUTES       1
#define DEFAULT_TIMEOUT_OUTPUT_MINUTES     10
#define DEFAULT_TIMEOUT_NOPROGRESS_MINUTES  3
#define DEFAULT_TIMEOUT_PERSISTENT_SECONDS  0

/* if a timed-out request has not gone then close the network connection */
#define TIMEOUT_ABORT_SECONDS 20

/* limit on persistent connections (999999 effectively disables) */
#define PERSISTENT_LIMIT 999999

/* maximum consecutive failures on persistent connection before disconnect */
#define PERSISTENT_FAILURE_MAX 256

/* maximum successive failures on secure connection before exit and restart */
#define SESOLA_NET_PROBLEM_MAX 64

#define DEFAULT_DCL_CGI_HEADER_SIZE   2048
#define DEFAULT_DCL_CGIPLUSIN_SIZE    3072
#define DEFAULT_DCL_SYSCOMMAND_SIZE   4096
#define DEFAULT_DCL_SYSOUTPUT_SIZE    4096
#define DEFAULT_FILE_BUFFER_SIZE      1024
#define DEFAULT_NET_READ_BUFFER_SIZE  2048
#define DEFAULT_OUTPUT_BUFFER_SIZE    4096
#define MAX_REQUEST_HEADER           32768
#define MAX_REQUEST_FIELD_NAME_LEN     255

/* prefixes the rights identifier name used for tagging DCL script processes */
#define PROCESS_RIGHTS_ID_PREFIX "WASD_PRC_"

/* control pre-expired responses */
#define PRE_EXPIRE_ADMIN            1
#define PRE_EXPIRE_DELETE_ON_CLOSE  1
#define PRE_EXPIRE_FTP_PROXY        0
#define PRE_EXPIRE_INDEX_OF         0
#define PRE_EXPIRE_MAPPING_RULES    0
#define PRE_EXPIRE_PUT              1
#define PRE_EXPIRE_SSI              0
#define PRE_EXPIRE_UPD              1
#define PRE_EXPIRE_UPD_TREE_OF      1
#define PRE_EXPIRE_WATCH            1
#define PRE_EXPIRE_WEBDAV           1

/* versions of the HTTP protocol */
#define HTTP_VERSION_NOT_SET   0
#define HTTP_VERSION_0_9       9
#define HTTP_VERSION_1_0      10
#define HTTP_VERSION_1_1      11
#define HTTP_VERSION_2        20
#define HTTP_VERSION_UNKNOWN  -1

/* used when data differentiated by protocol (e.g. accounting) */
#define HTTP12 0   /* all requests */
#define HTTP1  1   /* HTTP/1.n requests */
#define HTTP2  2   /* HTTP/2 requests */
#define HTTPN  3   /* number of elements in array */

/* constants used to identify HTTP methods (MUST be a BITMAP for AUTH*.C) */
#define HTTP_METHOD_CONNECT           0x00000001
#define HTTP_METHOD_DELETE            0x00000002
#define HTTP_METHOD_GET               0x00000004
#define HTTP_METHOD_HEAD              0x00000008
#define HTTP_METHOD_POST              0x00000010
#define HTTP_METHOD_PUT               0x00000020
#define HTTP_METHOD_TRACE             0x00000040
#define HTTP_METHOD_OPTIONS           0x00000080
#define HTTP_METHOD_WEBDAV_COPY       0x00000100
#define HTTP_METHOD_WEBDAV_LOCK       0x00000200
#define HTTP_METHOD_WEBDAV_MKCOL      0x00000400
#define HTTP_METHOD_WEBDAV_MOVE       0x00000800
#define HTTP_METHOD_WEBDAV_PROPFIND   0x00001000
#define HTTP_METHOD_WEBDAV_PROPPATCH  0x00002000
#define HTTP_METHOD_WEBDAV_UNLOCK     0x00004000
#define HTTP_METHOD_SHARE_SSH         0x00100000
#define HTTP_METHOD_EXTENSION         0x10000000
#define HTTP_METHOD_UNSUPPORTED       0x80000000

#define  HTTP_READ_METHODS   (HTTP_METHOD_GET | \
                              HTTP_METHOD_HEAD | \
                              HTTP_METHOD_OPTIONS)

#define  HTTP_WRITE_METHODS  (HTTP_METHOD_CONNECT | \
                              HTTP_METHOD_DELETE | \
                              HTTP_METHOD_POST | \
                              HTTP_METHOD_PUT)

#define HTTP_WEBDAV_READ_METHODS  (HTTP_METHOD_WEBDAV_PROPFIND)

#define HTTP_WEBDAV_WRITE_METHODS  (HTTP_METHOD_WEBDAV_COPY | \
                                    HTTP_METHOD_WEBDAV_LOCK | \
                                    HTTP_METHOD_WEBDAV_MOVE | \
                                    HTTP_METHOD_WEBDAV_MKCOL | \
                                    HTTP_METHOD_WEBDAV_PROPPATCH | \
                                    HTTP_METHOD_WEBDAV_UNLOCK)
                                   
/* constants for controlling logging */
#define LOGGING_BEGIN     1
#define LOGGING_CLOSE     2
#define LOGGING_END       3
#define LOGGING_ENTRY     4
#define LOGGING_FLUSH     5
#define LOGGING_OPEN      6
#define LOGGING_SHUT      7
#define LOGGING_TIMESTAMP 8

/* constants for OPCOM messages */
#define OPCOM_HTTPD          0x01
#define OPCOM_CONTROL        0x02
#define OPCOM_ADMIN          0x04
#define OPCOM_AUTHORIZATION  0x08
#define OPCOM_PROXY_MAINT    0x10

/* constants used by HTTPd supervisor timer */
#define TIMER_INPUT             1
#define TIMER_THROTTLE          2
#define TIMER_OUTPUT            3
#define TIMER_NOPROGRESS        4
#define TIMER_PERSISTENT        5
#define TIMER_TERMINATE         6

/* constants used to indicate the nature of the timeout */
#define TIMEOUT_NONE            0
#define TIMEOUT_INPUT           1
#define TIMEOUT_THROTTLE        2
#define TIMEOUT_OUTPUT          3
#define TIMEOUT_NOPROGRESS      4
#define TIMEOUT_PERSISTENT      5
#define TIMEOUT_TERMINATE       6

/* constants used by the description module */
#define DESCRIPTION_ALL         0x01
#define DESCRIPTION_TEXT_PLAIN  0x02
#define DESCRIPTION_TEXT_HTML   0x04
/* this is returned in the first character the file type contains none */
#define DESCRIPTION_IMPOSSIBLE  0xff

/* default directory listing layout */
#define DEFAULT_DIR_LAYOUT "I__L__R__S:b__D"

/* WASD_CONFIG_GLOBAL directive obsolete at v11.5.0 */
#define ADMIN_BODY_TAG  "<body link=\"#0000cc\" vlink=\"#0000cc\">"
#define REPORT_BODY_TAG "<body link=\"#0000cc\" vlink=\"#0000cc\">"

/* "http:" or "https:" service and request */
#define SCHEME_HTTP     1
#define SCHEME_HTTPS    2

/* if true, stops HTTPd server account with SYSPRV PUT(etc)ing - DANGEROUS */
#define PUT_DISALLOW_SYSPRV 0

#define CONFIG_HOME_PAGES_MAX      16
#define CONFIG_README_FILES_MAX    16
#define CONFIG_SCRIPT_PROCTOR_MAX  16
#define CONFIG_SCRIPT_RUNTIME_MAX  16
#define CONFIG_REVALIDATE_MINUTES_MAX  1440

#define CONFIG_SERVER_SIGNATURE_OFF    0
#define CONFIG_SERVER_SIGNATURE_ON     1
#define CONFIG_SERVER_SIGNATURE_EMAIL  2

#define SCRIPT_NAME_SIZE   256
#define METHOD_NAME_SIZE    32

#define CONFIG_DEFAULT_DIR_BODY_TAG "<body>"
#define CONFIG_DEFAULT_ADMIN_BODY_TAG \
        "<body bgcolor=\"#ffffff\" link=\"#0000cc\" vlink=\"#0000cc\">"
#define CONFIG_DEFAULT_REPORT_BODY_TAG \
        "<body bgcolor=\"#ffffff\" link=\"#0000cc\" vlink=\"#0000cc\">"

/* maximum Kbytes (1024) that can be in a body to be POSTed or PUTted */
#define PUT_DEFAULT_KBYTES_MAX 250
/* number of versions retained for files POSTed or PUTed */
#define PUT_DEFAULT_VERSION_LIMIT 3
/* W:RE,G:RE,O:RWED,S:RWED */
#define PUT_DEFAULT_FILE_PROTECTION 0xaa00
/* W:RE,G:RE,O:RWED,S:RWED */
#define WEBDAV_DEFAULT_FILE_PROTECTION 0xaa00

/* number of times a request can internally redirect */
#define REQUEST_REDIRECTION_MAX 5

/* number of times a request can be redacted */
#define REQUEST_REDACT_MAX 5

/* number of possible status codes groups multiplied by status coded */
#define RESPONSE_STATUS_CODE_MAX 6*30

/* number of pointers available for adding server-generated cookies */
#define RESPONSE_COOKIE_MAX 20

/* WASD tag generated from file; hex digits: 12 for FID, 16 for RDT */
#define ENTITY_TAG_MAX 28

/* generated by script and stored in cache structure */
#define CACHE_ENTITY_MAX 63

/* internal "scripts" */
#define ADMIN_SCRIPT_ECHO   "/echo"
#define ADMIN_SCRIPT_HISS   "/hiss"
#define ADMIN_SCRIPT_HISS_MAX_BYTES 1048176
#define ADMIN_SCRIPT_STREAM "/stream"
#define ADMIN_SCRIPT_TREE   "/tree"
#define ADMIN_SCRIPT_UPD    "/upd"
#define ADMIN_SCRIPT_WHERE  "/where"
#define ADMIN_SCRIPT_XRAY   "/xray"

/* default instance number when in demo mode */
#define DEMO_INSTANCE_GROUP_NUMBER 0

/* regular expression processing */
#define REGEX_CHAR '^'
/* number of structures for holding match offsets */
#define REGEX_PMATCH_MAX 10
/* compile flags, case-insensitive extended GREP, anchors match newlines */
#define REGEX_C_FLAGS (REG_EXTENDED | REG_ICASE | REG_NEWLINE)
/* execution flags */
#define REGEX_E_FLAGS (0)

/* for creating network mode detached processes */
#define NETWORK_MODE_LOG_NAME "NET$WASD.LOG"
#define LGI$M_NET_PROXY  1
#define UAF$S_USERNAME  12
#define UAF$S_PASSWORD  32
#define UAF$S_ACCOUNT    8

/* used to highlight alternate rows in some admin reports */
#define ADMIN_REPORT_ALTHI "class=\"althi\" bgcolor=\"#eeeeee\""

#define WASD_DOCTYPE "<!DOCTYPE html>\n"

/*********************/
/* functional macros */
/*********************/

/* mainly to allow easy use of the __unaligned directive */
#define UINTPTR __unaligned uint*
#define ULONGPTR __unaligned ulong*
#define USHORTPTR __unaligned ushort*
#define INT64PTR __unaligned __int64*

#define VMSok(x) ((x) & STS$M_SUCCESS)
#define VMSnok(x) (!((x) & STS$M_SUCCESS))

/* is it linear-white-space? (avoids the call overhead of an isspace()) */
#define ISLWS(c) (c == ' ' || c == '\t')
#define NOTLWS(c) (c != ' ' && c != '\t')

/* is it a control character? */
#define ISCTL(c) (((uchar)c >= 0 && (uchar)c <= 31) || (uchar)c == 127)
#define NOTCTL(c) (!(((uchar)c >= 0 && (uchar)c <= 31) || (uchar)c == 127))

/* end of CR or LF terminated line? */
#define ISCRLF(ptr) (c == '\r' || c == '\n')
#define NOTCRLF(c) (c != '\r' && c != '\n')

/* end of CR or LF terminated line? */
#define ISEOL(c) (c == '\r' || c == '\n' || !c)
#define NOTEOL(c) (c != '\r' && c != '\n' && c)

/* is a separator character? */
#define ISSEP(c) (!NOTSEP(c))
#define NOTSEP(c) ((c >= 'a' && c <= 'z') || \
                   (c >= 'A' && c <= 'Z') || \
                   (c >= '0' && c <= '9') || \
                    c == '-' || c == '_' || c == '%' || c == '+' || \
                    c == '\'' || c == '&' || c == '*' || c == '.' || \
                    c == '!' || c == '$' || c == '^' || c == '#' || \
                    c == '`' || c == '|' || c == '~' || (uchar)c > 127)

/* is either of these quotation marks */
#define ISQUOT(c) (c == '\"' || c == '\'')
#define NOTQUOT(c) (c != '\"' && c != '\'')

/* WASD uses toupper() so much let's have an inline one of our own */
#define TOUP(c) (ToUpperCase[(uchar)c])
/* likewise (arrays found in SUPPORT.C) */
#define TOLO(c) (ToLowerCase[(uchar)c])

#ifndef USE_INT64
#ifdef __VAX
#define USE_INT64 0
#else
#define USE_INT64 1
#endif
#endif

/* demonstrated to be an order of magnitude faster than memcmp() */

#define MATCH0(ptr1,ptr2,len) (memcmp(ptr1,ptr2,len) == 0)
#define MATCH1(ptr1,ptr2) (*(char*)(ptr1) == *(char*)(ptr2))
#define MATCH2(ptr1,ptr2) (*(USHORTPTR)(ptr1) == *(USHORTPTR)(ptr2))
#define MATCH3(ptr1,ptr2) ((*(ULONGPTR)(ptr1) & 0x00ffffff) == \
                           (*(ULONGPTR)(ptr2) & 0x00ffffff))
#define MATCH4(ptr1,ptr2) (*(ULONGPTR)(ptr1) == *(ULONGPTR)(ptr2))

#if USE_INT64

#define MATCH5(ptr1,ptr2) ((*(INT64PTR)(ptr1) & 0x000000ffffffffff) == \
                           (*(INT64PTR)(ptr2) & 0x000000ffffffffff))
#define MATCH6(ptr1,ptr2) ((*(INT64PTR)(ptr1) & 0x0000ffffffffffff) == \
                           (*(INT64PTR)(ptr2) & 0x0000ffffffffffff))
#define MATCH7(ptr1,ptr2) ((*(INT64PTR)(ptr1) & 0x00ffffffffffffff) == \
                           (*(INT64PTR)(ptr2) & 0x00ffffffffffffff))
#define MATCH8(ptr1,ptr2) (*(INT64PTR)(ptr1) == *(INT64PTR)(ptr2))

#else

#define MATCH5(ptr1,ptr2) ((((ULONGPTR)(ptr1))[0] == ((ULONGPTR)(ptr2))[0]) && \
                           ((((ULONGPTR)(ptr1))[1] & 0x000000ff) == \
                            (((ULONGPTR)(ptr2))[1] & 0x000000ff)))
#define MATCH6(ptr1,ptr2) ((((ULONGPTR)(ptr1))[0] == ((ULONGPTR)(ptr2))[0]) && \
                           ((((ULONGPTR)(ptr1))[1] & 0x0000ffff) == \
                            (((ULONGPTR)(ptr2))[1] & 0x0000ffff)))
#define MATCH7(ptr1,ptr2) ((((ULONGPTR)(ptr1))[0] == ((ULONGPTR)(ptr2))[0]) && \
                           ((((ULONGPTR)(ptr1))[1] & 0x00ffffff) == \
                            (((ULONGPTR)(ptr2))[1] & 0x00ffffff)))
#define MATCH8(ptr1,ptr2) ((((ULONGPTR)(ptr1))[0] == ((ULONGPTR)(ptr2))[0]) && \
                           (((ULONGPTR)(ptr1))[1] == ((ULONGPTR)(ptr2))[1]))

#endif

#define MATCH9(ptr1,ptr2)  (MATCH8(ptr1,ptr2) && \
                            MATCH1(((char*)ptr1)+8,((char*)ptr2)+8))
#define MATCH10(ptr1,ptr2) (MATCH8(ptr1,ptr2) && \
                            MATCH2(((char*)ptr1)+8,((char*)ptr2)+8))
#define MATCH11(ptr1,ptr2) (MATCH8(ptr1,ptr2) && \
                            MATCH3(((char*)ptr1)+8,((char*)ptr2)+8))
#define MATCH12(ptr1,ptr2) (MATCH8(ptr1,ptr2) && \
                            MATCH4(((char*)ptr1)+8,((char*)ptr2)+8))
#define MATCH13(ptr1,ptr2) (MATCH8(ptr1,ptr2) && \
                            MATCH5(((char*)ptr1)+8,((char*)ptr2)+8))
#define MATCH14(ptr1,ptr2) (MATCH8(ptr1,ptr2) && \
                            MATCH6(((char*)ptr1)+8,((char*)ptr2)+8))
#define MATCH15(ptr1,ptr2) (MATCH8(ptr1,ptr2) && \
                            MATCH7(((char*)ptr1)+8,((char*)ptr2)+8))
#define MATCH16(ptr1,ptr2) (MATCH8(ptr1,ptr2) && \
                            MATCH8(((char*)ptr1)+8,((char*)ptr2)+8))
#define MATCH17(ptr1,ptr2) (MATCH8(ptr1,ptr2) && \
                            MATCH8(((char*)ptr1)+8,((char*)ptr2)+8) && \
                            MATCH1(((char*)ptr1)+16,((char*)ptr2)+16))
#define MATCH18(ptr1,ptr2) (MATCH8(ptr1,ptr2) && \
                            MATCH8(((char*)ptr1)+8,((char*)ptr2)+8) && \
                            MATCH2(((char*)ptr1)+16,((char*)ptr2)+16))
#define MATCH19(ptr1,ptr2) (MATCH8(ptr1,ptr2) && \
                            MATCH8(((char*)ptr1)+8,((char*)ptr2)+8) && \
                            MATCH3(((char*)ptr1)+16,((char*)ptr2)+16))
#define MATCH20(ptr1,ptr2) (MATCH8(ptr1,ptr2) && \
                            MATCH8(((char*)ptr1)+8,((char*)ptr2)+8) && \
                            MATCH4(((char*)ptr1)+16,((char*)ptr2)+16))

/* demonstrated to be 50% faster than comparable MATCH() */

#define SAME1(ptr,val) (*(char*)(ptr) == val)
#define SAME2(ptr,val) (*(USHORTPTR)(ptr) == val)
#define SAME3(ptr,val) ((*(ULONGPTR)(ptr) & 0x00ffffff) == val)
#define SAME4(ptr,val) (*(ULONGPTR)(ptr) == val)
#define SET2(ptr,val)  (*(USHORTPTR)(ptr) = val)
#define SET4(ptr,val)  (*(ULONGPTR)(ptr) = val)

/* these quad macros are designed for storage assigned as long[2] */

/* is the 64 bit number in 'a' the same as in 'b' */
#if USE_INT64
#define QUAD_EQUAL_QUAD(a,b) (*(INT64PTR)a == *(INT64PTR)b)
#else
#define QUAD_EQUAL_QUAD(a,b) (((ULONGPTR)a)[0] == \
                              ((ULONGPTR)b)[0] && \
                              ((ULONGPTR)a)[1] == \
                              ((ULONGPTR)b)[1])
#endif

/* is the 64 bit number in 'a' larger than that in 'b'? boolean result in c */
#if USE_INT64
#define QUAD_GT_QUAD(a,b,c) { c = (*(INT64PTR)a > *(INT64PTR)b); }
#else
/* do it by checking the sign of a subtraction */
#define QUAD_GT_QUAD(a,b,c) { \
   ulong  q[2]; \
   lib$subx (b, a, q, 0); \
   c = (q[1] & 0x80000000) != 0; \
}
#endif

/* is the 64 bit number zero? */
#if USE_INT64
#define QUAD_ZERO(a) (!*(INT64PTR)a)
#else
#define QUAD_ZERO(a) (!((ULONGPTR)a)[0] && !((ULONGPTR)a)[1])
#endif

/* is the 64 bit number NOT zero? */
#if USE_INT64
#define QUAD_NOT_ZERO(a) (*(INT64PTR)a)
#else
#define QUAD_NOT_ZERO(a) (((ULONGPTR)a)[0] || ((ULONGPTR)a)[1])
#endif

/* is the (signed) 64 bit number less than zero? */
#if USE_INT64
#define QUAD_LT_ZERO(a) (*(INT64PTR)a < 0)
#else
#define QUAD_LT_ZERO(a) (((ULONGPTR)a)[1] & 0x8000000)
#endif

/* put the 64 bit number in 'a' into 'b' */
#if USE_INT64
#define PUT_QUAD_QUAD(a,b) { *(INT64PTR)b = *(INT64PTR)a; }
#else
#define PUT_QUAD_QUAD(a,b) { ((ULONGPTR)b)[0] = ((ULONGPTR)a)[0]; \
                             ((ULONGPTR)b)[1] = ((ULONGPTR)a)[1]; }
#endif

/* put the 32 bit number in 'a' into 'b' */
#if USE_INT64
#define PUT_LONG_QUAD(a,b) { *(INT64PTR)b = (__int32)a; }
#else
#define PUT_LONG_QUAD(a,b) { ((ULONGPTR)b)[0] = a; ((ULONGPTR)b)[1] = 0; }
#endif

/* put the least significant 32 bits in 'a' into 32 bit 'b' */
#if USE_INT64
#define PUT_QUAD_LONG(a,b) { (__int32)b = *(INT64PTR)a; }
#else
#define PUT_QUAD_LONG(a,b) { b = ((ULONGPTR)a)[0]; }
#endif

/* zero the 64 bit number at 'a' */
#if USE_INT64
#define PUT_ZERO_QUAD(a) { *(INT64PTR)a = 0; }
#else
#define PUT_ZERO_QUAD(a) { ((ULONGPTR)a)[0] = ((ULONGPTR)a)[1] = 0; }
#endif

/* NOTE: adds and substracts CANNOT be used with pointers to quads! */

/* adds the 64 bit number at 'a' to the number at 'b' */
#if USE_INT64
#define ADD_QUAD_QUAD(a,b) *(INT64PTR)b = *(INT64PTR)b + *(INT64PTR)a;
#else
#define ADD_QUAD_QUAD(a,b) lib$addx(a,b,b,0);
#endif

/* adds the 64 bit number at 'a' to the number at 'b' result in 'c' */
#if USE_INT64
#define PLUS_QUAD_QUAD(a,b,c) *(INT64PTR)c = *(INT64PTR)b + *(INT64PTR)a;
#else
#define PLUS_QUAD_QUAD(a,b,c) lib$addx(a,b,c,0);
#endif

/* adds the 32 bit number in 'a' to the number in 'b' */
#if USE_INT64
#define ADD_LONG_QUAD(a,b) *(INT64PTR)b = *(INT64PTR)b + (__int32)a;
#else
#define ADD_LONG_QUAD(a,b) { \
   ulong q[2] = { a, 0 }; \
   lib$addx(&q,b,b,0); \
}
#endif

/* subtracts the 64 bit number at 'a' from the number at 'b' */
#if USE_INT64
#define SUB_QUAD_QUAD(a,b) *(INT64PTR)b = *(INT64PTR)b - *(INT64PTR)a;
#else
#define SUB_QUAD_QUAD(a,b) lib$subx(b,a,b,0);
#endif

/* is the 64 bit number at 'a' less than the number at 'b' */
#if USE_INT64
#define QUAD_LT_QUAD(a,b) (*(INT64PTR)a < *(INT64PTR)b)
#else
#define QUAD_LT_QUAD(a,b) QuadLtQuad(a,b)
#endif

/* subtracts the 32 bit number in 'a' from the number in 'b' */
#if USE_INT64
#define SUB_LONG_QUAD(a,b) *(INT64PTR)b = *(INT64PTR)b - (__int32)a;
#else
#define SUB_LONG_QUAD(a,b) { \
   ulong q[2] = { a, 0 }; \
   lib$subx(b,q,b,0); \
}
#endif

/* subtracts the 64 bit number at 'a' from the number at 'b' stores in 'c'*/
#if USE_INT64
#define MINUS_QUAD_QUAD(a,b,c) (*(INT64PTR)c = *(INT64PTR)b - *(INT64PTR)a)
#else
#define MINUS_QUAD_QUAD(a,b,c) lib$subx(b,a,c,0)
#endif

/* multiplies the 32 bit "quadword" in 'b' by the 32 bit number in 'a' */
#if USE_INT64 && !WATCH_MOD /* exercise the emul() when developing! */
#define MUL_LONG_QUAD(a,b) *(INT64PTR)b = *(INT64PTR)b * (__int32)a;
#else
#define MUL_LONG_QUAD(a,b) { \
   int  status; \
   ulong  EmulCand = (((ULONGPTR)b)[0]), \
          EmulPlier = a, \
          EmulAddend = 0; \
   if (((ULONGPTR)b)[1]) ErrorNoticed (NULL, SS$_BUGCHECK, NULL, FI_LI); \
   status = lib$emul (&EmulPlier, &EmulCand, &EmulAddend, b); \
   if (VMSnok (status)) ErrorNoticed (NULL, status, NULL, FI_LI); \
} 
#endif

/* make a float from the pointed-to quadword */
#if USE_INT64
#define FLOAT_FROM_QUAD(a) ((float)*(INT64PTR)a)
#else
#define FLOAT_FROM_QUAD(a) ((float)(((ULONGPTR)a)[0]) + \
                            ((float)(((ULONGPTR)a)[1])*4294967296.0))
#endif

/* the smallest delta time */
#if USE_INT64
#define ZERO_DELTA_TIME(a) { *(INT64PTR)a = 0xffffffffffffffff; }
#else
#define ZERO_DELTA_TIME(a) { ((ULONGPTR)a)[0] = ((ULONGPTR)a)[1] = 0xffffffff; }
#endif

/* is it the smallest delta time? */
#if USE_INT64
#define IS_ZERO_DELTA_TIME(a) (*(INT64PTR)a == 0xffffffffffffffff)
#else
#define IS_ZERO_DELTA_TIME(a) (((ULONGPTR)a)[0] == 0xffffffff && \
                               ((ULONGPTR)a)[1] == 0xffffffff)
#endif

/************/
/* typedefs */
/************/

typedef int BOOL;
typedef (*FAB_AST) (struct FAB*);
typedef (*GENERAL_AST) (ulong);
typedef (*VOID_AST) (void*);
typedef (*PROXY_AST) (struct ProxyTaskStruct*);
typedef (*REQUEST_AST) (struct RequestStruct*);
typedef (*CALL_BACK) (ulong);

typedef struct RequestPathSetStruct REQUEST_PATHSET;
typedef struct RequestStruct REQUEST_STRUCT;

/*******************/
/* data structures */
/*******************/

typedef struct ItemList2Struct VMS_ITEM_LIST2;
struct ItemList2Struct
{
   ushort  buf_len;
   ushort  item;
   void  *buf_addr;
};

#ifndef __VAX
#pragma required_pointer_size save 
#pragma required_pointer_size 64 
typedef struct ItemList64a VMS_ITEM_LIST_64A;
struct ItemList64a
{
   ushort  mbo;
   ushort  item;
   long  mbmo;
   unsigned __int64  buf_len;
   unsigned __int64  *buf_addr;
};
#pragma required_pointer_size restore
#endif

typedef struct ItemList3Struct VMS_ITEM_LIST3;
struct ItemList3Struct
{
   ushort  buf_len;
   ushort  item;
   void  *buf_addr;
   void  *ret_len;
};

#ifndef __VAX
#pragma required_pointer_size save 
#pragma required_pointer_size 64 
typedef struct ItemList64b VMS_ITEM_LIST_64B;
struct ItemList64b
{
   ushort  mbo;
   ushort  item;
   long  mbmo;
   unsigned __int64  buf_len;
   unsigned __int64  *buf_addr;
   unsigned __int64  *ret_len;
};
#pragma required_pointer_size restore
#endif

struct AnExitHandler
{
   ulong  Flink;
   ulong  HandlerAddress;
   ulong  ArgCount;
   ulong  ExitStatusPtr;
};

typedef struct IoSbStruct IO_SB;

struct IoSbStruct
{
      ushort  Status;
      ushort  Count;
      variant_union {
         ulong  Unused;
         ulong  MbxPid;
      } Overlay1;
};

struct MbxSenseIOsb
{
   ushort  Status;
   ushort  MessageCount;
   ulong  MessageBytes;
};

/* 16 bytes for VAX and pre-V8.2 Alpha and Itanium, otherwise 64 bytes */ 
#define LOCK_VALUE_BLOCK_64 64
#define LOCK_VALUE_BLOCK_16 16

/* only defined for Alpha and Itanium V8.2 and later */
#undef LKI$_VALBLK
#define LKI$_VALBLK 515

#undef LKI$_XVALBLK
#define LKI$_XVALBLK 530

#undef LKI$_XVALNOTVALID
#define LKI$_XVALNOTVALID 531

#undef LCK$M_XVALBLK
#define LCK$M_XVALBLK 0x10000

#undef SS$_XVALNOTVALID
#define SS$_XVALNOTVALID 2984

#undef lksb
typedef struct lksb
{
   ushort lksb$w_status;
   ushort lksb$w_reserved;
   uint lksb$l_lkid;
   uchar lksb$b_valblk [LOCK_VALUE_BLOCK_64];
};

#undef LKIDEF
#undef lki$l_mstlkid
#undef lki$l_pid
#undef lki$l_mstcsid
#undef lki$b_rqmode
#undef lki$b_grmode
#undef lki$b_queue
#undef lki$$$_spare
#undef lki$l_lkid
#undef lki$l_csid
typedef struct wasd_lkidef
{
   uint lki$l_mstlkid;
   uint lki$l_pid;
   uint lki$l_mstcsid;
   uchar lki$b_rqmode;
   uchar lki$b_grmode;
   char lki$b_queue;
   char lki$$$_spare;
   uint lki$l_lkid;
   uint lki$l_csid;
} LKIDEF;
 

/*
   Store these structures naturally-aligned on AXP.
   Uses a bit more storage but makes access as efficient as possible.
*/

#ifndef __VAX
#   pragma member_alignment __save
#   pragma member_alignment
#endif

#define LIST_ENTRY_TYPE_UNDEFINED   0
#define LIST_ENTRY_TYPE_CACHE       1
#define LIST_ENTRY_TYPE_CHARSET     2
#define LIST_ENTRY_TYPE_DAVLOCK     3
#define LIST_ENTRY_TYPE_DCL         4
#define LIST_ENTRY_TYPE_DECNET      5
#define LIST_ENTRY_TYPE_DIR         6
#define LIST_ENTRY_TYPE_HISTORY     7
#define LIST_ENTRY_TYPE_HTTP2       8
#define LIST_ENTRY_TYPE_PERSONA     9
#define LIST_ENTRY_TYPE_REQUEST    10
#define LIST_ENTRY_TYPE_PROXY      11
#define LIST_ENTRY_TYPE_READ2      12
#define LIST_ENTRY_TYPE_SCRIPT     13
#define LIST_ENTRY_TYPE_SERVICE    14
#define LIST_ENTRY_TYPE_SSI        15
#define LIST_ENTRY_TYPE_STREAM2    16
#define LIST_ENTRY_TYPE_THROTTLE   17
#define LIST_ENTRY_TYPE_TIMER      18
#define LIST_ENTRY_TYPE_USER       19
#define LIST_ENTRY_TYPE_WATCH      20
#define LIST_ENTRY_TYPE_WEBSOCKET  21
#define LIST_ENTRY_TYPE_WRITE2     22

typedef struct ListEntryStruct LIST_ENTRY;

/* a list entry must be at octet zero of any including structure */
struct  ListEntryStruct
{
   LIST_ENTRY  *PrevPtr;
   LIST_ENTRY  *NextPtr;
   void  *DataPtr;
   ulong  DataType;
};

typedef struct ListHeadStruct LIST_HEAD;

struct  ListHeadStruct
{
   LIST_ENTRY  *HeadPtr;
   LIST_ENTRY  *TailPtr;
   int  EntryCount;
};

/* these macros operate on the list head */
#define LIST_GET_HEAD(lp) ((char*)((LIST_HEAD*)lp)->HeadPtr)
#define LIST_GET_TAIL(lp) ((char*)((LIST_HEAD*)lp)->TailPtr)
#define LIST_GET_COUNT(lp) (((LIST_HEAD*)lp)->EntryCount)
#define LIST_IS_EMPTY(lp) (!((LIST_HEAD*)lp)->EntryCount)
#define LIST_NOT_EMPTY(lp) (((LIST_HEAD*)lp)->EntryCount)

/* these macros operate on list entries */
#define LIST_GET_DATA(lp) ((char*)((char*)lp+sizeof(LIST_ENTRY)))
#define LIST_GET_PREV(lp) (((LIST_ENTRY*)lp)->PrevPtr)
#define LIST_GET_NEXT(lp) (((LIST_ENTRY*)lp)->NextPtr)
#define LIST_HAS_PREV(lp) ((((LIST_ENTRY*)lp)->PrevPtr) != NULL)
#define LIST_HAS_NEXT(lp) ((((LIST_ENTRY*)lp)->NextPtr) != NULL)

/* wrapper around a simple for(;;) loop */
#define LIST_ITERATE(ptr,list) \
for(ptr=(((LIST_HEAD*)list)->HeadPtr);ptr;ptr=(((LIST_ENTRY*)ptr)->NextPtr))

typedef struct SupervisorListStruct SUPERVISOR_LIST;

struct SupervisorListStruct
{
   LIST_HEAD  RequestList;
   int  ChunkSeconds;
};

typedef struct Md5HashStruct MD5_HASH;

struct Md5HashStruct
{
   variant_union {
      uchar  HashChar [16];
      ushort  HashShort [8];
      ulong  HashLong [4];
   } Overlay1;
};

typedef struct SysInfoStruct SYS_INFO;

struct SysInfoStruct
{
   ushort  HwNameLength,
           NodeNameLength;
   ulong  AvailCpuCnt,
          ClusterMember,
          DECnetVersion,
          LockValueBlockSize,
          MaxSysGroup,
          MemSize,
          MemoryMB,
          PageFactor,
          PageSize,
          VersionInteger;
   ulong  BootTime64 [QUAD2];
   char  HwName [61],
         NodeName [16],
         Version [9];
};

typedef struct HttpdProcessStruct HTTPD_PROCESS;

struct HttpdProcessStruct
{
     BOOL  PrivilegedAccount,
           SysInputFile,
           SysOutputFile;
     int  BytLmAvailable,
          UserNameLength,
          AstLm, BioLm, BytLm, DioLm, EnqLm, FilLm,
          Grp, Mode, Pid, PgFlQuo, PrcLm, TqLm, Uic;
     ulong  AuthPriv [QUAD2];
     ushort  PrcNamLength;
     char  *ModeName;
     char  ImageInfo [256],
           PrcNam [16],
           SysInput [256],
           SysOutput [256],
           UserName [UAF$S_USERNAME+1];
};

#define RANGE_BYTE_MAX 256

typedef struct RangeByteStruct RANGE_BYTE;

struct RangeByteStruct
{
   int  /* number of ranges to be transfered (zero is none/invalid) */
        Count,
        /* current range being transfered (array index, 0 thru to n-1) */
        Index,
        /* total length of current range being transfered (last-first+1) */
        Length,
        /* offset for the first byte in the first bucket (used by FILE.C) */
        Offset,
        /* the number of bytes remaining for current range (used by FILE.C) */
        Remaining,
        /* number of ranges in the request */
        Total;

   int  /* first byte offset */
        First [RANGE_BYTE_MAX],
        /* last byte offset */
        Last [RANGE_BYTE_MAX];
};

/* used to accumulate alignment fault statistics */
struct FaultAccumStruct
{
   ulong  pc,
          cnt;
};
struct FaultDataStruct
{
   ulong  GetBufferSize,
          ItemCount,
          ItemMax,
          ItemOverflow,
          PCmask,
          ReportBufferSize,
          ReportOverflow,
          StartTickSecond;
   struct FaultAccumStruct  *ItemArray;
};

/*******************************************/
/* header files we need early in the piece */
/*******************************************/

#include "tcpip.h"
#include "enamel.h"
#include "instance.h"
#include "odsstruct.h"
#include "metacon.h"
#include "proxystruct.h"

/**********************************/
/* request history data structure */
/**********************************/

struct  RequestHistoryStruct
{
   LIST_ENTRY  HistoryListEntry;
   struct  ServiceStruct  *ServicePtr;
   ulong  BinaryTime [QUAD2],
          BytesRawRx [QUAD2],
          BytesRawTx [QUAD2],
          ResponseDuration [QUAD2];
   ulong  ConnectNumber;
   int  BytesPerSecond,
        BytesTxGzipPercent,
        HttpMajorVersion,
        ResponseStatusCode,
        RequestState,
        TimeoutType;
   char  *RequestPtr;
   BOOL  Truncated;
   char  ClientAndRequest [256];
};

/*************************/
/* per-server accounting */
/*************************/

typedef struct AccountingStruct ACCOUNTING_STRUCT;

struct AccountingStruct
{
   /* this MUST be the first member to allow zeroing of the rest */
   ulong  ZeroedCount;

   ulong  AuthAcmeCount,
          AuthBasicCount,
          AuthAgentCount,
          AuthAuthorizedCount,
          AuthDigestCount,
          AuthHtDatabaseCount,
          AuthNotAuthenticatedCount,
          AuthNotAuthorizedCount,
          AuthOtherCount,
          AuthRFC1413Count,
          AuthSimpleListCount,
          AuthSkelKeyCount,
          AuthTokenCount,
          AuthVmsCount,
          AuthX509Count,
          CacheHitCount,
          CacheHitNotModifiedCount,
          CacheLoadCount,
          ConnectAcceptedCount,
          ConnectIpv4Count,
          ConnectIpv6Count,
          ConnectRejectedCount,
          ConnectSSLCount,
          ConnectSSL2Count,
          ConnectSSL3Count,
          ConnectTLS13Count,
          ConnectTLS12Count,
          ConnectTLS11Count,
          ConnectTLS1Count,
          ConnectTooBusyCount,
          ConnectPeakPersistent,
          CurrentHttp1Persistent,
          DclCgiPlusReusedCount,
          DclCrePrcCount,
          DclCrePrcDetachCount,
          DclCrePrcPersonaCount,
          DclCrePrcPersonaDefaultCount,
          DclCrePrcPersonaInvUserCount,
          DclCrePrcPersonaPrvUserCount,
          DclCrePrcSubprocessCount,
          DclDelPrcCount,
          DclForceXCount,
          DclHitHardLimitCount,
          DclProctorCount,
          DclRteReusedCount,
          DclWebSocketCount,
          DclWebSocketRawCount,
          DoAutoScriptCount,
          DoCgiPlusScriptCount,
          DoDclCommandCount,
          DoDECnetCount,
          DoDECnetReuseCount,
          DoDECnetCgiCount,
          DoDECnetCgiReuseCount,
          DoDECnetOsuCount,
          DoDECnetOsuReuseCount,
          DoDirectoryCount,
          DoRteScriptCount,
          DoScriptCount,
          DoFileCount,
          DoFileModuleCount,
          DoFileNotModifiedCount,
          DoNoModuleCount,
          DoProxyCount,
          DoPutCount,
          DoServerAdminCount,
          DoSsiCount,
          DoUpdateCount,
          DoWebDavCount,
          DoWebSockCount,
          ErrorsNoticedCount,
          GzipDeflateCount,
          GzipInflateCount,
          Http2RequestCount,
          Http2RequestPeak,
          LastExitPid,
          LastExitStatus,
          LookupDnsAddressCount,
          LookupDnsAddressErrorCount,
          LookupDnsNameCount,
          LookupDnsNameErrorCount,
          LookupLiteralCount,
          LookupLiteralErrorCount,
          LookupCacheAddressCount,
          LookupCacheNameCount,
          MethodConnectCount,
          MethodDeleteCount,
          MethodExtensionCount,
          MethodGetCount,
          MethodHeadCount,
          MethodOptionsCount,
          MethodPostCount,
          MethodPutCount,
          MethodSshCount,
          MethodTraceCount,
          MethodWebDavCopyCount,
          MethodWebDavLockCount,
          MethodWebDavMkColCount,
          MethodWebDavMoveCount,
          MethodWebDavPropFindCount,
          MethodWebDavPropPatchCount,
          MethodWebDavUnLockCount,
          MethodWebDav_DeleteCount,
          MethodWebDav_GetCount,
          MethodWebDav_OptionsCount,
          MethodWebDav_PutCount,
          NcsCount,
          NcsConvertCount,
          NetReadErrorCount,
          NetWriteErrorCount,
          OdsDirectBugcheckCount,
          OdsDirectCallCount,
          OdsDirectLoadCount,
          OdsDirectRetryCount,
          PathAlertCount,
          PipelineRequestCount,
          PipelineRequestMax,
          ProcessingTooBusyCount,
          RedactRequestCount,
          RedirectLocalCount,
          RedirectRemoteCount,
          RequestErrorCount,
          RequestForbiddenCount,
          RequestHttp09Count,
          RequestHttp10Count,
          RequestHttp11Count,
          RequestHttp2Count,
          RequestNotFromCacheCount,
          RequestPersistentCount,
          RequestPersistentMax,
          RequestProxyCount,
          RequestSSLCount,
          SpuriousWakeCount,
          StartupCount,
          StreamLfConversionCount,
          ThrottleBusyMetric,
          ThrottleTotalBusy,
          ThrottleTotalProcessed,
          ThrottleTotalQueued,
          WebDavEnabled,
          WebDavAromaCount,
          WebDavMetaReadAttemptCount,
          WebDavMetaReadCount,
          WebDavMetaWriteAttemptCount,
          WebDavMetaWriteCount,
          WebDavRequestCount,
          WebDavXmlParseCount,
          WebSocketCount,
          WebSocketRawCount;

   ulong  ErrorsNoticedTime64 [QUAD2],
          Http2FlowControlCount [QUAD2],
          Http2FlowFrameCount [QUAD2],
          Http2FrameCountRx [QUAD2],
          Http2FrameCountTx [QUAD2],
          Http2FrameRequestCountRx [QUAD2],
          Http2FrameRequestCountTx [QUAD2],
          GzipDeflateBytesIn [QUAD2],
          GzipDeflateBytesOut [QUAD2],
          GzipInflateBytesIn [QUAD2],
          GzipInflateBytesOut [QUAD2],
          LastExitTime64 [QUAD2];

   ulong  CurrentDclScriptProcess [INSTANCE_MAX+1],
          CurrentDclScriptCgiPlus [INSTANCE_MAX+1],
          CurrentDclScriptRTE [INSTANCE_MAX+1],
          CurrentDECnetCGI [INSTANCE_MAX+1],
          CurrentDECnetOSU [INSTANCE_MAX+1],
          CurrentDECnetTasks [INSTANCE_MAX+1],
          CurrentPersistentHttp1 [INSTANCE_MAX+1],
          CurrentThrottleProcessing [INSTANCE_MAX+1],
          CurrentThrottleQueued [INSTANCE_MAX+1],
          CurrentWebSockets [INSTANCE_MAX+1],
          CurrentWebSocketsRaw [INSTANCE_MAX+1],
          ResponseStatusCodeGroup [6],
          /* see RequestHttpStatusCode() for calculation */
          ResponseStatusCodeCount [RESPONSE_STATUS_CODE_MAX];

   /* total [0], HTTP/1 [1], HTTP/2 [2] */

   ulong  BytesPerSecondAve [HTTPN],
          BytesPerSecondMax [HTTPN],
          BytesPerSecondMin [HTTPN],
          ConnectCount [HTTPN],
          ConnectPeak [HTTPN],
          CurrentConnected [HTTPN],
          CurrentProcessing [HTTPN],
          ProcessingPeak [HTTPN],
          ProcessingTotalCount [HTTPN],
          ResponseDurationCount [HTTPN];

   ulong  CurrentInstanceConnected [HTTPN] [INSTANCE_MAX+1],
          CurrentInstanceProcessing [HTTPN] [INSTANCE_MAX+1];

   ulong  BlocksRawRx [HTTPN] [QUAD2],
          BlocksRawTx [HTTPN] [QUAD2],
          BlocksRawTotal [HTTPN] [QUAD2],
          BytesRawRx [HTTPN] [QUAD2],
          BytesRawTx [HTTPN] [QUAD2],
          BytesPerSecondMaxBytes [HTTPN] [QUAD2],
          BytesPerSecondMinBytes [HTTPN] [QUAD2],
          BytesPerSecondMaxDuration [HTTPN] [QUAD2],
          BytesPerSecondMinDuration [HTTPN] [QUAD2],
          BytesPerSecondRawRx [HTTPN] [QUAD2],
          BytesPerSecondRawTx [HTTPN] [QUAD2],
          BytesPerSecondRawTotal [HTTPN] [QUAD2],
          ResponseDurationMax [HTTPN] [QUAD2],
          ResponseDurationMin [HTTPN] [QUAD2],
          ResponseDuration [HTTPN] [QUAD2],
          WebDavBytesRawRx [HTTPN] [QUAD2],
          WebDavBytesRawTx [HTTPN] [QUAD2];

    int  InstanceStatusTableCount;
    INSTANCE_STATUS  InstanceStatusTable [INSTANCE_STATUS_TABLE_MAX];
    INSTANCE_NODE_DATA  InstanceNodeData [INSTANCE_MAX+1];
};

/************************/
/* HTTPd global section */
/************************/

typedef struct MonRequestStruct MONITOR_REQUEST;

struct MonRequestStruct
{
   BOOL  Alert;
   int  HttpStatus,
        HttpProtocol,
        BytesPerSecond,
        BytesTxGzipPercent;
   ulong  BytesRawRx [QUAD2],
          BytesRawTx [QUAD2];
   char  AuthUser [96],
         ClientHostName [96],
         ClientIpAddressString [TCPIP_ADDRESS_STRING_MAX+1],
         Duration [16],
         MethodName [16],
         PrcNam [16],
         ReadError [96],
         Service [96],
         Time [16],
         Uri [236],
         WriteError [96];
};

/* name is "WASD" + a hex version number + instance number + string */
#define GBLSEC_NAME_FAO "!AZ_!6XL_!UL_!AZ"

typedef struct HttpdGblSecStruct HTTPD_GBLSEC;

struct HttpdGblSecStruct
{
   ulong  GblSecVersion,
          GblSecLength,
          HttpdProcessId;
   ulong  Mutex [INSTANCE_MUTEX_COUNT+1],
          MutexCount [INSTANCE_MUTEX_COUNT+1],
          MutexWaitCount [INSTANCE_MUTEX_COUNT+1];
   char  HttpdVersion [16],
         StatusMessage [256],
         PkPasswd [64];
   ACCOUNTING_STRUCT  Accounting;
   PROXY_ACCOUNTING_STRUCT  ProxyAccounting;
   MONITOR_REQUEST  Request;
   int  ConnectSuspend,
        InstanceClusterCurrent,
        InstanceNodeCurrent,
        InstanceStartupMax,
        InstancePassive;
   char  AuthSkelKeyUserName [47+1],
         AuthSkelKeyPassword [31+1];
   int  AuthSkelKeyHttpdTickSecond;
   char  MetaConNote [LOCK_VALUE_BLOCK_64];
   /* obsolete VM dynamic tuning */
   ulong  VmHttp2SizePages,
          VmRequestSizePages;
};

#ifndef __VAX
#   pragma member_alignment __restore
#endif

/************************/
/* module include files */
/************************/

#ifndef ADMIN_H_LOADED
#   include "admin.h"
#endif
#ifndef AUTH_H_LOADED
#   include "auth.h"
#endif
#ifndef BASIC_H_LOADED
#   include "basic.h"
#endif
#ifndef BODY_H_LOADED
#   include "body.h"
#endif
#ifndef CACHE_H_LOADED
#   include "cache.h"
#endif
#ifndef CGI_H_LOADED
#   include "cgi.h"
#endif
#ifndef CONFIG_H_LOADED
#   include "config.h"
#endif
#ifndef CONTROL_H_LOADED
#   include "control.h"
#endif
#ifndef DESCR_H_LOADED
#   include "descr.h"
#endif
#ifndef DCL_H_LOADED
#   include "dcl.h"
#endif
#ifndef DICT_H_LOADED
#   include "dict.h"
#endif
#ifndef DIR_H_LOADED
#   include "dir.h"
#endif
#ifndef DECNET_H_LOADED
#   include "decnet.h"
#endif
#ifndef ERROR_H_LOADED
#   include "error.h"
#endif
#ifndef FAO_H_LOADED
#   include "fao.h"
#endif
#ifndef FILE_H_LOADED
#   include "file.h"
#endif
#ifndef GRAPH_H_LOADED
#   include "graph.h"
#endif
#ifndef HTADMIN_H_LOADED
#   include "htadmin.h"
#endif
#ifndef HTTP2_H_LOADED
#   include "http2.h"
#endif
#ifndef HTTPD_H_LOADED
#   include "httpd.h"
#endif
#ifndef HPACK_H_LOADED
#   include "hpack.h"
#endif
#ifndef INSTANCE_H_LOADED
#   include "instance.h"
#endif
#ifndef MAPURL_H_LOADED
#   include "mapurl.h"
#endif
#ifndef MSG_H_LOADED
#   include "msg.h"
#endif
#ifndef NET_H_LOADED
#   include "net.h"
#endif
#ifndef ODS_H_LOADED
#   include "ods.h"
#endif
#ifndef PERSONA_H_LOADED
#   include "persona.h"
#endif
#ifndef PROXY_H_LOADED
#   include "proxy.h"
#endif
#ifndef PROXYCACHE_H_LOADED
#   include "proxycache.h"
#endif
#ifndef PROXYFTP_H_LOADED
#   include "proxyftp.h"
#endif
#ifndef PROXYMAINT_H_LOADED
#   include "proxymaint.h"
#endif
#ifndef PROXYNET_H_LOADED
#   include "proxynet.h"
#endif
#ifndef PROXYVERIFY_H_LOADED
#   include "proxyverify.h"
#endif
#ifndef PUT_H_LOADED
#   include "put.h"
#endif
#ifndef REQUEST_H_LOADED
#   include "request.h"
#endif
#ifndef RESPONSE_H_LOADED
#   include "response.h"
#endif
#ifndef SSI_H_LOADED
#   include "ssi.h"
#endif
#ifndef SERVICE_H_LOADED
#   include "service.h"
#endif
#ifndef Sesola_H_LOADED
#   include "Sesola.h"
#endif
#ifndef STMLF_H_LOADED
#   include "stmlf.h"
#endif
#ifndef STRDSC_H_LOADED
#   include "strdsc.h"
#endif
#ifndef STRNG_H_LOADED
#   include "strng.h"
#endif
#ifndef SUPPORT_H_LOADED
#   include "support.h"
#endif
#ifndef SYSPLUS_H_LOADED
#   include "sysplus.h"
#endif
#ifndef THROTTLE_H_LOADED
#   include "throttle.h"
#endif
#ifndef UPD_H_LOADED
#   include "upd.h"
#endif
#ifndef VM_H_LOADED
#   include "vm.h"
#endif
#ifndef WATCH_H_LOADED
#   include "watch.h"
#endif
#ifndef WEBSOCK_H_LOADED
#   include "websock.h"
#endif
#ifndef WEBDAV_H_LOADED
#   include "davweb.h"
#endif

/*
   Store the following structures naturally-aligned on AXP.
   Uses a bit more storage but makes access as efficient as possible.
*/

#ifndef __VAX
#   pragma member_alignment __save
#   pragma member_alignment
#endif

/***************/
/* minor tasks */
/***************/

typedef struct HissTaskStruct HISS_TASK;

struct HissTaskStruct
{
   /* maximum number of bytes of hiss to be sent */
   int  HissBytesMax;
};

typedef struct StreamTaskStruct STREAM_TASK;

struct StreamTaskStruct
{
   int  /* maximum number of bytes of streamed pritables to be sent */
        StreamBytesMax,
        /* note where we're up to between each write */
        StreamOctetBuffer,
        /* ascii, binary, octet, text */
        StreamTypeFlag;
};

typedef struct TraceTaskStruct TRACE_TASK;

struct TraceTaskStruct
{
   int  JustAFiller;
};

/****************************************/
/* request authentication/authorization */
/****************************************/

typedef struct RequestAuthorizationStruct AUTH_STRUCT;

struct RequestAuthorizationStruct
{
   BOOL  /* the user was authenticated using ACME */
         AcmeAuthenticated,
         /* a case-less username and password was performed */
         CaseLess,
         /* authenticated user may only access via https: (SSL) */
         HttpsOnly,
         /* do not cache authentication information, revalidate each time */
         NoCache,
         /* there was a problem with the configuration of the path */
         PathProblem,
         /* the authentication realm name is a synonym for the SYSUAF */
         RealmIsVmsSynonym,
         /* there was a problem with the configuration of the realm */
         RealmProblem,
         /* 'RemoteUser' was resolved rather than supplied by the user */
         ResolvedRemoteUser,
         /* the user was authenticated using a skeleton key */
         SkelKeyAuthenticated,
         /* the user was authenticated from the SYSUAF */
         SysUafAuthenticated,
         /* user may change SYSUAF password */
         SysUafCanChangePwd,
         /* user can authenticate even if hours seem to prohibit */
         SysUafNilAccess,
         /* primary password has expired */
         SysUafPwdExpired,
         /* authorization rule directed to use SYSUAF profile */
         VmsUserProfile,
         /* authorization rule directed to script SYSUAF username */
         VmsUserScriptAs;

   int  /* X509 client certificate fingerprint length */
        ClientCertFingerprintLength,
        /* X509 client certificate CA length */
        ClientCertIssuerLength,
        /*  X509 client certificate client length */
        ClientCertSubjectLength,
        /* VMS status result of authentication/authorization */
        FinalStatus,
        /* length of string */
        GroupReadLength,
        /* VMS status result of group read authorization */
        GroupReadStatus,
        /* length of string */
        GroupWriteLength,
        /* VMS status result of group write authorization */
        GroupWriteStatus,
        /* length of path being authorized :^) */
        PathBeingAuthorizedLength,
        /* length of path from authorization rule */
        PathLocationLength,
        /* length of additional parameter(s) */
        PathParameterLength,
        /* length of mapping PROTECT RULE from pass 1 */
        Protect1Length,
        /* length of mapping PROTECT RULE from pass 1 */
        Protect2Length,
        /* length of proxy mapping string */
        ProxyStringLength,
        /* length of string */
        RealmLength,
        /* length of string */
        RealmParamLength,
        /* length of the reason string */
        ReasonLength,
        /* what was originally supplied in remote_user */
        RemoteUserLength,
        /* number of minutes before credentials need to be revalidated */
        RevalidateTimeout,
        /* length of CGI-like meta variables */
        ScriptMetaLength,
        /* SYSUAF logon wasd NETWORK, BATCH, REMOTE, etc. */
        SysUafLogonType,
        /* authenticated user details length */
        UserDetailsLength,
        /* number of identifiers loaded into array */
        VmsIdentifiersCount;

   ushort  /* length of the user profile pointed to */
           VmsUserProfileLength;

   ulong  /* value representation of scheme being used for challenge */
          ChallengeScheme,
          /* the capability flags of the authorization path */
          GroupCan,
          /* VMS identifier value controlling read access */
          GroupReadVmsIdentifier,
          /* VMS identifier value controlling write access */
          GroupWriteVmsIdentifier,
          /* VMS identifier value controlling authentication */
          RealmVmsIdentifier,
          /* the capability flags of the request (ACT ON THESE!) */
          RequestCan,
          /* value representation of scheme being used for request */
          Scheme,
          /* source of read-only group information */
          SourceGroupRead,
          /* source of full-access group information */
          SourceGroupWrite,
          /* source of realm information */
          SourceRealm,
          /* the capability flags of the remote user */
          UserCan,
          /* what everybody else can do on that path */
          WorldCan;

   ulong  /* pointer to array of VMS identifiers (zero-terminated) */
          *VmsIdentifiersPtr;

   char  /* authorization token value */
         *AuthTokenValuePtr,
         /* BASIC challenge response header field */
         *BasicChallengePtr,
         /* X509 client certificate fingerprint */
         *ClientCertFingerprintPtr,
         /* X509 client certificate CA */
         *ClientCertIssuerPtr,
         /* X509 client certificate client */
         *ClientCertSubjectPtr,
         /* DIGEST challenge response header field */
         *DigestChallengePtr,
         /* when digest authenticating, the client-supplied nonce */
         *DigestNoncePtr,
         /* when digest authenticating, the client-supplied digest */
         *DigestResponsePtr,
         /* when digest authenticating, the client-supplied URI */
         *DigestUriPtr,
         /* locates the directory containing required databases */
         *DirectoryPtr,
         /* pointer to authorization group name */
         *GroupReadPtr,
         /* pointer to string of IP-address/username masks */
         *GroupRestrictListPtr,
         /* pointer to authorization group name */
         *GroupWritePtr,
         /* pointer to the path being authorized :^) */
         *PathBeingAuthorizedPtr,
         /* the path from the rule that triggered authorization */
         *PathLocationPtr,
         /* used for additional authorization parameters */
         *PathParameterPtr,
         /* mapping PROTECT RULE from pass 1 */
         *Protect1Ptr,
         /* mapping PROTECT RULE from pass 2 */
         *Protect2Ptr,
         /* pointer to a string containing proxy username mappings */
         *ProxyStringPtr,
         /* pointer to authorization realm name */
         *RealmPtr,
         /* pointer to authorization realm synonym string */
         *RealmDescrPtr,
         /* pointer to realm parameter string */
         *RealmParamPtr,
         /* pointer to a string containing a 401/403 error message */
         *ReasonPtr,
         /* points to either "Authorization:" or "Proxy-Authorization:" field */
         *RequestAuthorizationPtr,
         /* a list of non-CGI meta variables */
         *ScriptMetaPtr,
         /* authenticated user details */
         *UserDetailsPtr,
         /* user profile is used by sys$check_access() */
         *VmsUserProfilePtr,
         /* pointer to string of IP-address/username masks */
         *WorldRestrictListPtr;

   char  /* what was originally provide in remote_user */
         RemoteUser [AUTH_MAX_USERNAME_LENGTH+1],
         /* basic, digest, etc. */
         Type [16];

   /* a pointer to a template used when searching the cache */
   AUTH_CREC  *CacheSearchRecordPtr;

   /* structure used during SYSUAF processing */
   AUTH_SYSUAF  *SysUafDataPtr;

   /* structure used during ACME processing */
   AUTH_ACME  *AcmeDataPtr;

   /* AST function pointers */
   REQUEST_AST  AstFunctionBuffer;
   REQUEST_AST  AstFunction;
   REQUEST_AST  AgentCalloutFunction;
};

/**************************/
/* request content (body) */
/**************************/

typedef struct RequestBodyStruct BODY_STRUCT;

struct  RequestBodyStruct
{
   int  /* chunked body count */
        ChunkCount,
        /* current chunk size (from 'ChunkSizeString') */
        ChunkSize,
        /* stage in the chunked processing */
        ChunkState,
        /* how much has been read from the client */
        ContentCount,
        /* count of buffered data for chunked trailer fields */
        ChunkedTrailerBufferCount,
        /* size of buffer for chunked trailer fields */
        ChunkedTrailerBufferSize,
        /* detect when chunked trailer fields are terminated */
        ChunkedTrailerNewLineCount,
        /* equivalent of request header content-length */
        ContentLength,
        /* amount of raw or processed data available in this buffer */
        DataCount,
        /* size of raw data buffer (maximum read capacity, etc.) */
        DataSize,
        /* VMS status of last buffer read or other operation */
        DataStatus,
        /* virtual block number (512 byte block) of output */
        DataVBN,
        /* how many reads have been made from the client */
        DiscardReadCount,
        /* was processed as this sort of content (BODY_PROCESSED_AS..) */
        ProcessedAs,
        /* e.g. convert from chunked/gzipped as read from the client */
        UnEncodeStream;

   char  /* points to the start of buffer used for chunked trailer fields */
         *ChunkedTrailerBufferPtr,
         /* pointer to raw or processed data ('.DataCount' gives it's size) */
         *DataPtr;

   char  /* buffer for ASCII hexadecimal chunk size number */
         ChunkSizeString [32];

   /* a pointer to body processing data */
   BODY_PROCESS  *ProcessPtr;

   /* "callback" function used to process/transfer body contents */
   REQUEST_AST  AstFunction;
   REQUEST_AST  ProcessFunction;
};

/*************************/
/* request cache storage */
/*************************/

typedef struct RequestCacheStruct REQUEST_CACHE;

struct RequestCacheStruct
{
   BOOL  /* do not cache this request (for some reason or another) */
         DoNotCache,
         /* content is currently being loaded */
         Loading,
         /* the request has been assessed to see if it requires loading */
         LoadCheck,
         /* loaded at the CGI access point */
         LoadFromCgi,
         /* loaded at the file access point */
         LoadFromFile,
         /* loaded at the network access point */
         LoadFromNet,
         /* content is currently not usable */
         NotUsable;

   int  /* VMS status reflecting data load */
        LoadStatus,
        /* maximum length of content data (size of buffer) */
        ContentBufferSize,
        /* length of content data */
        ContentLength,
        /* amount of buffer remaining */
        ContentRemaining,
        /* convenience for when performing record I/O in the file module */
        RecordBlockLength,
        /* non-file response header, cache-control seconds (if present) */
        ResponseCacheControl;

   /* MD5 hash of mapped path */
   MD5_HASH  Md5Hash;

   char  /* used both when loading and reading cache */
         *ContentPtr,
         /* data content-type */
         *ContentTypePtr,
         /* used both when loading and reading cache */
         *CurrentPtr;

   char  /* non-file response header, entity tag (if present) */
         ResponseEntityTag [CACHE_ENTITY_MAX+1];

   /* request is being used to fill a cache entry */
   struct CacheStruct  *EntryPtr;
};

/*************************/
/* request character set */
/*************************/

struct  RequestCharsetStruct
{
   int  /* character set name length */
        CharsetLength;

   ulong  /* context of NCS conversion function */
          NcsCf;

   char  /* pointer to character set name to be converted to */
         CharsetPtr;
};

/***************************/
/* request CGI environment */
/***************************/

typedef struct RequestCgiStruct CGI_STRUCT;

struct  RequestCgiStruct
{
   BOOL  /* one-shot, absorb script CGI or NHP response header */
         AbsorbHeader,
         /* an agent does not need to provide a CGI compilant output */
         AgentScript,
         /* do not output to client record-by-record, buffer */
         BufferRecords,
         /* script output escape is being processed */
         CalloutInProgress,
         /* script is requesting that its content be/not be GZIP compressed */
         ContentEncodingGzip,
         /* the MIME type is "text/..." */
         ContentTypeText,
         /* remove all non-printable characters */
         FilterStream,
         /* the script has issued an initial "100 Continue" response */
         Header100Continue,
         /* already done one of these already without a "real" header */
         Header100ContinueDone,
         /* the WebSocket has issued an initial "101 Switching Protocols" */
         Header101Switching,
         /* header does not contain carriage-control */
         HeaderCarRet,
         /* is NOT a script, just the CLI being used to execute some DCL */
         IsCliDcl,
         /* in the body of the response  */
         ProcessingBody,
         /* the response is already transfer-encoded in some way */
         TransferEncoding,
         /* script is requesting that its content be/not be chunked */
         TransferEncodingChunked;

   int  /* length of heap memory pointed to by BufferPtr */
        BufferLength,
        /* remaining space in heap memory pointed to by BufferPtr */
        BufferRemaining,
        /* count of characters pointed to by 'CalloutOutputPtr' */
        CalloutOutputCount,
        /* if the CGI response contained a content-length field */
        ContentLength,
        /* length of "end-of-file" (output) sequence */
        EofLength,
        /* length of "end-of-text" sequence */
        EotLength,
        /* length of "escape" sequence */
        EscLength,
        /* keep track of usage when buffering script header */
        HeaderLength,
        /* CGI header lines so far */
        HeaderLineCount,
        /* stream, record, crlf modes */
        OutputMode,
        /* number of records (may have multiple lines) received from a script */
        RecordCount,
        /* period before the dynamic content is considered stale */
        ScriptControlCacheExpiresAfter,
        /* use this as the maximum allowed size to be cached */
        ScriptControlCacheMaxKBytes,
        /* line in module error reported from */
        ScriptControlErrorLine,
        /* script has returned a VMS status value */
        ScriptControlErrorVmsStatus,
        /* script is forcing this HTTP status (when error reporting) */
        ScriptControlHttpStatus,
        /* how many attempts have been made to restart a CGI script */
        ScriptRetryCount,
        /* length of the symbol(s) truncated string */
        SymbolTruncateLength,
        /* for VMS Apache compatibility (1.3.9 at least!) */
        XVMSRecordMode;

   char  /* heap memory in which the CGI variables are generated */
         *BufferPtr,
         /* current position in CGI variable buffer */
         *BufferCurrentPtr,
         /* pointer to a record output by a callout sequence */
         *CalloutOutputPtr,
         /* dynamically allocated space for buffering script header */
         *HeaderPtr,
         /* name of module error reported from */
         *ScriptControlErrorModulePtr,
         /* text of error message */
         *ScriptControlErrorTextPtr,
         /* text in commented portion of error message */
         *ScriptControlErrorVmsTextPtr,
         /* VMS syntax script file name */
         *ScriptFileNamePtr,
         /* pointer to the symbol(s) truncated */
         *SymbolTruncatePtr;

   char  /* "end-of-file" (output) sequence */
         EofStr [32],
         /* "end-of-text" sequence */
         EotStr [32],
         /* "escape" sequence */
         EscStr [32];
};

/******************************/
/* request header information */
/******************************/

typedef struct RequestHeaderStruct HEADER_STRUCT;

struct  RequestHeaderStruct
{
   BOOL  /* client accepts ZLIB compressed streams */
         AcceptEncodingGzip,
         /* "Cache-control: max-age=0" header field */
         CacheControlMaxAgeZero,
         /* "Cache-control: max-stale[=0]" header field */
         CacheControlMaxStaleZero,
         /* "Cache-control: max-fresh=0" header field */
         CacheControlMinFreshZero,
         /* "Cache-control: no-cache" header field */
         CacheControlNoCache,
         /* "Cache-control: no-store" header field */
         CacheControlNoStore,
         /* "Cache-control: no-transform" header field */
         CacheControlNoTransform,
         /* "Cache-control: only-if-cached" header field */
         CacheControlOnlyIfCached,
         /* "Connection: close" header value */
         ConnectionClose,
         /* "Connection: HTTP2-Settings" header value */
         ConnectionHttp2Settings,
         /* "Connection: keep-alive" header value */
         ConnectionKeepAlive,
         /* "Connection: Upgrade" header field */
         ConnectionUpgrade,
         /* client body is a ZLIB compressed stream */
         ContentEncodingGzip,
         /* client has provided an unknown content encoding */
         ContentEncodingUnknown,
         /* "Expect: 100-continue" header field */
         Expect100Continue,
         /* unsupported "Expect:" expectation */
         ExpectUnsupported,
         /* "Keep-Alive:" header field  */
         KeepAliveConnection,
         /* "Max-forwards:" header field */
         MaxForwards,
         /* "Pragma: no-cache" header field */
         PragmaNoCache,
         /* "Proxy-Connection: close" header field */
         ProxyConnectionClose,
         /* "ProxyConnection: keep-alive" header field */
         ProxyConnectionKeepAlive,
         /* if read buffer is reused (e.g. body read) original header kaput */
         RequestHeaderPtrInvalid,
         /* "Transfer-Encoding: chunked" header field detected */
         TransferEncodingChunked,
         /* http: "Upgrade: h2c" header field */
         UpgradeHttp2onHttp,
         /* "Upgrade: WASD-tunnel" header field */
         UpgradeWASDtunnel,
         /* "Upgrade: WebSocket" header field */
         UpgradeWebSocket,
         /* when WATCHing a new request has been noted */
         WatchNewRequest,
         /* return the uninterpreted resource */
         WebDavTranslateFalse,
         /* can overwrite a non-null resource */
         WebDavOverwrite;

   int  /* "Cache-control: max-age=n" header field */
        CacheControlMaxAge,
        /* "Cache-control: max-stale=n" header field */
        CacheControlMaxStale,
        /* "Cache-control: min-fresh=n" header field */
        CacheControlMinFresh,
        /* "Content-Length:" value */
        ContentLength,
        /* length of "Host:" field value */
        HostLength,
        /* value representation of HTTP protocol version number */
        HttpVersion,
        /* length of if-modified-since header */
        IfModifiedSinceLength,
        /* "Keep-Alive: nnn" header field  */
        KeepAliveSeconds,
        /* value representation of request HTTP method */
        Method,
        /* length of path from HTTP header */
        PathInfoLength,
        /* length of query string from HTTP header */
        QueryStringLength,
        /* count of any body received with HTTP header */
        RequestBodyCount,
        /* length of HTTP header */
        RequestHeaderLength,
        /* length of HTTP request line */
        RequestLineLength,
        /* length of URI (path plus query string) from HTTP header */
        RequestUriLength,
        /* number of (forbidden) unencoded quotation marks in the URI */
        RequestUriQuoteCount,
        /* resource depth */
        WebDavDepth,
        /* WebSocket version number ("Sec-WebSocket-Version:")) */
        WebSocketVersion,
        /* WebDAV OSX (Apple) quirk */
        XExpectedEntityLength;

   char  /* "Accept:" header value */
         *AcceptPtr,
         /* "Accept-Charset:" header value */
         *AcceptCharsetPtr,
         /* "Accept-Encoding:" header value */
         *AcceptEncodingPtr,
         /* "Accept-Language:" header value */
         *AcceptLangPtr,
         /* "Access-Control-Request-Headers:" header value */
         *AccConRequestHeadersPtr,
         /* "Access-Control-Request-Method:" header value */
         *AccConRequestMethodPtr,
         /* "Authorization:" header value */
         *AuthorizationPtr,
         /* "Cache-Control:" header value */
         *CacheControlPtr,
         /* stream's MIME content type header value */
         *ContentTypePtr,
         /* "Cookie:" header value */
         *CookiePtr,
         /* "Forwarded:" header value */
         *ForwardedPtr,
         /* "HTTP2-Settings:" header value */
         *Http2SettingsPtr,
         /* "Host:" header value */
         *HostPtr,
         /* "If-Match:" header value */
         *IfMatchPtr,
         /* "If-None-Match:" header value */
         *IfNoneMatchPtr,
         /* "Origin:" header value */
         *OriginPtr,
         /* pointer to heap storage of request path */
         *PathInfoPtr,
         /* pointer to heap storage of request query string */
         *QueryStringPtr,
         /* pointer to any body received with request header */
         *RequestBodyPtr,
         /* pointer to request header */
         *RequestHeaderPtr,
         /* pointer to requested resource (path and any query string) */
         *RequestUriPtr,
         /* "Proxy-Authorization:" header value */
         *ProxyAuthorizationPtr,
         /* "Referer:" header value */
         *RefererPtr,
         /* pointer to HTTP request line */
         *RequestLinePtr,
         /* sec-websocket-key: header value */
         *SecWebSocketKeyPtr,
         /* sec-websocket-protocol: header value */
         *SecWebSocketProtocolPtr,
         /* "User-Agent:" header value */
         *UserAgentPtr,
         /* "X-Forwarded-For:" header value */
         *XForwardedForPtr,
         /* "If:" header value */
         *WebDavIfPtr,
         /* "Depth:" header value */
         *WebDavDepthPtr,
         /* value of above */
         *WebDavDestinationPtr,
         /* "Lock-Token:" header value */
         *WebDavLockTokenPtr,
         /* "Overwrite:" header value */
         *WebDavOverwritePtr,
         /* "Timeout:" header value */
         *WebDavTimeoutPtr,
         /* "Translate:" header value */
         *WebDavTranslatePtr;

   char  /* string representing the request's HTTP method */
         MethodName [METHOD_NAME_SIZE];

   /* byte-range structure */
   RANGE_BYTE  *RangeBytePtr;
};

/***********************************/
/* request network-related storage */
/***********************************/

typedef struct RequestNetStruct NET_STRUCT;

/* must be located in the non-zeroed portion of the request stucture! */
struct  RequestNetStruct
{
   int  /* count of consecutive failures on a persistent connection */
        ConsecutiveFailureCount,
        /* stores original data length over multiple GZIP writes */
        GzipDataLength,
        /* count of how many times the TCP/IP connection is reused */
        PersistentCount,
        /* count of data suspected of being a pipelined request */
        PipelineBufferCount,
        /* size of buffer for data suspected of being a pipelined request */
        PipelineBufferSize,
        /* count of how many times pipelined requests have occured */
        PipelineRequestCount,
        /* size of network read */
        ReadBufferSize,
        /* incremented by NetReadRawAst() with each status block error */
        ReadErrorCount,
        /* redacted request read count */
        RedactBufferCount,
        /* size of redacted request */
        RedactBufferSize,
        /* incremented by NetWriteRawAst() with each status block error */
        WriteErrorCount,
        /* size of network write */
        WriteRawDataLength;

   ulong  /* first error status */
          ReadErrorStatus,
          /* first error status */
          WriteErrorStatus;

   char  /* points to original data over multiple GZIP writes */
         *GzipDataPtr,
         /* dynamically stores data suspected of being a pipelined request */
         *PipelineBufferPtr,
         /* pointer to heap storage client-read network buffering */
         *ReadBufferPtr,
         /* redacted request buffer */
         *RedactBufferPtr,
         /* pointer to network writes */
         *WriteRawDataPtr;

   /* network read and write AST function pointers */
   REQUEST_AST  GzipAstFunction;
};

/*************************/
/* request path settings */
/*************************/

typedef struct RequestPathSetStruct PATHSET_STRUCT;

struct RequestPathSetStruct
{
   BOOL  /* language variant is based on file type not file name */
         AcceptLangTypeVariant,
         /* language variant is based on file type not "text/.." */
         AcceptLangWildcard,
         /* access according to SYSUAF profile */
         AccessProfile,
         /* allowed to read from this path */
         AccessRead,
         /* access as server account (best effort) */
         AccessServer,
         /* allowed to write to this path */
         AccessWrite,
         /* alert if path is detected */
         Alert,
         /* all access must be authorized (or fail) */
         AuthorizeAll,
         /* only authorize the mapped path, rather than the request path */
         AuthorizeMapped,
         /* only authorize the full path (not as script then path) */
         AuthorizeOnce,
         /* cache CGI-compliant script output */
         CacheCGI,
         /* cache (non-file) requests containing cookies */
         CacheCookie,
         /* do not cache files (traditional/backward-compatible setting) */
         CacheNoFile,
         /* cache request network output of any kind */
         CacheNet,
         /* cache non-parse-header script output */
         CacheNPH,
         /* it's a permanent cache entry (cannot be flushed) */
         CachePermanent,
         /* cache this path with query-string */
         CacheQuery,
         /* cache Server Side Includes output */
         CacheSSI,
         /* CORS */
         CorsAllowCredentials,
         /* terminate the CGIPLUS stream using an EOF after the empty record */
         CgiPlusInWriteof,
         /* access to directory listings is allowed */
         DirAccess,
         /* access to directory listings is not allowed */
         DirNoAccess,
         /* access is allowed the directory contains .WWW_BROWSABLE */
         DirAccessSelective,
         /* icon plain-text link disabled */
         DirNoIconLink,
         /* implied wildcard disabled */
         DirNoImpliedWildcard,
         /* wildcard specification allowed */
         DirWildcard,
         /* wildcard specification not allowed */
         DirNoWildcard,
         /* rule mapping, SET the path to be pre-expired */
         Expired,
         /* send an HTTP/2 ping frame */
         Http2SendPing,
         /* move HTTP/2 to HTTP/1.1 (immediately) */
         Http2ToHttp11,
         /* allow VMS '...' wildcard */
         MapEllipsis,
         /* apply mapping rules to empty paths */
         MapEmpty,
         /* this request is using an HTTP extension-method (not GET, etc.) */
         MapExtensionMethod,
         /* if a script is mapped, DO NOT map the derived path portion */
         MapOnce,
         /* during mapping replace path with request URI (for rewrite) */
         MapUri,
         /* rule mapping, SET the path not-to-be-cached */
         NoCache,
         /* do not apply any default search script */
         NoDefaultSearch,
         /* rule mapping, SET the path not-to-be-logged */
         NoLog,
         /* VMS user profile does not apply to this path */
         NoProfile,
         /* path may contain SSI documents with privileged directives */
         PrivSsi,
         /* proxy affinity domain is set */
         ProxyAffinity,
         /* reverse proxy authorization verification */
         ProxyReverseVerify,
         /* reverse proxy doesn't send Authorization infos to origin server */
         ProxyReverseNoAuthHeader,
         /* provide unknown request fields in proxy request header */
         ProxyUnknownRequestFields,
         /* by default applicable response are chunked, suppress that */
         ResponseNoChunked,
         /* for successful responses suppress end-of-header blank line */
         ResponseHeaderBegin,
         /* for successful responses do not *generate* a header */
         ResponseHeaderNone,
         /* response reports origina HTTP version (e.g. HTTP/1.0) */
         ResponseHttpOriginal,
         /* decode any chunked or gzip encoded request body */
         ScriptBodyDecode,
         /* do not search for the script file (for RTE use) */
         ScriptNoFind,
         /* check that the path exists as a file before activating script */
         ScriptPathFind,
         /* do not parse the query string, let the script handle it */
         ScriptQueryNone,
         /* do not report form-url-encoded error, let the script handle it */
         ScriptQueryRelaxed,
         /* truncate a CGI symbol that would otherwise be too long */
         ScriptSymbolTruncate,
         /* pass the file name and path translated in U**x syntax */
         ScriptSyntaxUnix,
         /* rule mapping, SET the path allowing stream-LF conversion */
         StmLF,
         /* a throttle has been set against this path */
         ThrottleSet,
         /* WebDAV (and directory listing) does not display hidden files */
         WebDavNoHidden,
         /* WebDAV methods do not allow/apply locking to this path */
         WebDavNoLock,
         /* WebDAV methods access according to SYSUAF profile */
         WebDavProfile,
         /* WebDAV methods do not allow/apply property(ies) to this path */
         WebDavNoProp,
         /* to PUT on this path you need a compatible WebDAV lock */
         WebDavPutLock,
         /* WebDAV methods allowed to read from this path */
         WebDavRead,
         /* WebDAV methods access as server account (best effort) */
         WebDavServer,
         /* if true emulate windows properties */
         WebDavNoWinProp,
         /* WebDAV methods allowed to write to this path */
         WebDavWrite;

   int  /* per-path config equivalent */
        AuthRevalidateTimeout,
        /* entry expires after this many seconds or day/hour/minute */
        CacheExpiresAfter,
        /* prevents a cache entry being immediately reloaded */
        CacheGuardSeconds,
        /* use this as the maximum allowed size to be cached */
        CacheMaxKBytes,
        /* client IP address has been substituted */
        ClientAddress,
        /* CORS */
        CorsMaxAge,
        /* directory listing top and bottom delimiter */
        DirDelimit,
        /* directory listing font monospace (D) or inherit */
        DirFont,
        /* style of directory listing */
        DirStyle,
        /* directory listing title */
        DirTitle,
        /* if a string literal */
        DirTitleLength,
        /* index of number of versions of each file */
        DirVersionsOf,
        /* per-path number of concurrent streams */
        Http2MaxStreams,
        /* send an HTTP/2 go-away frame */
        Http2SendGoAway,
        /* response data written at high, normal or low priority */
        Http2WriteQueue,
        /* send an HTTP/2 rst_stream frame */
        Http2SendReset,
        /* on-disk name encoding */
        OdsName,
        /* ODS-2, ODS-5, SRI, PATHWORKS, Advanced Server file name munging */
        PathOds,
        /* proxy service's proxy server port */
        ProxyChainPort,
        /* proxy "Forwarded: by" */
        ProxyForwardedBy,
        /* proxy "X-Forwarded-For:" */
        ProxyXForwardedFor,
        /* proxy header remove/modify */
        ProxyHeaderCount,
        /* */
        ProxyTunnelRequestLength,
        /* overrides global configuration directive */
        PutRFM,
        /* overrides global configuration directive */
        PutMaxKbytes,
        /* allows setting the syntax of the regular expression parser */
        RegexSyntax,
        /* report bad request as this status code */
        Report400as,
        /* report forbidden as this status code */
        Report403as,
        /* report not found as this status code */
        Report404as,
        /* raw, basic or detailed report */
        ReportType,
        /* transform an HTTP 200 status to 203 for log analysis */
        Response200is203,
        /* length of Content Security Policy header */
        ResponseCspLength,
        /* length of Content Security Policy Report Only header */
        ResponseCsproLength,
        /* length of additional response header fields */
        ResponseHeaderAddLength,
        /* variable record appended carriage control */
        ResponseVarRecord,
        /* gzip compress response body flag */
        ResponseGzip,
        /* per-path config equivalent */
        ScriptBitBucketTimeout,
        /* length of script activating command */
        ScriptCommandLength,
        /* CPU limit of script */
        ScriptCpuMax,
        /* CGI zombie or CGIplus lifetime */
        ScriptLifeTime,
        /* length of "(name=value[,name=value])" non-CGI variables */
        ScriptParamsLength,
        /* length of 'ssi=exec=' */
        SsiExecLength,
        /* SSL CGI variables */
        SSLCGIvar,
        /* index into array of lists of throttled requests */
        ThrottleIndex,
        /* absolute maximum requests before 503 "busy" */
        ThrottleBusy,
        /* concurrent requests before queueing */
        ThrottleFrom,
        /* a per-user throttle has been set */
        ThrottlePerUser,
        /* concurrent requests after which FIFOing ceases */
        ThrottleResume,
        /* concurrent requests before FIFO processing */
        ThrottleTo,
        /* seconds before queued request is terminated */
        ThrottleTimeoutBusy,
        /* seconds before queued request is set to processing */
        ThrottleTimeoutQueue,
        /* per-path config equivalent */
        TimeoutNoProgress,
        /* per-path config equivalent */
        TimeoutOutput,
        /* per-path config equivalent */
        TimeoutPersistent,
        /* self-explanatory */
        WebDavLockTimeoutDefault,
        /* self-explanatory */
        WebDavLockTimeoutMax,
        /* WebSocket input mailbox size */
        WebSocketInputSize,
        /* WebSocket output mailbox size */
        WebSocketOutputSize;

   char  /* if non-zero then attempt to resolve a language-specific file */
         AcceptLangChar;
         
   char  /* default language of files in path */
         *AcceptLangPtr,
         /* redirection URL if VMS-authenticated password is expired */
         *AuthSysUafPwdExpUrlPtr,
         /* associate path with a CGI variable prefix */
         *CgiPrefixPtr,
         /* move request to this service (when mapping concluded) */
         *ChangeServicePtr,
         /* associate path with a specific charset */
         *CharsetPtr,
         /* really just for ease of testing */
         *ClientAddressLiteralPtr,
         /* associate path with a specific content-type */
         *ContentTypePtr,
         /* CORS */
         *CorsAllowHeadersPtr,
         /* CORS */
         *CorsAllowMethodsPtr,
         /* CORS */
         *CorsAllowOriginPtr,
         /* CORS */
         *CorsExposeHeadersPtr,
         /* associate directory listing with a specific charset */
         *DirCharsetPtr,
         /* null-terminated string (e.g. "_blank") */
         *DirTargetPtr,
         /* one of more null-terminated strings */
         *DirThesePtr,
         /* null-terminated string literal */
         *DirTitlePtr,
         /* document root */
         *MapRootPtr,
         /* page formatting */
         *HtmlBodyTagPtr,
         /* page footer formatting */
         *HtmlFooterPtr,
         /* page footer formatting */
         *HtmlFooterTagPtr,
         /* page header formatting */
         *HtmlHeaderPtr,
         /* page header formatting */
         *HtmlHeaderTagPtr,
         /* associate path with a "Index of" format */
         *IndexPtr,
         /* string with down-stream <username>:<password> credentials */
         *ProxyChainCredPtr,
         /* string with host name and port */
         *ProxyChainHostPortPtr,
         /* when reverse proxying rewrites any 302 "Location:" URL */
         *ProxyReverseLocationPtr,
         /* inject this "request" into a proxy tunnel stream */
         *ProxyTunnelRequestPtr,
         /* Content Security Policy header */
         *ResponseCspPtr,
         /* Content Security Policy Report Only header */
         *ResponseCsproPtr,
         /* list of additional response header fields */
         *ResponseHeaderAddPtr,
         /* value of Strict-Transport-Security: field */
         *ResponseStrictTransSecPtr,
         /* the username the agent should execute under */
         *ScriptAgentAsPtr,
         /* the username the script should execute under */
         *ScriptAsPtr,
         /* script activating command and/or qualifiers and/or parameters */
         *ScriptCommandPtr,
         /* eqivalent of "Script-Control: <...>" in CGI response header */
         *ScriptControlPtr,
         /* script default directory */
         *ScriptDefaultPtr,
         /* a list of "(name=value[,name=value])" non-CGI variables */
         *ScriptParamsPtr,
         /* string containing allowed SSI #exec commands */
         *SsiExecPtr,
         /* URL for CSS to load */
         *StyleSheetPtr,
         /* directory to store WebDAV meta files */
         *WebDavMetaDirPtr;

   char  /* proxy header remove/modify */
         *ProxyHeader [MAPURL_PROXY_HEADER_MAX];

   char  /* CGIPLUSIN records have explicit <LF>, <CR>, or <CR><LF> added */
         CgiPlusInCC [4],
         /* sort columns and direction */
         DirSort [2+1];

   IPADDRESS  /* the proxy outgoing IP address has been set */
              ProxyBindIpAddress,
              /* proxy service's proxy server */
              ProxyChainIpAddress;
};

/********************/
/* request response */
/********************/

typedef struct RequestResponseStruct RESPONSE_STRUCT;

struct  RequestResponseStruct
{
   BOOL  /* the response body is being ZLIB compressed */
         ContentEncodeAsGzip,
         /* the response body is already ZLIB compressed */
         ContentIsEncodedGzip,
         /* the response body is already encoded un an unrecognised way */
         ContentIsEncodedUnknown,
         /* report any errors using the error report script */
         ErrorReportByRedirect,
         /* response header has been generated */
         HeaderGenerated,
         /* response header has been sent to client */
         HeaderSent,
         /* the response body is NOT to be chunked */
         NoChunked,
         /* the response body is NOT to be ZLIB compressed (e.g. TRACE) */
         NoGzip,
         /* response include an "Expires:" the same as "Last-Modified:" */
         PreExpired,
         /* interal error - respond with a canned 500 header */
         Internal500,
         /* response body is being chunked */
         TransferEncodingChunked;

   int  /* character set length */
        CharsetLength,
        /* NCS conversion buffer size */
        CharsetNcsBufferSize,
        /* the output buffer need to be this many time bigger than input */
        CharsetNcsCfFactor,
        /* length of chunk (including hex size and carriage control) */
        ChunkedLength,
        /* size of the currently allocated chunk buffer */
        ChunkedBufferSize,
        /* from generated response headers (if specified) */
        ContentLength,
        /* buffer for header append length */
        HeaderAppendLength,
        /* buffer for data length */
        HeaderDataLength,
        /* used during HEAD method to determine when header ends */
        HeaderNewlineCount,
        /* response header status has been set */
        HeaderStatus,
        /* numeric equivalent of the "200", "302", etc., HTTP status code */
        HttpStatus,
        /* value representation of response HTTP protocol version number */
        HttpVersion,
        /* length of error report text/query-string */
        ErrorReportLength,
        /* current buffer count for request rebuilt from callout */
        RedactBufferCount,
        /* current buffer size for request rebuilt from callout */
        RedactBufferSize;

   ulong  /* NCS conversion function */
          CharsetNcsCf;

   ulong  /* response duration */
          Duration [QUAD2];

   char  /* NCS conversion buffer */
         *CharsetNcsBufferPtr,
         /* point to currently allocated chunk buffer */
         *ChunkedBufferPtr,
         /* from generated headers and CGI responses */
         *ContentTypePtr,
         /* "Cookie:" response header array */
         *CookiePtr [RESPONSE_COOKIE_MAX],
         /* buffer for data pointer */
         *HeaderDataPtr,
         /* pointer to heap storage of redirection location path */
         *LocationPtr,
         /* pointer to other info when generating error report */
         *ErrorOtherTextPtr,
         /* pointer to error text/query-string */
         *ErrorReportPtr,
         /* pointer to explanation when generating error report */
         *ErrorTextPtr,
         /* message character set */
         *MsgCharsetPtr,
         /* pointer to boundary string */
         *MultipartBoundaryPtr,
         /* buffer to contain request being rebuilt from callout */
         *RedactBufferPtr;

   char  /* buffer to contain hex chunk size string */
         ChunkedSizeString [8],
         /* HTTP/1.1 entity tag */
         EntityTag [ENTITY_TAG_MAX+1];

   /* item list descriptors used for chunked buffer list */
   VMS_ITEM_LIST2  ChunkedP5 [4];

   /* AST function pointers */
   REQUEST_AST  HeaderAstFunction;
};

/************************/
/* request time storage */
/************************/

typedef struct RequestTimeStruct TIME_STRUCT;

struct  RequestTimeStruct
{
   ulong  /* start of request processing */
          BeginTime64 [QUAD2],
          /* time from "If-Modified-Since:" header */
          IfModifiedSinceTime64 [QUAD2],
          /* time from "If-Range:" header */
          IfRangeBeginTime64 [QUAD2],
          /* time from "If-UnModified-Since:" header */
          IfUnModifiedSinceTime64 [QUAD2];

   ushort  /* component equivalent of 'BeginTime64' */
           BeginNumTime [7];

   char  /* GMT-adjusted string equivalent of 'BeginTime64' */
         GmDateTime [48];
};

/******************/
/* request timers */
/******************/

typedef struct RequestTimrStruct TIMR_STRUCT;

/* must be located in the non-zeroed portion of the request stucture! */
struct  RequestTimrStruct
{
   LIST_ENTRY  ListEntry;

   int  /* counter for input timeout */
        InputSecond,
        /* index into 5, 15, 60, 300, 300+ (etc.) second queues */
        ListIndex,
        /* previous Rx bytes for output no-progress checking */
        NoProgressBytesRx,
        /* previous Tx bytes for output no-progress checking */
        NoProgressBytesTx,
        /* counter for output no-progress */
        NoProgressSecond,
        /* storage for server value (WATCH must be able to manipulate this) */
        NoProgressPeriod,
        /* counter for output timeout */
        OutputSecond,
        /* counter for persistent connection timeout */
        PersistentSecond,
        /* counter for imediate termination */
        TerminateSecond,
        /* counter for throttle timeout */
        ThrottleSecond,
        /* supervisor timer has expired */
        TimeoutCount,
        /* contains TIMEOUT_.. value to indicate type of timeout */
        TimeoutType;
};

/**************/
/* web socket */
/**************/

typedef struct RequestWebSocketStruct WEBSOCKET_STRUCT;

struct  RequestWebSocketStruct
{
   LIST_ENTRY  WebSockListEntry;

   REQUEST_STRUCT  *RequestPtr;

   BOOL  CalloutInProgress,
         RawSocket;

   int  InOutCount,
        InputSize,
        OutputSize,
        QueuedInput,
        QueuedNetRead,
        QueuedNetWrite,
        QueuedOutput;

   ushort  InputChannel,
           OutputChannel;

   ulong  ScriptProcessPid;

   char  *InputPtr,
         *OutputPtr;

   char  InputDevName [DCL_MAILBOX_DEVNAM_MAX+1],
         OutputDevName [DCL_MAILBOX_DEVNAM_MAX+1],
         Utf8Char [4];

   struct dsc$descriptor_s  InputDevNameDsc;
   struct dsc$descriptor_s  OutputDevNameDsc;

   IO_SB  CalloutIOsb,
          InputIOsb,
          OutputIOsb;
};

/******************************/
/* per-request data structure */
/******************************/

typedef struct RequestStruct REQUEST_STRUCT;

struct RequestStruct
{
   /***************************/
   /* general purpose storage */
   /***************************/

   /*
      Storage areas at the beginning of this structure, specifically
      above the field 'RetainAboveZeroBelow', are retained between
      successive requests during persistent connections.
      When a "keep-alive" connection is reinitialized ready for a
      potential new request all of this structure below (and including)
      that field are zeroed, effectively allowing a new request.
   */

   /* for maintaining the list of request structures */
   LIST_ENTRY  ListEntry;

   /* zone ID for request heap's virtual memory management */
   ulong  VmHeapZoneId;

   /* network parameters, request timer data, etc */
   NET_STRUCT           rqNet;
   TIMR_STRUCT          rqTmr;
   HTTP2_STREAM_STRUCT  Http2Stream;

   /* pointer to network I/O structure */
   NETIO_STRUCT  *NetIoPtr;

   /* pointer to service structure of host/port etc of service connected to */
   SERVICE_STRUCT  *ServicePtr,
                   *ServiceBeforeChangePtr;

   /* generally points at the local client data but can be re-pointed */
   CLIENT_STRUCT  *ClientPtr,
                  *ClientResetPtr;

   /* the request has an AST in progress */
   REQUEST_AST  AstFunction;

   BOOL  /* redirect for request X-ray purposes */
         RedirectedXray;

   int  /* to prevent consecutive auth revalidation 401s */
        AuthRevalidateCount,
        /* server number of IP accept() and request creation */
        ConnectNumber,
        /* avoid redirection loops by keeping track of the number */
        KeywordRedirectCount,
        /* HTTP 1 or 2 for the request network communication */
        NetworkHttp,
        /* avoid redirection loops by keeping track of the number */
        RedirectCount,
        /* an error is being reported from a redirect path */
        RedirectErrorStatusCode,
        /* number of time redact has been attempted to be used */
        RedactCount,
        /* see REQUEST_STATE_.. in request.h */
        RequestState,
        /* request is being WATCHed */
        WatchItem;

   char  /* notepad is persistent */
         *NotePadPtr,
         /* location rewrite storage is persistent */
         *ProxyReverseLocationPtr,
         /* when redirecting this points to any current authentication realm */
         *RedirectErrorAuthRealmDescrPtr;

   /* request dictionary */
   DICT_STRUCT  *rqDictPtr;

   /* for speedy access to the notepad entry */
   DICT_ENTRY_STRUCT  *NotePadDictEntry;

   /* the rest of this structure will be zeroed with a persistent connection */
   /******************/
    ulong  ZeroedBegin;
   /******************/

   BOOL  /* "temporary" file, delete it on close */
         DeleteOnClose,
         /* request handled internally by the server */
         InternalRequest,
         /* true if a mapping rule identifies this as a "CGIplus" script */
         IsCgiPlusScript,
         /* do not get the response from cache */
         NotFromCache,
         /* extended file specifications to be used on this path */
         PathOdsExtended,
         /* this request is using a persistent network connection */
         PersistentRequest,
         /* the response is to be made expecting a persistent connection */
         PersistentResponse,
         /* proxy request (e.g. "http://...", "ftp://...") */
         ProxyRequest,
         /* proxy tunnel (only for accounting purposes) */
         ProxyTunnelRequest,
         /* lot like a WebSocket request only different (see WEBSOCK.C) */
         RawSocketRequest,
         /* the virtual service specific in the request was unknown */
         UnknownVirtualService,
         /* WebDAV method detected */
         WebDavMethod,
         /* request has a WebDAV method or a specific request header field */
         WebDavRequest,
         /* as the name suggests... */
         WebSocketRequest,
         /* though not definitively WebDAV it still smells like it */
         WhiffOfWebDav,
         /* a client certificate is required by the meta config */
         X509ClientCertMeta;

   int  /* counter representing request activity has been incremented */
        AccountingDone,
        /* bytes rx plus tx divided by the duration of the request */
        BytesPerSecond,
        /* percentage of original size for GZIPed response */
        BytesTxGzipPercent,
        /* length of configuration directory */
        ConfigDirectoryLength,
        /* size of buffer space for sys$output from DCL subprocess */
        DclSysOutputSize,
        /* used as temporary storage for ZLIB memory management accounting */
        GzipMemoryAllocated,
        /* when trying home pages this returns the VMS status */
        HomePageStatus,
        /* length of mapped path */
        MappedPathLength,
        /* pass through rules (mapping rules, 1 or 2) */
        MetaConPass,
        /* prevent runaway restarts through rules */
        MetaConRestartCount,
        /* integer representing prefered message language */
        MsgLanguage,
        /* on-disk file naming specification */
        PathOds,
        /* local port from outgoing proxy connection (logging purposes only) */
        ProxyLocalPort,
        /* length of remote user name */
        RemoteUserLength,
        /* count of home page file names tried */
        RequestHomePageIndex;

   ulong  /* count of REQUEST-RELATED bytes received from the client */
          BytesRx [QUAD2],
          /* count of REQUEST-RELATED bytes sent to the client */
          BytesTx [QUAD2];

   char  /* buffer space for sys$output from DCL subprocess */
         *DclSysOutputPtr,
         /* pointer to mapped path */
         *MappedPathPtr,
         /* pointer to (being) mapped path (during mapping rule processing) */
         *MetaConMappedPtr,
         /* pointer to script name (during mapping rule processing) */
         *MetaConScriptPtr;

   char  /* source of configuration information */
         ConfigDirectory [METACON_CONFIG_DIR_LENGTH+1],
         /* authenticated user name from "Authorization:" */
         RemoteUser [AUTH_MAX_USERNAME_LENGTH+1],
         /* storage when authenticating remote user */
         RemoteUserPassword [AUTH_MAX_PASSWORD_LENGTH+1],
         /* file mapped from path to specification */
         RequestMappedFile [ODS_MAX_FILE_NAME_LENGTH+1],
         /* run-time mapped from rules */
         RequestMappedRunTime [ODS_MAX_FILE_NAME_LENGTH+1],
         /* script mapped from path to specification */
         RequestMappedScript [ODS_MAX_FILE_NAME_LENGTH+1],
         /* mapped script name */
         ScriptName [SCRIPT_NAME_SIZE+1];

   /* descriptor-associated storage for when NewWriteBuffered() */
   BOOL  NetWriteEscapeHtml,
         NetWriteFlushOnly;
   int  NetWriteBufferCount;
   STR_DSC  NetWriteBufferDsc;
   REQUEST_AST  NetWriteAstFunction;

   /* MD5 hash of mapped path */
   MD5_HASH  Md5HashPath;

   /* structures containing specific request storage */
   struct  RequestHeaderStruct         rqHeader;
   struct  RequestBodyStruct           rqBody;
   struct  RequestAuthorizationStruct  rqAuth;
   struct  RequestCacheStruct          rqCache;
   struct  RequestCgiStruct            rqCgi;
   struct  RequestPathSetStruct        rqPathSet;
   struct  RequestResponseStruct       rqResponse;
   struct  RequestTimeStruct           rqTime;
   struct  RequestWebSocketStruct      rqWebSocket;
   struct  ContentTypeStruct           rqContentInfo;

   /* when a path is throttled this will be in the active or waiting list */
   LIST_ENTRY  ThrottleListEntry;
   BOOL  ThrottlePerUser;

/* include to get the GZIP_COMPRESS structure */
#define GZIP_COMPRESS_ONLY
#include "gzip.h"
#undef GZIP_COMPRESS_ONLY

   GZIP_COMPRESS  GzipCompress;

   FILE_CONTENT   *FileContentPtr;
   ODS_STRUCT     ParseOds;

   /**************/
   /* task lists */
   /**************/

   /* these two modules can have multiple, concurrent instances */
   LIST_HEAD     DirTaskList,
                 SsiTaskList;

   /* these modules/tasks can only have one total or multiple serially */
   ADMIN_TASK    *AdminTaskPtr;
   DCL_TASK      *DclTaskPtr;
   DECNET_TASK   *DECnetTaskPtr;
   DESCR_TASK    *DescrTaskPtr;
   DIR_TASK      *DirTaskPtr;
   FILE_TASK     *FileTaskPtr;
   HISS_TASK     *HissTaskPtr;
   HTADMIN_TASK  *HTAdminTaskPtr;
   PROXY_TASK    *ProxyTaskPtr;
   PUT_TASK      *PutTaskPtr;
   SSI_TASK      *SsiTaskPtr;
   STREAM_TASK   *StreamTaskPtr;
   TRACE_TASK    *TraceTaskPtr;
   UPD_TASK      *UpdTaskPtr;
   WEBDAV_TASK   *WebDavTaskPtr;

   /*****************/
    ulong  ZeroedEnd;
   /*****************/

};

#ifndef __VAX
#   pragma member_alignment __restore
#endif

#endif /* WASD_H_LOADED */

/*****************************************************************************/
