[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#1063417: bookworm-pu: package libapache2-mod-qos/11.74-1+deb12u1



Package: release.debian.org
Severity: normal
Tags: bookworm
User: release.debian.org@packages.debian.org
Usertags: pu
X-Debbugs-Cc: packages@qa.debian.org
Control: affects -1 + src:libapache2-mod-qos

Please update libapache2-mod-qos from 11.63 to 11.74 in bookworm.

[ Reason ]
The Apache2 module mod_qos in bookworm not useable out-of-the-box. If package is installed and the module is enabled, the httpd daemon is not able to start and throws an error: "[…] mod_qos.so: undefined symbol: pcre_free […]"

This bug has been reported as #1000072.

[ Impact ]
Breaks Apache2 in installations upgrading from bullseye to bookworm. Users must then choose between manually disabling the module or uninstall the package completely.

[ Tests ]
I have tested mod_qos 11.74-1 on my own system and it works without issue and without the need to update any configuration settings.

[ Risks ]
It's possible that mod_qos implements some incompatible configuration changes which might require the user to make updates to their Apache2 configs. However, even in this case, such an outcome is arguably more desirable than a fully broken module.
diff -Nru libapache2-mod-qos-11.63/apache2/mod_qos.c libapache2-mod-qos-11.74/apache2/mod_qos.c
--- libapache2-mod-qos-11.63/apache2/mod_qos.c	2019-05-25 09:08:59.000000000 -0400
+++ libapache2-mod-qos-11.74/apache2/mod_qos.c	2023-05-18 08:34:25.000000000 -0400
@@ -13,14 +13,14 @@
  * different priority to different requests.
  *
  * mod_qos requires OpenSSL, PCRE, threading and shared memory
- * support. It has been developed and fully tested for Apache
- * httpd version 2.2 MPM worker binaries and is optimized to be
- * used in a reverse proxy.
+ * support. It has been designed, developed and fully 
+ * tested for Apache httpd MPM worker binaries and it is optimized
+ * to be used in a reverse proxy.
  *
  * See http://mod-qos.sourceforge.net/ for further
- * details and to optain the latest version of this module.
+ * details and to obtain the latest version of this module.
  *
- * Copyright (C) 2019 Pascal Buchbinder
+ * Copyright (C) 2023 Pascal Buchbinder
  *
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -42,8 +42,8 @@
 /************************************************************************
  * Version
  ***********************************************************************/
-static const char revision[] = "$Id: mod_qos.c 2554 2019-05-23 19:53:33Z pbuchbinder $";
-static const char g_revision[] = "11.63";
+static const char revision[] = "$Id: mod_qos.c 2706 2023-05-16 19:52:59Z pbuchbinder $";
+static const char g_revision[] = "11.74";
 
 /************************************************************************
  * Includes
@@ -51,8 +51,16 @@
 /* std */
 #include <ctype.h>
 #include <time.h>
-#include <arpa/inet.h>
-#include <unistd.h>
+
+#ifndef WIN32
+#    include <arpa/inet.h>
+#    include <unistd.h>
+#else
+#    include <ws2tcpip.h>
+#    include <windows.h>
+#    include <direct.h>
+#endif
+
 #include <stdlib.h>
 
 // for socket options
@@ -75,10 +83,11 @@
 #include <ap_mpm.h>
 #include <scoreboard.h>
 #include <ap_config.h>
+#include <ap_regex.h>
 #include <mpm_common.h>
+#include <util_md5.h>
 
 /* apr / scrlib */
-#include <pcre.h>
 #include <apr_strings.h>
 #include <apr_file_info.h>
 #include <apr_base64.h>
@@ -193,7 +202,6 @@
 #define QS_EMPTY_CON      "NullConnection"
 #define QS_BROKEN_CON     "BrokenConnection"
 #define QS_RuleId         "QS_RuleId"
-#define QS_MFILE          "/var/tmp/"
 
 // enable connection counter if one of the following feature is used
 #define QS_COUNT_CONNECTIONS(sconf) (sconf->max_conn != -1) || \
@@ -246,12 +254,6 @@
 #define QS_REQ_RATE_TM    5
 #endif
 
-/* Preprocessor Definitions
- * match_limt for PCRE extra limits in study() */
-#ifndef QS_EXTRA_MATCH_LIMIT
-#define QS_EXTRA_MATCH_LIMIT 1500
-#endif
-
 #define QS_MAX_DELAY 5000000
 
 #define QOS_DEC_MODE_FLAGS_URL        0x00
@@ -277,12 +279,19 @@
 #endif
 #define QOS_CC_BEHAVIOR_TOLERANCE_STR "20"
 
+/* Apache 2.2 testing needs patch in util_pcre.c line 134 as it does not know AP_REG_DOTALL
+ * Add:
+ *  if ((cflags & 0x40) != 0) options |= 0x04; */
+#ifndef AP_REG_DOTALL
+#define AP_REG_DOTALL                 0x40
+#endif
+
 #define QS_ERR_TIME_FORMAT "%a %b %d %H:%M:%S %Y"
 
 #define QSMOD 4
 #define QOS_DELIM ";"
 
-// Apache 2.4 compat (experimental)
+// Apache 2.4 compat
 #if (AP_SERVER_MINORVERSION_NUMBER == 4)
 #define QS_APACHE_24 1
 #if (AP_SERVER_PATCHLEVEL_NUMBER > 17)
@@ -298,7 +307,6 @@
 #define qos_unixd_set_global_mutex_perms ap_unixd_set_global_mutex_perms
 #define QS_ISDEBUG(s) APLOG_IS_LEVEL(s, APLOG_DEBUG)
 #else
-#define QS_APACHE_22 1
 #define QS_CONN_REMOTEIP(c) c->remote_ip
 #define QS_CONN_REMOTEADDR(c) c->remote_addr
 #define QS_CONN_MASTER(c) (c)
@@ -323,11 +331,7 @@
  ***********************************************************************/
 typedef struct {
   const char *name;             /* variable name */
-#ifdef AP_REGEX_H
   ap_regex_t *preg;
-#else
-  regex_t *preg;
-#endif
   const char *url;              /* redirect url */
   int code;
 } qos_redirectif_entry_t;
@@ -391,21 +395,17 @@
 };
 
 typedef struct {
-  short int limit;
+  unsigned short int limit;
   time_t limitTime;
 } qos_s_entry_limit_t;
 
 typedef struct {
-  short int limit;
+  unsigned short int limit;
   time_t limitTime;
   const char *eventClearStr; // name of the var clearing the counter
   const char *eventDecStr; // name of the var decrementing the counter
   const char *condStr;
-#ifdef AP_REGEX_H
   ap_regex_t *preg;
-#else
-  regex_t *preg;
-#endif
 } qos_s_entry_limit_conf_t;
 
 typedef struct {
@@ -425,7 +425,7 @@
   /* prefer */
   short int vip;
   /* ev block */
-  short int block;
+  unsigned short int block;
   short int blockMsg;
   time_t time;
   time_t blockTime;
@@ -535,33 +535,19 @@
 typedef struct {
   char *variable1;
   char *variable2;
-#ifdef AP_REGEX_H
   ap_regex_t *preg;
-#else
-  regex_t *preg;
-#endif
   char *name;
   char *value;
 } qos_setenvif_t;
 
 typedef struct {
-#ifdef AP_REGEX_H
   ap_regex_t *preg;
-#else
-  regex_t *preg;
-#endif
   char *name;
   char *value;
 } qos_setenvifquery_t;
 
 typedef struct {
-  pcre *preg;
-  pcre_extra *extra;
-#ifdef AP_REGEX_H
   ap_regex_t *pregx;
-#else
-  regex_t *pregx;
-#endif  
   char *name;
   char *value;
 } qos_setenvifparpbody_t;
@@ -570,8 +556,7 @@
  * generic request filter
  */
 typedef struct {
-  pcre *pr;
-  pcre_extra *extra;
+  ap_regex_t *preg;
   char *text;
   char *id;
   qs_rfilter_type_e type;
@@ -631,11 +616,7 @@
   time_t limitTime;  // timer
   qs_event_action_e action;
   const char *condStr;
-#ifdef AP_REGEX_H
   ap_regex_t *preg;
-#else
-  regex_t *preg;
-#endif
 } qos_event_limit_entry_t;
 
 /** 
@@ -649,15 +630,9 @@
   char *url;
   int url_len;
   char *event;
-#ifdef AP_REGEX_H
   ap_regex_t *regex;
   ap_regex_t *regex_var;
   ap_regex_t *condition;
-#else
-  regex_t *regex;
-  regex_t *regex_var;
-  regex_t *condition;
-#endif
   int counter;
   int limit;
   /* measurement */
@@ -742,7 +717,7 @@
   int decodings; 
   apr_table_t *disable_reqrate_events;
   apr_table_t *setenvstatus_t;
-  apr_table_t *setenvif_t;
+  apr_array_header_t *setenvif_t;
   apr_table_t *setenvifquery_t;
   apr_array_header_t* setenvcmp;
 } qos_dir_config;
@@ -754,7 +729,6 @@
   apr_pool_t *pool;
   int is_virtual;
   server_rec *base_server;
-  const char *chroot;
   char *mfile;
   qs_actable_t *act;
   const char *error_page;
@@ -764,7 +738,7 @@
   apr_table_t *setreqheaderlate_t;
   apr_table_t *unsetresheader_t;
   apr_table_t *unsetreqheader_t;
-  apr_table_t *setenvif_t;
+  apr_array_header_t *setenvif_t;
   apr_table_t *setenvifquery_t;
   apr_table_t *setenvifparp_t;
   apr_table_t *setenvifparpbody_t;
@@ -789,19 +763,11 @@
   int keyset;
   char *header_name;
   int header_name_drop;
-#ifdef AP_REGEX_H
   ap_regex_t *header_name_regex;
-#else
-  regex_t *header_name_regex;
-#endif
   apr_table_t *disable_reqrate_events;
   char *ip_header_name;
   int ip_header_name_drop;
-#ifdef AP_REGEX_H
   ap_regex_t *ip_header_name_regex;
-#else
-  regex_t *ip_header_name_regex;
-#endif
   int vip_user;
   int vip_ip_user;
 
@@ -837,8 +803,9 @@
   int enable_testip;
 #endif
   int disable_handler;
-  /* client control */
   int log_only;               /* GLOBAL ONLY */
+  int log_env;
+  /* client control */
   int has_qos_cc;             /* GLOBAL ONLY */
   int qos_cc_size;            /* GLOBAL ONLY */
   int qos_cc_prefer;          /* GLOBAL ONLY */
@@ -859,6 +826,7 @@
   qos_geo_t *geodb;           /* GLOBAL ONLY */
   int geo_limit;              /* GLOBAL ONLY */
   apr_table_t *geo_priv;      /* GLOBAL ONLY */
+  int geo_excludeUnknown;     /* GLOBAL ONLY */
   qs_ip_type_e ip_type;       /* GLOBAL ONLY */
   int qsstatus;               /* GLOBAL ONLY */
   int qsevents;               /* GLOBAL ONLY */
@@ -965,34 +933,22 @@
   char *url;
   char *event;
   int limit;
-#ifdef AP_REGEX_H
-  /* apache 2.2 */
   ap_regex_t *regex;
   ap_regex_t *regex_var;
   ap_regex_t *condition;
-#else
-  /* apache 2.0 */
-  regex_t *regex;
-  regex_t *regex_var;
-  regex_t *condition;
-#endif
   long req_per_sec_limit;
   apr_off_t kbytes_per_sec_limit;
 } qs_rule_ctx_t;
 
 typedef struct {
   const char* name;
-  const char* pcre;
+  const char* pattern;
   qs_flt_action_e action;
   int size;
 } qos_her_t;
 
 typedef struct {
-#ifdef AP_REGEX_H
   ap_regex_t *preg;
-#else
-  regex_t *preg;
-#endif
   char *name;
   char *value;
 } qos_pregval_t;
@@ -1001,15 +957,13 @@
   int num;
   int thinktime;
   const char* pattern;
-  pcre *preg;
-  pcre_extra *extra;
+  ap_regex_t *preg;
   qs_rfilter_action_e action;
 } qos_milestone_t;
 
 typedef struct {
   char *text;
-  pcre *pcre;
-  pcre_extra *extra;
+  ap_regex_t *preg;
   qs_flt_action_e action;
   int size;
 } qos_fhlt_r_t;
@@ -1018,18 +972,22 @@
   apr_time_t request_time;
   unsigned int in_addr;
   unsigned int conn;
-  unsigned int tid;
+#if APR_HAS_THREADS
+  apr_os_thread_t tid;
+#endif
   unsigned int unique_id_counter;
 } qos_unique_id_t;
 
 /************************************************************************
- * globals
+ * Globals
  ***********************************************************************/
 
 module AP_MODULE_DECLARE_DATA qos_module;
+static int m_forced_close = 1;
 static int m_retcode = HTTP_INTERNAL_SERVER_ERROR;
-static int m_worker_mpm = 1; // note: mod_qos is fully tested for Apache 2.2 worker MPM only
+static int m_threaded_mpm = 1; // note: mod_qos is fully tested for Apache 2.2 worker MPM only
 static int m_event_mpm = 0;
+static double m_event_mpm_worker_factor = 2;
 static unsigned int m_hostcode = 0;
 static int m_generation = 0; // parent process (restart generation)
 static int m_qos_cc_partition = QSMOD;
@@ -1060,6 +1018,8 @@
 /* mod_ssl, forward and optional function */
 APR_DECLARE_OPTIONAL_FN(int, ssl_is_https, (conn_rec *));
 static APR_OPTIONAL_FN_TYPE(ssl_is_https) *qos_is_https = NULL;
+APR_DECLARE_OPTIONAL_FN(char *, ssl_var_lookup, (apr_pool_t *, server_rec *, conn_rec *, request_rec *, char *));
+static APR_OPTIONAL_FN_TYPE(ssl_var_lookup) *qos_ssl_var = NULL;
 
 static void qs_inc_eventcounter(apr_pool_t *ppool, int event, int locked);
 #define QS_INC_EVENT(sconf, event) if(sconf->qsevents) qs_inc_eventcounter(sconf->act->ppool, event, 0)
@@ -1070,28 +1030,28 @@
    extensions which are used rarely) */
 /* reserved (to be escaped): {}[]()^$.|*+?\ */
 static const qos_her_t qs_header_rules[] = {
-#define QS_URL_UNRESERVED  "a-zA-Z0-9\\._~% \\-"
-#define QS_URL_GEN         ":/\\?#\\[\\]@"
-#define QS_URL_SUB         "!\\$&'\\(\\)\\*\\+,;="
+#define QS_URL_UNRESERVED  "a-zA-Z0-9._~% -"
+#define QS_URL_GEN         ":/?#\\[\\]@"
+#define QS_URL_SUB         "!$&'()*+,;="
 #define QS_URL             "["QS_URL_GEN""QS_URL_SUB""QS_URL_UNRESERVED"]"
 #define QS_2616TOKEN       "[\\x21\\x23-\\x27\\x2a-\\x2e0-9A-Z\\x5-\\x60a-z\\x7e]+"
-#define QS_B64_SP          "[a-zA-Z0-9 \\+/\\$=:]"
+#define QS_B64_SP          "[a-zA-Z0-9 +/$=:]"
 #define QS_PIPE            "\\|"
 #define QS_WEAK            "(W/)?"
-#define QS_H_ACCEPT        "[a-zA-Z0-9_\\*\\+\\-]+/[a-zA-Z0-9_\\*\\+\\.\\-]+(;[ ]?[a-zA-Z0-9]+=[0-9]+)?[ ]?(;[ ]?q=[0-9\\.]+)?"
-#define QS_H_ACCEPT_C      "[a-zA-Z0-9\\*\\-]+(;[ ]?q=[0-9\\.]+)?"
-#define QS_H_ACCEPT_E      "[a-zA-Z0-9\\*\\-]+(;[ ]?q=[0-9\\.]+)?"
-#define QS_H_ACCEPT_L      "[a-zA-Z\\*\\-]+[0-9]{0,3}(;[ ]?q=[0-9\\.]+)?"
+#define QS_H_ACCEPT        "[a-zA-Z0-9_*+-]+/[a-zA-Z0-9_*+.-]+(;[ ]?[a-zA-Z0-9]+=[0-9]+)?[ ]?(;[ ]?[qv]=[a-z0-9.]+)?"
+#define QS_H_ACCEPT_C      "[a-zA-Z0-9*-]+(;[ ]?q=[0-9.]+)?"
+#define QS_H_ACCEPT_E      "[a-zA-Z0-9*-]+(;[ ]?q=[0-9.]+)?"
+#define QS_H_ACCEPT_L      "[a-zA-Z*-]+[0-9]{0,3}(;[ ]?q=[0-9.]+)?"
 #define QS_H_CACHE         "no-cache|no-store|max-age=[0-9]+|max-stale(=[0-9]+)?|min-fresh=[0-9]+|no-transform|only-if-chached"
-#define QS_H_CONTENT       "[\"a-zA-Z0-9\\*/; =\\-]+"
+#define QS_H_CONTENT       "[\"a-zA-Z0-9*/; =-]+"
 #define QS_H_COOKIE        "["QS_URL_GEN""QS_URL_SUB"\""QS_URL_UNRESERVED"]"
-#define QS_H_EXPECT        "[a-zA-Z0-9= ;\\.,\\-]"
-#define QS_H_PRAGMA        "[a-zA-Z0-9= ;\\.,\\-]"
-#define QS_H_FROM          "[a-zA-Z0-9=@;\\.,\\(\\)\\-]"
-#define QS_H_HOST          "[a-zA-Z0-9\\.\\-]+(:[0-9]+)?"
-#define QS_H_IFMATCH       "[a-zA-Z0-9=@;\\.,\\*\"\\-]"
+#define QS_H_EXPECT        "[a-zA-Z0-9= ;.,-]"
+#define QS_H_PRAGMA        "[a-zA-Z0-9= ;.,-]"
+#define QS_H_FROM          "[a-zA-Z0-9=@;.,()-]"
+#define QS_H_HOST          "[a-zA-Z0-9.-]+(:[0-9]+)?"
+#define QS_H_IFMATCH       "[a-zA-Z0-9=@;.,*\"-]"
 #define QS_H_DATE          "[a-zA-Z0-9 :,]"
-#define QS_H_TE            "[a-zA-Z0-9\\*\\-]+(;[ ]?q=[0-9\\.]+)?"
+#define QS_H_TE            "[a-zA-Z0-9*-]+(;[ ]?q=[0-9.]+)?"
   { "Accept", "^("QS_H_ACCEPT"){1}([ ]?,[ ]?("QS_H_ACCEPT"))*$", QS_FLT_ACTION_DROP, 300 },
   { "Accept-Charset", "^("QS_H_ACCEPT_C"){1}([ ]?,[ ]?("QS_H_ACCEPT_C"))*$", QS_FLT_ACTION_DROP, 300 },
   { "Accept-Encoding", "^("QS_H_ACCEPT_E"){1}([ ]?,[ ]?("QS_H_ACCEPT_E"))*$", QS_FLT_ACTION_DROP, 500 },
@@ -1100,8 +1060,8 @@
   { "Access-Control-Request-Headers", "^([a-zA-Z0-9-]+){1}([ ]?,[ ]?([a-zA-Z0-9-]+))*$", QS_FLT_ACTION_DROP, 500 },
   { "Authorization", "^"QS_B64_SP"+$", QS_FLT_ACTION_DROP, 4000 },
   { "Cache-Control", "^("QS_H_CACHE"){1}([ ]?,[ ]?("QS_H_CACHE"))*$", QS_FLT_ACTION_DROP, 100 },
-  { "Connection", "^([teTE]+,[ ]?)?([a-zA-Z0-9\\-]+){1}([ ]?,[ ]?([teTE]+))?$", QS_FLT_ACTION_DROP, 100 },
-  { "Content-Encoding", "^[a-zA-Z0-9\\-]+(,[ ]*[a-zA-Z0-9\\-]+)*$", QS_FLT_ACTION_DENY, 100 },
+  { "Connection", "^([teTE]+,[ ]?)?([a-zA-Z0-9-]+){1}([ ]?,[ ]?([teTE]+))?$", QS_FLT_ACTION_DROP, 100 },
+  { "Content-Encoding", "^[a-zA-Z0-9-]+(,[ ]*[a-zA-Z0-9-]+)*$", QS_FLT_ACTION_DENY, 100 },
   { "Content-Language", "^([0-9a-zA-Z]{0,8}(-[0-9a-zA-Z]{0,8})*)(,[ ]*([0-9a-zA-Z]{0,8}(-[0-9a-zA-Z]{0,8})*))*$", QS_FLT_ACTION_DROP, 100 },
   { "Content-Length", "^[0-9]+$", QS_FLT_ACTION_DENY, 10 },
   { "Content-Location", "^"QS_URL"+$", QS_FLT_ACTION_DENY, 200 },
@@ -1114,29 +1074,29 @@
   { "Expect", "^"QS_H_EXPECT"+$", QS_FLT_ACTION_DROP, 200 },
   { "From", "^"QS_H_FROM"+$", QS_FLT_ACTION_DROP, 100 },
   { "Host", "^"QS_H_HOST"$", QS_FLT_ACTION_DROP, 100 },
-  { "If-Invalid", "^[a-zA-Z0-9_\\.:;\\(\\) /\\+!\\-]+$", QS_FLT_ACTION_DROP, 500 },
+  { "If-Invalid", "^[a-zA-Z0-9_.:;() /+!-]+$", QS_FLT_ACTION_DROP, 500 },
   { "If-Match", "^"QS_WEAK""QS_H_IFMATCH"+$", QS_FLT_ACTION_DROP, 100 },
   { "If-Modified-Since", "^"QS_H_DATE"+$", QS_FLT_ACTION_DROP, 100 },
   { "If-None-Match", "^"QS_WEAK""QS_H_IFMATCH"+$", QS_FLT_ACTION_DROP, 100 },
   { "If-Range", "^"QS_H_IFMATCH"+$", QS_FLT_ACTION_DROP, 100 },
   { "If-Unmodified-Since", "^"QS_H_DATE"+$", QS_FLT_ACTION_DROP, 100 },
-  { "If-Valid", "^[a-zA-Z0-9_\\.:;\\(\\) /\\+!\\-]+$", QS_FLT_ACTION_DROP, 500 },
+  { "If-Valid", "^[a-zA-Z0-9_.:;() /+!-]+$", QS_FLT_ACTION_DROP, 500 },
   { "Keep-Alive", "^[0-9]+$", QS_FLT_ACTION_DROP, 20 },
   { "Max-Forwards", "^[0-9]+$", QS_FLT_ACTION_DROP, 20 },
   { "Origin", "^"QS_URL"+$", QS_FLT_ACTION_DROP, 2000 },
   { "Proxy-Authorization", "^"QS_B64_SP"+$", QS_FLT_ACTION_DROP, 400 },
   { "Pragma", "^"QS_H_PRAGMA"+$", QS_FLT_ACTION_DROP, 200 },
-  { "Range", "^[a-zA-Z0-9=_\\.:;\\(\\) /\\+!\\-]+$", QS_FLT_ACTION_DROP, 200 },
+  { "Range", "^[a-zA-Z0-9=_.:;() /+!-]+$", QS_FLT_ACTION_DROP, 200 },
   { "Referer", "^"QS_URL"+$", QS_FLT_ACTION_DROP, 2000 },
   { "TE", "^("QS_H_TE"){1}([ ]?,[ ]?("QS_H_TE"))*$", QS_FLT_ACTION_DROP, 100 },
   { "Transfer-Encoding", "^(chunked|Chunked|compress|Compress|deflate|Deflate|gzip|Gzip|identity|Identity)([ ]?,[ ]?(chunked|Chunked|compress|Compress|deflate|Deflate|gzip|Gzip|identity|Identity))*$", QS_FLT_ACTION_DENY, 100 },
   { "Unless-Modified-Since", "^"QS_H_DATE"+$", QS_FLT_ACTION_DROP, 100 },
   { "User-Agent", "^[a-zA-Z0-9]+[a-zA-Z0-9_.:;()\\[\\]@ /+!=,-]+$", QS_FLT_ACTION_DROP, 300 },
   { "Upgrade-Insecure-Requests", "^1$", QS_FLT_ACTION_DROP, 1 },
-  { "Via", "^[a-zA-Z0-9_\\.:;\\(\\) /\\+!\\-]+$", QS_FLT_ACTION_DROP, 100 },
-  { "X-Forwarded-For", "^[a-zA-Z0-9_\\.:\\-]+(, [a-zA-Z0-9_\\.:\\-]+)*$", QS_FLT_ACTION_DROP, 100 },
-  { "X-Forwarded-Host", "^[a-zA-Z0-9_\\.:\\-]+$", QS_FLT_ACTION_DROP, 100 },
-  { "X-Forwarded-Server", "^[a-zA-Z0-9_\\.:\\-]+$", QS_FLT_ACTION_DROP, 100 },
+  { "Via", "^[a-zA-Z0-9_.:;() /+!-]+$", QS_FLT_ACTION_DROP, 100 },
+  { "X-Forwarded-For", "^[a-zA-Z0-9_.:-]+(, [a-zA-Z0-9_.:-]+)*$", QS_FLT_ACTION_DROP, 100 },
+  { "X-Forwarded-Host", "^[a-zA-Z0-9_.:-]+$", QS_FLT_ACTION_DROP, 100 },
+  { "X-Forwarded-Server", "^[a-zA-Z0-9_.:-]+$", QS_FLT_ACTION_DROP, 100 },
   { "X-lori-time-1", "^[0-9]+$", QS_FLT_ACTION_DROP, 20 },
   { "X-Do-Not-Track", "^[0-9]+$", QS_FLT_ACTION_DROP, 20 },
   { NULL, NULL, 0, 0 }
@@ -1193,6 +1153,19 @@
  * private functions
  ***********************************************************************/
 
+static int qos_regexec_len(apr_pool_t *pool, const ap_regex_t *preg,
+                           const char *buff, apr_size_t len) {
+#if (AP_SERVER_MINORVERSION_NUMBER < 4) && defined QS_INTERNAL_TEST
+  // Apache 2.2 is no longer supported (test only)
+  char *data = apr_palloc(pool, len + 1);
+  memcpy(data, buff, len);
+  data[len] = '\0';
+  return ap_regexec(preg, data, 0, NULL, 0); // won't work for null chars!
+#else
+  return ap_regexec_len(preg, buff, len, 0, NULL, 0);
+#endif
+}
+
 /**
  * Converts an ip long array back to a string representation
  *
@@ -1216,7 +1189,7 @@
  * Converts an ip string to long array (128 bit) representation
  *
  * @param src String representation, e.g. 139.12.33.1 or 1::8
- * @param dst Pointer to array of unsigned long (2) (contains "{ 0, 0 }" on errror)
+ * @param dst Pointer to array of unsigned long (2) (contains "{ 0, 0 }" on error)
  * @return 1 on success, 0 on error
  */
 static int qos_ip_str2long(const char *src, apr_uint64_t *dst) {
@@ -1237,41 +1210,7 @@
   return inet_pton(AF_INET6, convert, dst);
 }
 
-/**
- * Studies pcre pattern (for perfomance improvement) and sets match limits.
- * @param pool Pool to allocate structure from (or to register cleanup)
- * @param pc Pattern to study
- * @return extra data
- */
-static pcre_extra *qos_pcre_study(apr_pool_t *pool, pcre *pc) {
-  pcre_extra *extra = NULL;
-#ifdef QOS_EXTRA_USE_PCRE_STUDY
-  const char *errptr = NULL;
-  extra = pcre_study(pc, 0, &errptr);
-#endif
-  if(extra != NULL) {
-    apr_pool_cleanup_register(pool, extra, (int(*)(void*))pcre_free, apr_pool_cleanup_null);
-  } else {
-    extra = apr_pcalloc(pool, sizeof(pcre_extra));
-  }
-#ifdef PCRE_EXTRA_MATCH_LIMIT
-  extra->match_limit = QS_EXTRA_MATCH_LIMIT;
-  extra->flags |= PCRE_EXTRA_MATCH_LIMIT;
-#endif
-#ifdef PCRE_EXTRA_MATCH_LIMIT_RECURSION
-  extra->match_limit_recursion = QS_EXTRA_MATCH_LIMIT;
-  extra->flags |= PCRE_EXTRA_MATCH_LIMIT_RECURSION;
-#endif
-#ifdef PCRE_EXTRA_MATCH_LIMIT_RECURSION
-  extra->match_limit_recursion = QS_EXTRA_MATCH_LIMIT;
-  extra->flags |= PCRE_EXTRA_MATCH_LIMIT_RECURSION;
-#endif
-
-  return extra;
-}
-
-static int qos_encode64_binary(char *encoded, const char *string,
-                               int len) {
+static int qos_encode64_binary(char *encoded, const char *string, int len) {
   int i;
   char *p;
   
@@ -1311,27 +1250,19 @@
  * @return error message (NULL on success)
  */
 static char *qos_load_headerfilter(apr_pool_t *pool, apr_table_t *outHdrFltTable,
-                                   const qos_her_t *hdrFltRuleDefArray
-                                   ) {
-  const char *errptr = NULL;
-  int erroffset;
+                                   const qos_her_t *hdrFltRuleDefArray) {
   const qos_her_t* hdrFltRuleDefEntry;
   for(hdrFltRuleDefEntry = hdrFltRuleDefArray; hdrFltRuleDefEntry->name != NULL ; ++hdrFltRuleDefEntry) {
     qos_fhlt_r_t *hdrFltElement = apr_pcalloc(pool, sizeof(qos_fhlt_r_t));
-    hdrFltElement->text = apr_pstrdup(pool, hdrFltRuleDefEntry->pcre);
-    hdrFltElement->pcre = pcre_compile(hdrFltRuleDefEntry->pcre, PCRE_DOTALL, &errptr, &erroffset, NULL);
+    hdrFltElement->text = apr_pstrdup(pool, hdrFltRuleDefEntry->pattern);
+    hdrFltElement->preg = ap_pregcomp(pool, hdrFltRuleDefEntry->pattern, AP_REG_DOTALL);
     hdrFltElement->action = hdrFltRuleDefEntry->action;
     hdrFltElement->size = hdrFltRuleDefEntry->size;
-    if(hdrFltElement->pcre == NULL) {
-      return apr_psprintf(pool, "could not compile pcre %s at position %d,"
-                          " reason: %s", 
-                          hdrFltRuleDefEntry->name,
-                          erroffset, errptr);
+    if(hdrFltElement->preg == NULL) {
+      return apr_psprintf(pool, "could not compile regular expression '%s' for %s header",
+                          hdrFltElement->text, hdrFltRuleDefEntry->name);
     }
-    hdrFltElement->extra = qos_pcre_study(pool, hdrFltElement->pcre);
     apr_table_setn(outHdrFltTable, hdrFltRuleDefEntry->name, (char *)hdrFltElement);
-    apr_pool_cleanup_register(pool, hdrFltElement->pcre, (int(*)(void*))pcre_free, 
-                              apr_pool_cleanup_null);
   }
   return NULL;
 }
@@ -1340,7 +1271,7 @@
  * Returns string representation of filter type (for logging purposes)
  * @param pool To allocate string
  * @param type Rule type
- * @retrun Name of the directive used to configure the rule
+ * @return Name of the directive used to configure the rule
  */
 static char *qos_rfilter_type2text(apr_pool_t *pool, qs_rfilter_type_e type) {
   if(type == QS_DENY_REQUEST_LINE) return apr_pstrdup(pool, "QS_DenyRequestLine");
@@ -1353,7 +1284,7 @@
 
 /**
  * Sets unique apache instance id (hopefully) to the global m_hostcore variable
- * @param ptemp Pool to allocate memroy from
+ * @param ptemp Pool to allocate memory from
  * @param s Base server record
  */
 static void qos_hostcode(apr_pool_t *ptemp, server_rec *s) {
@@ -1386,17 +1317,23 @@
  * temp file name for the main/virtual serve
  * @param pool Pool to allocate the file name from
  * @param s Server record
- * @return path
+ * @return absolute file name
  */
 static char *qos_tmpnam(apr_pool_t *pool, server_rec *s) {
   qos_srv_config *sconf = (qos_srv_config*)ap_get_module_config(s->module_config, 
                                                                 &qos_module);
-  char *path = QS_MFILE;
-  char *id;
-  char *e;
+  const char *path = NULL;
+  char *ret;
+  char *file;
+  if(apr_temp_dir_get(&path, pool) != APR_SUCCESS) {
+    path = apr_pstrdup(pool, "/var/tmp");
+  }
   if(sconf && sconf->mfile) {
     path = sconf->mfile;
   }
+  ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
+               QOS_LOGD_PFX"temporary directory for semaphores/shared memory: %s"
+               " (use QS_SemMemFile to override it).", path);
   if(s) {
     unsigned int scode = 0;
     char *key = apr_psprintf(pool, "%u%s.%s.%d",
@@ -1410,14 +1347,15 @@
     for(p = key, i = len; i; i--, p++) {
       scode = scode * 33 + *p;
     }
-    id = apr_psprintf(pool, "%s%u", path, scode);
-    
+    file = apr_psprintf(pool, "%u", scode);
   } else {
-    id = apr_psprintf(pool, "%s%u", path, m_hostcode);
+    file = apr_psprintf(pool, "%u", m_hostcode);
   }
-  e = &id[strlen(path)];
-  e[0] += 25; /* non numeric */
-  return id;
+  file[0] += 25; /* non numeric */
+  apr_filepath_merge(&ret, path, file, APR_FILEPATH_NATIVE, pool);
+  ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
+               QOS_LOGD_PFX"temporary file: %s", ret);
+  return ret;
 }
 
 /**
@@ -1640,11 +1578,7 @@
       eventLimitConf->preg = NULL;
       if(src->condStr) {
         eventLimitConf->condStr = apr_pstrdup(pool, src->condStr);
-#ifdef AP_REGEX_H
         eventLimitConf->preg = ap_pregcomp(pool, src->condStr, AP_REG_EXTENDED);
-#else
-        eventLimitConf->preg = ap_pregcomp(pool, src->condStr, REG_EXTENDED);
-#endif
       }
       apr_table_addn(clientDataArray->limitTable, eventName, (char *)eventLimitConf);
     }
@@ -1981,8 +1915,6 @@
     id.in_addr = m_unique_id.in_addr;
 #if APR_HAS_THREADS
     id.tid = apr_os_thread_current();
-#else
-    id.tid = 0;
 #endif
     id.conn = r->connection->id;
     id.unique_id_counter = m_unique_id.unique_id_counter;
@@ -1995,6 +1927,86 @@
   return uid;
 }
 
+static void qos_log_env(request_rec *r, const char *handler) {
+  char *msg = "";
+  int i;
+  apr_table_entry_t *e = (apr_table_entry_t *) apr_table_elts(r->subprocess_env)->elts;
+  for (i = 0; i < apr_table_elts(r->subprocess_env)->nelts; ++i) {
+    msg = apr_psprintf(r->pool, "%s=%s;%s",  e[i].key, e[i].val, msg);
+  }
+  ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, 0, r,
+                QOS_LOG_PFX(210)"ENV %s %s %s", handler, msg, qos_unique_id(r, NULL));
+  return;
+}
+
+static char *qos_ipv6_hash(request_rec *r, const char *var) {
+  char *md = ap_md5_binary(r->pool, (unsigned char *)var, strlen(var));
+  char *hash = apr_pcalloc(r->pool, 64);
+  char *d = hash;
+  int c = 0;
+  while(md[0]) {
+    d[0] = md[0];
+    d++;
+    c++;
+    md++;
+    if(c == 4 && md[0]) {
+      c=0;
+      d[0] = ':';
+      d++;
+    }
+  }
+  d[0] = '\0';
+  return hash;
+}
+
+static const char *qos_forwardedfor_fromHeader(request_rec *r, const char *header) {
+  const char *forwardedfor = apr_table_get(r->headers_in, header);
+  if(forwardedfor == NULL && r->prev) {
+    // internal redirect?
+    forwardedfor = apr_table_get(r->prev->headers_in, header);
+  }
+  if(forwardedfor == NULL && r->main) {
+    // internal redirect?
+    forwardedfor = apr_table_get(r->main->headers_in, header);
+  }
+  return forwardedfor;
+}
+
+static const char *qos_forwardedfor_fromSSL(request_rec *r) {
+  if(qos_ssl_var) {
+    const char *dn = qos_ssl_var(r->pool, r->server, r->connection, r, "SSL_CLIENT_S_DN");
+    const char *issuer = qos_ssl_var(r->pool, r->server, r->connection, r, "SSL_CLIENT_I_DN");
+    char *header = apr_pstrcat(r->pool, dn, issuer, NULL);
+    if(header && header[0]) {
+      return header;
+    }
+  }
+  return NULL;
+}
+
+static const char *qos_pseudoip(request_rec *r, const char *header) {
+  const char *forwardedfor = NULL;
+  if(strcmp("SSL_CLIENT_S_DN", header) == 0) {
+    forwardedfor = qos_forwardedfor_fromSSL(r);
+  } else {
+    forwardedfor = qos_forwardedfor_fromHeader(r, header);
+  }
+  if(forwardedfor && forwardedfor[0]) {
+    return qos_ipv6_hash(r, forwardedfor);
+  }
+  return NULL;
+}
+
+static const char *qos_forwardedfor(request_rec *r, const char *header) {
+  const char *forwardedfor = NULL;
+  if(header[0] == '#') {
+    forwardedfor = qos_pseudoip(r, &header[1]);
+  } else {
+    forwardedfor = qos_forwardedfor_fromHeader(r, header);
+  }
+  return forwardedfor;
+}
+
 /**
  * Returns the client IP, either from the connection
  * of from the forwarded-for header if configured
@@ -2002,7 +2014,7 @@
  * @param r Request to get the IP from the header
  * @param sconf
  * @param cconf (if available) to get the real IP from
- * @param caller Which caller of the methode
+ * @param caller Which caller of the method
  * @param ip6 The client's IP address to be used (pointer to array of unsigned long (2))
  * @return The client's IP address as a string (for logging)
  */
@@ -2011,15 +2023,7 @@
                                     apr_uint64_t *ip6) {
   const char *forwardedForLogIP;
   if(sconf->qos_cc_forwardedfor) {
-    const char *forwardedfor = apr_table_get(r->headers_in, sconf->qos_cc_forwardedfor);
-    if(forwardedfor == NULL && r->prev) {
-      // internal redirect?
-      forwardedfor = apr_table_get(r->prev->headers_in, sconf->qos_cc_forwardedfor);
-    }
-    if(forwardedfor == NULL && r->main) {
-      // internal redirect?
-      forwardedfor = apr_table_get(r->main->headers_in, sconf->qos_cc_forwardedfor);
-    }
+    const char *forwardedfor = qos_forwardedfor(r, sconf->qos_cc_forwardedfor);
     if(forwardedfor) {
       if(qos_ip_str2long(forwardedfor, ip6) == 0) {
         if(apr_table_get(r->notes, "QOS_LOG_PFX069") == NULL) {
@@ -2529,7 +2533,7 @@
   entries = (qos_milestone_t *)sconf->milestones->elts;
   for(i = 0; i < sconf->milestones->nelts; ++i) {
     milestone = &entries[i];
-    if(pcre_exec(milestone->preg, milestone->extra, the_request, the_request_len, 0, 0, NULL, 0) == 0) {
+    if(qos_regexec_len(r->pool, milestone->preg, the_request, the_request_len) == 0) {
       required = milestone->num;
       break;
     }
@@ -2602,7 +2606,7 @@
         char pre = pt[-1];
         if(pre == ' ' ||
            pre == ';') {
-          // @beginnin of a cookie
+          // @beginning of a cookie
           p = pt;
           pt = NULL;
         } else {
@@ -2664,7 +2668,9 @@
   int buf_len = 0;
   unsigned char *buf;
   char *value = qos_get_remove_cookie(r, sconf->cookie_name);
-  if(value == NULL) return 0;
+  if(value == NULL) {
+    return 0;
+  }
   buf_len = qos_decrypt(r, sconf, &buf, value);
   if(buf_len != sizeof(qos_session_t)) {
     ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, 0, r,
@@ -2794,6 +2800,10 @@
   ap_mpm_query(AP_MPMQ_MAX_DAEMONS, &maxDaemons);
   ap_mpm_query(AP_MPMQ_MAX_THREADS, &maxThreads);
   maxClientsCalc = (maxThreads == 0 ? 1 : maxThreads) * (maxDaemons == 0 ? 1 : maxDaemons);
+  if(m_event_mpm) {
+    /* QS_MaxClients = (AsyncRequestWorkerFactor + 1) * MaxRequestWorkers */
+    maxClientsCalc = (m_event_mpm_worker_factor + 1) * maxClientsCalc;
+  }
   if(bsconf->max_clients_conf > 0) {
     maxClients = bsconf->max_clients_conf;
   } else {
@@ -2802,7 +2812,7 @@
   if(maxClients != maxClientsCalc) {
     ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, bs, 
                  QOS_LOG_PFX(007)"calculated MaxClients/MaxRequestWorkers (max connections): %d,"
-                 " applied limit: %d",
+                 " applied limit: %d (QS_MaxClients)",
                  maxClientsCalc, maxClients);
   } else {
     ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, bs, 
@@ -3067,14 +3077,6 @@
   return APR_SUCCESS;
 }
 
-//static apr_status_t qos_cleanup_geodb(void *p) {
-//  qos_geo_t *geodb = p;
-//  if(geodb->data) {
-//    free(geodb->data);
-//  }
-//  return APR_SUCCESS;
-//}
-
 /**
  * Loads the geo database. See QS_GEO_PATTERN about the file format.
  * @param pool To allocate memory from
@@ -3085,13 +3087,8 @@
  */
 static apr_status_t qos_loadgeo(apr_pool_t *pool, qos_geo_t *geodb,
                                 char **msg, int *errors) {
-#ifdef AP_REGEX_H
   ap_regmatch_t ma[AP_MAX_REG_MATCH];
   ap_regex_t *preg;
-#else
-  regmatch_t ma[AP_MAX_REG_MATCH];
-  regex_t *preg;
-#endif
   qos_geo_entry_t *entry = NULL;
   qos_geo_entry_t *last = NULL;
 
@@ -3099,11 +3096,7 @@
   char line[HUGE_STRING_LEN];
   FILE *file;
 
-#ifdef AP_REGEX_H
   preg = ap_pregcomp(pool, QS_GEO_PATTERN, AP_REG_EXTENDED);
-#else
-  preg = ap_pregcomp(pool, QS_GEO_PATTERN, REG_EXTENDED);
-#endif
   if(preg == NULL) {
     // internal error
     *msg = apr_pstrdup(pool, "failed to compile regular"
@@ -3136,7 +3129,6 @@
   }
   
   geodb->size = lines;
-  //geodb->data = calloc(geodb->size, sizeof(qos_geo_entry_t));
   geodb->data = apr_pcalloc(pool, APR_ALIGN_DEFAULT(sizeof(qos_geo_entry_t)) * geodb->size);
 
   // load the file into the memory
@@ -3313,7 +3305,9 @@
       ap_log_error(APLOG_MARK, APLOG_ALERT, 0, sconf->base_server, 
                    QOS_LOG_PFX(035)"QS_SrvMaxConn: no free IP slot available!"
                    " Check log for unclean child exit and consider"
-                   " to do a graceful server restart if this condition persists.");
+                   " to do a graceful server restart if this condition persists."
+                   " You might also increase the number of supported connections"
+                   " using the 'QS_MaxClients' directive.");
       QS_INC_EVENT_LOCKED(sconf, 35);
     }
   }
@@ -3441,13 +3435,15 @@
     c->cs->state = CONN_STATE_LINGER;
   }
   apr_table_set(c->notes, QS_CONN_ABORT, QS_CONN_ABORT);
+  if (m_forced_close == 0) {
+    return DECLINED;
+  }
 
+  //apr_brigade_cleanup(bb);
   APR_BRIGADE_INSERT_HEAD(bb, e);
   e = apr_bucket_flush_create(c->bucket_alloc);
   APR_BRIGADE_INSERT_TAIL(bb, e);
   ap_pass_brigade(c->output_filters, bb);
-  //  e = apr_bucket_flush_create(c->bucket_alloc);
-  //  APR_BRIGADE_INSERT_TAIL(bb, e);
 
 //  if(socket) {
 //    // speed up connection termination
@@ -3566,7 +3562,7 @@
   qs_acentry_t *actEntry = act->entry;
   int match_len = 0;
   while(actEntry) {
-    if((actEntry->event == NULL) && (actEntry->regex == NULL) && (r->parsed_uri.path != NULL)) {
+    if((actEntry->event == NULL) && (actEntry->regex == NULL)) {
       /* per location limitation */
       if(actEntry->url && (strncmp(actEntry->url, r->parsed_uri.path, actEntry->url_len) == 0)) {
         /* best match */
@@ -3949,7 +3945,7 @@
 #endif
         data = copyq;
         if(strlen(data) != len) {
-          *msg = apr_pstrdup(r->pool, "null chracter within data structure in query");
+          *msg = apr_pstrdup(r->pool, "null character within data structure in query");
           return HTTP_BAD_REQUEST;
         }
       } else {
@@ -3962,7 +3958,7 @@
       apr_table_t *tl = apr_table_make(r->pool, 200);
       int rc;
       if(strlen(value) != len) {
-        *msg = apr_pstrdup(r->pool, "null chracter within data structure");
+        *msg = apr_pstrdup(r->pool, "null character within data structure");
         return HTTP_BAD_REQUEST;
       }
       rc = j_val(r->pool, &value, tl, "J", 0);
@@ -3994,7 +3990,7 @@
                              qos_dir_config *dconf) {
   apr_table_entry_t *entry = (apr_table_entry_t *)apr_table_elts(dconf->rfilter_table)->elts;
   int i;
-  char *path = apr_pstrdup(r->pool, r->parsed_uri.path ? r->parsed_uri.path : "");
+  char *path = apr_pstrdup(r->pool, r->parsed_uri.path);
   char *query = NULL;
   char *fragment = NULL;
   char *request_line = apr_pstrdup(r->pool, r->the_request);
@@ -4128,7 +4124,7 @@
       return HTTP_FORBIDDEN;
     }
   }
-  /* process black and white list rules in one loop */
+  /* process deny- and allow- list rules in one loop */
   for(i = 0; i < apr_table_elts(dconf->rfilter_table)->nelts; i++) {
     if(entry[i].key[0] == '+') {
       int deny_rule = 0;
@@ -4136,18 +4132,18 @@
       qos_rfilter_t *rfilter = (qos_rfilter_t *)entry[i].val;
       if(rfilter->type == QS_DENY_REQUEST_LINE) {
         deny_rule = 1;
-        ex = pcre_exec(rfilter->pr, rfilter->extra, request_line, request_line_len, 0, 0, NULL, 0);
+        ex = qos_regexec_len(r->pool, rfilter->preg, request_line, request_line_len);
       } else if(rfilter->type == QS_DENY_PATH) {
         deny_rule = 1;
-        ex = pcre_exec(rfilter->pr, rfilter->extra, path, path_len, 0, 0, NULL, 0);
+        ex = qos_regexec_len(r->pool, rfilter->preg, path, path_len);
       } else if(rfilter->type == QS_DENY_QUERY) {
         deny_rule = 1;
-        ex = pcre_exec(rfilter->pr, rfilter->extra, query, query_len, 0, 0, NULL, 0);
+        ex = qos_regexec_len(r->pool, rfilter->preg, query, query_len);
       } else if(rfilter->type == QS_DENY_EVENT) {
-        /* event rules are processed seperately */
+        /* event rules are processed separately */
       } else {
         permit_rule = 1;
-        ex = pcre_exec(rfilter->pr, rfilter->extra, uri, uri_len, 0, 0, NULL, 0);
+        ex = qos_regexec_len(r->pool, rfilter->preg, uri, uri_len);
         permit_rule_action = rfilter->action;
         if(ex == 0) {
           permit_rule_match = 1; 
@@ -4203,7 +4199,7 @@
     int denied = 0;
     if(he) {
       if(mode != QS_HEADERFILTER_SIZE_ONLY) {
-        if(pcre_exec(he->pcre, he->extra, entry[i].val, strlen(entry[i].val), 0, 0, NULL, 0) < 0) {
+        if(ap_regexec(he->preg, entry[i].val, 0, NULL, 0) != 0) {
           denied = 1;
         }
       }
@@ -4211,7 +4207,7 @@
         denied += 2;
       }
       if(denied) {
-        char *pattern = apr_psprintf(r->pool, "(pattern=%s, max. lenght=%d)",
+        char *pattern = apr_psprintf(r->pool, "(pattern=%s, max. length=%d)",
                                      he->text, he->size);
         if(he->action == QS_FLT_ACTION_DENY) {
           ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r,
@@ -4246,7 +4242,7 @@
                     QOS_LOG_PFX(042)"drop %s header%s: \'%s: %s\', %s, c=%s, id=%s",
                     type,
                     sconf->log_only ? " (log only)" : "",
-                     entry[i].key, entry[i].val,
+                    entry[i].key, entry[i].val,
                     apr_table_get(reason, entry[i].key),
                     QS_CONN_REMOTEIP(r->connection) == NULL ? "-" : QS_CONN_REMOTEIP(r->connection),
                     qos_unique_id(r, "042"));
@@ -4396,11 +4392,7 @@
  * Detects events at response time.
  */
 static void qos_setenvres(request_rec *r, qos_srv_config *sconf) {
-#ifdef AP_REGEX_H
   ap_regmatch_t regm[AP_MAX_REG_MATCH];
-#else
-  regmatch_t regm[AP_MAX_REG_MATCH];
-#endif
   int i;
   apr_table_entry_t *entry = (apr_table_entry_t *)apr_table_elts(sconf->setenvres_t)->elts;
   for(i = 0; i < apr_table_elts(sconf->setenvres_t)->nelts; i++) {
@@ -4434,8 +4426,8 @@
     for(i = 0; i < apr_table_elts(sconf->setenvresheadermatch_t)->nelts; i++) {
       const char *val = apr_table_get(headers, entryMatch[i].key);
       if(val) {
-        pcre *pr = (pcre *)entryMatch[i].val;
-        if(pcre_exec(pr, NULL, val, strlen(val), 0, 0, NULL, 0) == 0) {
+        ap_regex_t *preg = (ap_regex_t *)entryMatch[i].val;
+        if(ap_regexec(preg, val, 0, NULL, 0) == 0) {
           apr_table_set(r->subprocess_env, entryMatch[i].key, val);
         }
       }
@@ -4624,9 +4616,9 @@
 }
 
 /** 
- * Generic request validation.
- * We ensure to have at least a valid request uri received (no futher uri validation
- * required in your code).
+ * Generic request validation / sanity check:
+ * We ensure to have at least a valid, decoded request uri received.
+ * (no further uri validation required in your code)
  * @param r
  * @param sconf
  * @return HTTP_BAD_REQUEST for requests which may not be processed by mod_qos, otherwise
@@ -4664,11 +4656,7 @@
   for(i = 0; i < apr_table_elts(table_setenvif)->nelts; i++) {
     qos_setenvifquery_t *setenvif = (qos_setenvifquery_t *)entry[i].val;
     char *name = setenvif->name;
-#ifdef AP_REGEX_H
     ap_regmatch_t regm[AP_MAX_REG_MATCH];
-#else
-    regmatch_t regm[AP_MAX_REG_MATCH];
-#endif
     if(ap_regexec(setenvif->preg, query, AP_MAX_REG_MATCH, regm, 0) == 0) {
       if(name[0] == '!') {
         apr_table_unset(r->subprocess_env, &name[1]);
@@ -4692,26 +4680,31 @@
   apr_size_t len;
   const char *data = qos_parp_body_data_fn(r, &len);
   if(data && (len > 0)) {
-    int ovector[3];
     int i;
     apr_table_entry_t *entry = (apr_table_entry_t *)apr_table_elts(sconf->setenvifparpbody_t)->elts;
+#if (AP_SERVER_MINORVERSION_NUMBER < 4) && defined QS_INTERNAL_TEST
+    // Apache 2.2 is no longer supported (test only)
+    char *tmpData = apr_palloc(r->pool, len + 1);
+    memcpy(tmpData, data, len);
+    tmpData[len] = '\0';
+    data = (const char *)tmpData;
+#endif
     for(i = 0; i < apr_table_elts(sconf->setenvifparpbody_t)->nelts; i++) {
       qos_setenvifparpbody_t *setenvif = (qos_setenvifparpbody_t *)entry[i].val;
-      int c = pcre_exec(setenvif->preg, setenvif->extra, data, len, 0, 0, ovector, 3);
-      if(c >= 0) {
+      ap_regmatch_t regm[AP_MAX_REG_MATCH];
+#if (AP_SERVER_MINORVERSION_NUMBER < 4) && defined QS_INTERNAL_TEST
+      if(ap_regexec(setenvif->pregx, data, AP_MAX_REG_MATCH, regm, 0) == 0) { // won't work for null chars!
+#else
+      if(ap_regexec_len(setenvif->pregx, data, len, AP_MAX_REG_MATCH, regm, 0) == 0) {
+#endif
         char *name = setenvif->name;
-        char *value = apr_pstrdup(r->pool, setenvif->value);
         if(name[0] == '!') {
           apr_table_unset(r->subprocess_env, &name[1]);
         } else {
+          char *value = apr_pstrdup(r->pool, setenvif->value);
           char *p = strstr(value, "$1");
           if(p) {
-            char *c = apr_pstrndup(r->pool, &data[ovector[0]], ovector[1] - ovector[0]);
-#ifdef AP_REGEX_H
-            ap_regmatch_t regm[AP_MAX_REG_MATCH];
-#else
-            regmatch_t regm[AP_MAX_REG_MATCH];
-#endif
+            char *c = apr_pstrndup(r->pool, &data[regm[0].rm_so], regm[0].rm_eo - regm[0].rm_so);
             if(ap_regexec(setenvif->pregx, c, AP_MAX_REG_MATCH, regm, 0) == 0) {
               value = ap_pregsub(r->pool, value, c, AP_MAX_REG_MATCH, regm);
             }
@@ -4860,11 +4853,11 @@
  * @param r
  * @param setenvif_t
  */
-static void qos_setenvif(request_rec *r, apr_table_t *setenvif_t) {
+static void qos_setenvif(request_rec *r, apr_array_header_t *setenvif_t) {
   int i;
-  apr_table_entry_t *entry = (apr_table_entry_t *)apr_table_elts(setenvif_t)->elts;
-  for(i = 0; i < apr_table_elts(setenvif_t)->nelts; i++) {
-    qos_setenvif_t *setenvif = (qos_setenvif_t *)entry[i].val;
+  qos_setenvif_t *entries = (qos_setenvif_t *)setenvif_t->elts;
+  for(i = 0; i < setenvif_t->nelts; i++) {
+    qos_setenvif_t *setenvif = &entries[i];
     if(setenvif->preg == NULL) {
       // mode 1 (boolean AND operator)
       if((setenvif->variable1[0] == '!') && (setenvif->variable2[0] == '!')) {
@@ -4908,11 +4901,7 @@
       // mode 2 (pattern match)
       const char *value = apr_table_get(r->subprocess_env, setenvif->variable1);
       if(value) {
-#ifdef AP_REGEX_H
         ap_regmatch_t regm[AP_MAX_REG_MATCH];
-#else
-        regmatch_t regm[AP_MAX_REG_MATCH];
-#endif
         if(ap_regexec(setenvif->preg, value, AP_MAX_REG_MATCH, regm, 0) == 0) {
           if(setenvif->name[0] == '!') {
             apr_table_unset(r->subprocess_env, &setenvif->name[1]);
@@ -5049,7 +5038,9 @@
         if(actEntry->event) {
           if(((actEntry->event[0] != '!') && apr_table_get(r->subprocess_env, actEntry->event)) ||
              ((actEntry->event[0] == '!') && !apr_table_get(r->subprocess_env, &actEntry->event[1]))) {
-            actEntry->req++;
+            if(actEntry->req < LONG_MAX) {
+              actEntry->req++;
+            }
             if(now > (actEntry->interval + QS_BW_SAMPLING_RATE)) {
               if(actEntry->req_per_sec_limit) {
                 /* QS_EventPerSecLimit */
@@ -5116,7 +5107,9 @@
             entry->limitTime = 0;
           }
           /* increment limit event */
-          entry->limit++;
+          if(entry->limit < INT_MAX) {
+            entry->limit++;
+          }
           if(entry->limit == 1) {
             /* ... and start timer */
             entry->limitTime = now;
@@ -5202,7 +5195,9 @@
             }
             if(match) {
               apr_table_addn(rctx->event_entries, actEntry->url, (char *)actEntry);
-              actEntry->counter++;
+              if(actEntry->counter < INT_MAX) {
+                actEntry->counter++;
+              }
               if(actEntry->counter > actEntry->limit) {
                 rv = m_retcode;
                 ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r,
@@ -5332,14 +5327,11 @@
     apr_global_mutex_unlock(sconf->act->lock);   /* @CRT44 */
     if(!locked) {
       /* sleep 50ms */
-      struct timespec delay;
-      delay.tv_sec  = 0;
-      delay.tv_nsec = 50 * 1000000;
       qs_set_evmsg(r, "s;"); 
       if(sconf->log_only) {
         return;
       }
-      nanosleep(&delay, NULL);
+      apr_sleep(50000);
     }
     if(loops >= sconf->serializeTMO) {
       ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, 0, r,
@@ -5349,7 +5341,7 @@
                     qos_unique_id(r, "037"));
       QS_INC_EVENT(sconf, 37);
       /* remove this request from the queue resp. clear the queue
-         to avaoid a deadlock */
+         to avoid a deadlock */
       apr_global_mutex_lock(sconf->act->lock);     /* @CRT44.1 */
       sconf->act->serialize->q2 = 0;
       sconf->act->serialize->q1 = 0;
@@ -5406,14 +5398,11 @@
       apr_global_mutex_unlock(u->qos_cc->lock);        /* @CRT36 */   
       if(!locked) {
         /* sleep 100ms */
-        struct timespec delay;
-        delay.tv_sec  = 0;
-        delay.tv_nsec = 100 * 1000000;
         qs_set_evmsg(r, "s;"); 
         if(sconf->log_only) {
           return;
         }
-        nanosleep(&delay, NULL);
+        apr_sleep(100000);
       }
       // max wait time: 5 minutes
       if(loops >= 3000) {
@@ -5424,7 +5413,7 @@
                       qos_unique_id(r, "068"));
         QS_INC_EVENT(sconf, 68);
         /* remove this request from the queue resp. clear the queue
-           to avaoid a deadlock */
+           to avoid a deadlock */
         apr_global_mutex_lock(u->qos_cc->lock);          /* @CRT36.1 */
         clientEntry = qos_cc_getOrSet(u->qos_cc, &searchE, apr_time_sec(r->request_time));
         (*clientEntry)->serializeQueue = 0;
@@ -5460,7 +5449,9 @@
     searchE.ip6[1] = rctx->cc_event_ip[1];
     apr_global_mutex_lock(u->qos_cc->lock);            /* @CRT33 */
     clientEntry = qos_cc_getOrSet(u->qos_cc, &searchE, apr_time_sec(r->request_time));
-    (*clientEntry)->event_req++;
+    if((*clientEntry)->event_req < INT_MAX) {
+      (*clientEntry)->event_req++;
+    }
     count = (*clientEntry)->event_req;
     if((*clientEntry)->vip || rctx->is_vip) {
       vip = 1;
@@ -5668,7 +5659,7 @@
 /** 
  * determines client behavior based on accessed content types
  *
- * @return 0=normal, -1=unkonwn (not enough data), >=1 abnormal
+ * @return 0=normal, -1=unknown (not enough data), >=1 abnormal
  */
 static int qos_content_type(request_rec *r, qos_srv_config *sconf,
                             qos_s_t *s, qos_s_entry_t *e, int limit) {
@@ -5712,7 +5703,7 @@
       int i;
       unsigned int server[5];
       unsigned int client[5];
-      // note: all e->* variables are initialized by "1" to avaoid FPE
+      // note: all e->* variables are initialized by "1" to avoid FPE
       if(sconf->static_on == 1) {
         /* use predefined value */
         unsigned long e_all = e->html + e->img + e->cssjs + e->other + e->notmodified;
@@ -5794,7 +5785,9 @@
               actEntry->limitTime = 0;
             }
             /* increment limit event */
-            actEntry->limit++;
+            if(actEntry->limit < INT_MAX) {
+              actEntry->limit++;
+            }
             if(actEntry->limit == 1) {
               /* ... and start timer */
               actEntry->limitTime = now;
@@ -5810,7 +5803,7 @@
 }
 
 /**
- * client contol rules at log transaction
+ * client control rules at log transaction
  */
 static void qos_logger_cc(request_rec *r, qos_srv_config *sconf, qs_req_ctx *rctx) {
   int lowrate = 0;
@@ -5942,7 +5935,7 @@
         ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r->connection->base_server,
                      QOS_LOG_PFX(060)"access denied (previously), "
                      "QS_ClientEventBlockCount rule: "
-                     "max=%d, current=%d, "
+                     "max=%d, current=%hu, "
                      "message repeated %d times, "
                      "c=%s",
                      sconf->qos_cc_block,
@@ -5977,12 +5970,13 @@
       }
     }
     if(block_event) {
+      int newValue = (*clientEntry)->block + block_event;
       if((*clientEntry)->block == 0) {
         /* start timer */
         (*clientEntry)->blockTime = now;
       }
       /* ...and increment/increase block event counter */
-      (*clientEntry)->block += block_event;
+      (*clientEntry)->block = newValue > USHRT_MAX ? USHRT_MAX : newValue;
     }
   } else if((*clientEntry)->lowrate) {
     /* reset low prio client after 24h (resp. QOS_LOW_TIMEOUT seconds) */
@@ -6039,6 +6033,7 @@
           seenEvent = apr_pstrcat(r->pool, QS_LIMIT_SEEN, eventName, NULL);
         }
         if(apr_table_get(r->subprocess_env, seenEvent) == NULL) {
+          int newValue = (*clientEntryFromHdr)->limit[limitTableIndex].limit + eventSet;
           /* only once per request */
           apr_table_set(r->subprocess_env, seenEvent, "");
           if((*clientEntryFromHdr)->limit[limitTableIndex].limit == 0) {
@@ -6046,7 +6041,7 @@
             (*clientEntryFromHdr)->limit[limitTableIndex].limitTime = now;
           }
           /* ... and increase limit event */
-          (*clientEntryFromHdr)->limit[limitTableIndex].limit += eventSet;
+          (*clientEntryFromHdr)->limit[limitTableIndex].limit = newValue > USHRT_MAX ? USHRT_MAX : newValue;
         }
       }
     }
@@ -6060,7 +6055,7 @@
 }
 
 /**
- * client contol rules at header parser
+ * client control rules at header parser
  */
 static int qos_hp_cc(request_rec *r, qos_srv_config *sconf, char **msg, char **uid) {
   int ret = DECLINED;
@@ -6111,7 +6106,9 @@
       apr_time_t now = apr_time_sec(r->request_time);
       const char *v = apr_table_get(r->subprocess_env, QS_EVENT);
       if(v) {
-        (*clientEntry)->req++;
+        if((*clientEntry)->req < LONG_MAX) {
+          (*clientEntry)->req++;
+        }
         if(now > (*clientEntry)->interval + QS_BW_SAMPLING_RATE) {
           /* calc req/sec */
           (*clientEntry)->req_per_sec = (*clientEntry)->req / (now - (*clientEntry)->interval);
@@ -6162,7 +6159,7 @@
           ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r->connection->base_server,
                        QOS_LOG_PFX(060)"access denied (previously), "
                        "QS_ClientEventBlockCount rule: "
-                       "max=%d, current=%d, "
+                       "max=%d, current=%hu, "
                        "message repeated %d times, "
                        "c=%s",
                        sconf->qos_cc_block,
@@ -6192,7 +6189,7 @@
         *msg = apr_psprintf(r->connection->pool, 
                             QOS_LOG_PFX(060)"access denied%s, "
                             "QS_ClientEventBlockCount rule: "
-                            "max=%d, current=%d, age=%"APR_TIME_T_FMT", c=%s",
+                            "max=%d, current=%hu, age=%"APR_TIME_T_FMT", c=%s",
                             sconf->log_only ? " (log only)" : "",
                             sconf->qos_cc_block,
                             (*clientEntry)->block,
@@ -6241,14 +6238,15 @@
             seenEvent = apr_pstrcat(r->pool, QS_LIMIT_SEEN, eventName, NULL);
           }
           if(apr_table_get(r->subprocess_env, seenEvent) == NULL) {
-            // first occurance
+            int newValue = (*clientEntryFromHdr)->limit[limitTableIndex].limit + eventSet;
+            // first occurrence
             apr_table_set(r->subprocess_env, seenEvent, "");
             if((*clientEntryFromHdr)->limit[limitTableIndex].limit == 0) {
               /* .start timer */
               (*clientEntryFromHdr)->limit[limitTableIndex].limitTime = now;
             }
             /* increment limit event */
-            (*clientEntryFromHdr)->limit[limitTableIndex].limit += eventSet;
+            (*clientEntryFromHdr)->limit[limitTableIndex].limit = newValue > USHRT_MAX ? USHRT_MAX : newValue;
           }
         }
 
@@ -6293,7 +6291,7 @@
                                   QOS_LOG_PFX(067)"access denied%s, "
                                   "QS_%sClientEventLimitCount rule: "
                                   "event=%s, "
-                                  "max=%d, current=%d, age=%"APR_TIME_T_FMT", c=%s",
+                                  "max=%hu, current=%hu, age=%"APR_TIME_T_FMT", c=%s",
                                   sconf->log_only ? " (log only)" : "",
                                   conditional,
                                   eventName,
@@ -6328,15 +6326,10 @@
     }
     apr_global_mutex_unlock(u->qos_cc->lock);          /* @CRT17 */
 
-    if(!sconf->log_only) {
-      if(req_per_sec_block_rate) {
-        int sec = req_per_sec_block_rate / 1000;
-        int nsec = req_per_sec_block_rate % 1000;
-        struct timespec delay;
-        qs_set_evmsg(r, "L;"); 
-        delay.tv_sec  = sec;
-        delay.tv_nsec = nsec * 1000000;
-        nanosleep(&delay,NULL);
+    if(req_per_sec_block_rate) {
+      qs_set_evmsg(r, "L;"); 
+      if(!sconf->log_only) {
+        apr_sleep(req_per_sec_block_rate*1000);
       }
     }
   }
@@ -6348,7 +6341,7 @@
   qsstatus_t *s = selfv;
   s->exit = 1;
   /* may long up to 100ms */
-  if(m_worker_mpm || m_event_mpm) {
+  if(m_threaded_mpm) {
     apr_status_t status;
     apr_thread_join(&status, s->thread);
     //apr_pool_destroy(s->pool);
@@ -6356,19 +6349,71 @@
   return APR_SUCCESS;
 }
 
+// checks if connection counting is enabled (any host)
+static int qos_count_connections(qos_srv_config *sconf) {
+  server_rec *s = sconf->base_server;
+  qos_srv_config *bsconf = (qos_srv_config*)ap_get_module_config(s->module_config, &qos_module);
+  if(QS_COUNT_CONNECTIONS(bsconf)) {
+    return 1;
+  }
+  s = s->next;
+  while(s) {
+    qos_srv_config *sc = (qos_srv_config*)ap_get_module_config(s->module_config, &qos_module);
+    if(QS_COUNT_CONNECTIONS(sc)) {
+      return 1;
+    }
+    s = s->next;
+  }
+  return 0;
+}
+
+// total (server/all hosts) connections
+static int qos_server_connections(qos_srv_config *sconf) {
+  server_rec *s = sconf->base_server;
+  qos_srv_config *bsconf = (qos_srv_config*)ap_get_module_config(s->module_config, &qos_module);
+  int connections = bsconf->act->conn->connections;
+  s = s->next;
+  while(s) {
+    qos_srv_config *sc = (qos_srv_config*)ap_get_module_config(s->module_config, &qos_module);
+    if(sc->act->conn != bsconf->act->conn) {
+      // server has either his own counter or the base server's counter
+      connections += sc->act->conn->connections;
+    }
+    s = s->next;
+  }
+  return connections;
+  /*
+  int i, j;
+  worker_score *ws_record;
+  process_score *ps_record;
+  for(i = 0; i < sconf->server_limit; ++i) {
+    ps_record = ap_get_scoreboard_process(i);
+    for(j = 0; j < sconf->thread_limit; ++j) {
+      ws_record = ap_get_scoreboard_worker(i, j);
+      if(!ps_record->quiescing && ps_record->pid) {
+        if(ws_record->status == SERVER_READY && ps_record->generation == qos_my_generation) {
+          ready++;
+        }
+      }
+    }
+  }
+  */ 
+}
+
 /**
  * Status logger thread
  *
  * @param thread
  * @param selfv Base server_rec
  */
-static void *qos_status_thread(apr_thread_t *thread, void *selfv) {
+static void *APR_THREAD_FUNC qos_status_thread(apr_thread_t *thread, void *selfv) {
   qsstatus_t *s = selfv;
   int server_limit, thread_limit;
   ap_mpm_query(AP_MPMQ_HARD_LIMIT_THREADS, &thread_limit);
   ap_mpm_query(AP_MPMQ_HARD_LIMIT_DAEMONS, &server_limit);
   while(!s->exit) {
     char clientContentTypes[8192];
+    char allConn[64];
     int s_busy = 0;
     int s_open = 0;
     int s_ready = 0;
@@ -6388,14 +6433,14 @@
     e = 60 - (now % 60);
     e = e * 10;
     for(c = 0; c < e; c++) {
-      usleep(100000);
+      apr_sleep(100000);
       if(s->exit) {
         run = 0;
         break;
       }
     }
     if(!s->exit) {
-      apr_global_mutex_lock(s->lock);          /* @CRT47 */
+      apr_global_mutex_lock(s->lock);            /* @CRT47 */
       now = time(NULL);
       if(*s->qsstatustimer <= now) {
         // set next and fetch the data
@@ -6468,6 +6513,15 @@
                    );
         }
       }
+      allConn[0] = '\0';
+      if(qos_count_connections(s->sconf)) {
+        apr_global_mutex_lock(s->lock);          /* @CRT52 */
+        int all_connections = qos_server_connections(s->sconf);
+        snprintf(allConn, 64, ", \"QS_AllConn\": %d",
+                 all_connections
+                 );
+        apr_global_mutex_unlock(s->lock);        /* @CRT52 */
+      }
       ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, s->sconf->base_server,
                    QOS_LOG_PFX(200)"{ \"scoreboard\": { "
                    "\"open\": %d, \"waiting\": %d, \"read\": %d, "
@@ -6476,14 +6530,20 @@
                    "\"dns\": %d, \"closing\": %d, "
                    "\"finishing\": %d, \"idle\": %d }, "
                    "\"maxclients\": { "
-                   "\"max\": %d, \"busy\": %d }%s }",
-                   s_open, s_ready, s_read, s_write, s_keep, s_start, s_log,
-                   s_dns, s_closing, s_usr1, s_kill,
+                   "\"max\": %d, \"busy\": %d"
+                   "%s }"
+                   "%s }",
+                   s_open, s_ready, s_read,
+                   s_write, s_keep,
+                   s_start, s_log,
+                   s_dns, s_closing,
+                   s_usr1, s_kill,
                    s->maxclients, s_busy,
+                   allConn,
                    clientContentTypes);
     }
   }
-  if(m_worker_mpm || m_event_mpm) {
+  if(m_threaded_mpm) {
     apr_thread_exit(thread, APR_SUCCESS);
   }
   return NULL;
@@ -6513,57 +6573,6 @@
 }
 #endif
 
-// checks if connection counting is enabled (any host)
-static int qos_count_connections(qos_srv_config *sconf) {
-  server_rec *s = sconf->base_server;
-  qos_srv_config *bsconf = (qos_srv_config*)ap_get_module_config(s->module_config, &qos_module);
-  if(QS_COUNT_CONNECTIONS(bsconf)) {
-    return 1;
-  }
-  s = s->next;
-  while(s) {
-    qos_srv_config *sc = (qos_srv_config*)ap_get_module_config(s->module_config, &qos_module);
-    if(QS_COUNT_CONNECTIONS(sc)) {
-      return 1;
-    }
-    s = s->next;
-  }
-  return 0;
-}
-
-// total (server/all hosts) conections
-static int qos_server_connections(qos_srv_config *sconf) {
-  server_rec *s = sconf->base_server;
-  qos_srv_config *bsconf = (qos_srv_config*)ap_get_module_config(s->module_config, &qos_module);
-  int connections = bsconf->act->conn->connections;
-  s = s->next;
-  while(s) {
-    qos_srv_config *sc = (qos_srv_config*)ap_get_module_config(s->module_config, &qos_module);
-    if(sc->act->conn != bsconf->act->conn) {
-      // server has either his own counter or the base server's counter
-      connections += sc->act->conn->connections;
-    }
-    s = s->next;
-  }
-  return connections;
-  /*
-  int i, j;
-  worker_score *ws_record;
-  process_score *ps_record;
-  for(i = 0; i < sconf->server_limit; ++i) {
-    ps_record = ap_get_scoreboard_process(i);
-    for(j = 0; j < sconf->thread_limit; ++j) {
-      ws_record = ap_get_scoreboard_worker(i, j);
-      if(!ps_record->quiescing && ps_record->pid) {
-        if(ws_record->status == SERVER_READY && ps_record->generation == qos_my_generation) {
-          ready++;
-        }
-      }
-    }
-  }
-  */ 
-}
-
 /**
  * client control rules at process connection handler
  */
@@ -6630,7 +6639,7 @@
           // calculate the min. required free connections allowing us to serve request by this IP
           reqSpare = (cconf->sconf->max_clients - cconf->sconf->qos_cc_prefer_limit) * penalty / 12;
           if((cconf->sconf->max_clients - u->qos_cc->connections) < reqSpare) {
-            /* not enougth free connections */
+            /* not enough free connections */
             if(u->qos_cc->connections > cconf->sconf->qos_cc_prefer_limit) {
               *msg = apr_psprintf(cconf->mc->pool, 
                                   QOS_LOG_PFX(066)"access denied%s, "
@@ -6655,7 +6664,7 @@
 }
 
 /**
- * calculates the current minimal up/download bandwith
+ * calculates the current minimal up/download bandwidth
  */
 static int qos_req_rate_calc(qos_srv_config *sconf, int *current) {
   int req_rate = sconf->req_rate;
@@ -6663,7 +6672,7 @@
     int connections = qos_server_connections(sconf);
     if(connections > sconf->req_rate_start) {
       /* keep the minimal rate until reaching the min connections */
-      req_rate = req_rate + ((sconf->min_rate_max / sconf->max_clients) * connections);
+      req_rate = req_rate + (sconf->min_rate_max * connections / sconf->max_clients);
       if(connections > sconf->max_clients) {
         // limit the max rate to its max if we have more connections then expected
         if(connections > (sconf->max_clients + QS_DOUBLE_CONN_H)) {
@@ -6673,7 +6682,9 @@
                        " cal. request rate=%d,"
                        " max. limit=%d."
                        " Check log for unclean child exit and consider"
-                       " to do a graceful server restart if this condition persists.",
+                       " to do a graceful server restart if this condition persists."
+                       " You might also increase the number of supported connections"
+                       " using the 'QS_MaxClients' directive.",
                        connections, req_rate, sconf->min_rate_max);
         }
         QS_INC_EVENT(sconf, 36);
@@ -6902,7 +6913,7 @@
 /**
  * Translates an IP address (from geo csv) to a numeric value.
  *
- * @param pool To dup the string whike parsing.
+ * @param pool To dup the string while parsing.
  * @param ip
  * @return
  */
@@ -6989,7 +7000,7 @@
              "      <td colspan=\"1\">auto refresh</td>\n", r);
     ap_rputs("      <td colspan=\"8\">\n", r);
     ap_rprintf(r, "        <form action=\"%s\" method=\"get\">\n",
-               ap_escape_html(r->pool, r->parsed_uri.path ? r->parsed_uri.path : ""));
+               ap_escape_html(r->pool, r->parsed_uri.path));
     if(option && strstr(option, "ip")) {
       ap_rprintf(r, "          <input name=\"option\" value=\"ip\" type=\"hidden\">\n");
     }
@@ -7011,7 +7022,7 @@
              "      <td colspan=\"1\">client ip connections</td>\n", r);
     ap_rputs("      <td colspan=\"8\">\n", r);
     ap_rprintf(r, "        <form action=\"%s\" method=\"get\">\n",
-               ap_escape_html(r->pool, r->parsed_uri.path ? r->parsed_uri.path : ""));
+               ap_escape_html(r->pool, r->parsed_uri.path));
     if(!option || (option && !strstr(option, "ip")) ) {
       ap_rprintf(r, "          <input name=\"option\" value=\"ip\" type=\"hidden\">\n");
       ap_rprintf(r, "          <input name=\"action\" value=\"enable\" type=\"submit\">\n");
@@ -7035,7 +7046,7 @@
                "      <td colspan=\"1\">search a client ip entry</td>\n", r); 
       ap_rputs("      <td colspan=\"8\">\n", r);
       ap_rprintf(r, "        <form action=\"%s\" method=\"get\">\n",
-                 ap_escape_html(r->pool, r->parsed_uri.path ? r->parsed_uri.path : ""));
+                 ap_escape_html(r->pool, r->parsed_uri.path));
       if(option && strstr(option, "ip")) {
         ap_rprintf(r, "          <input name=\"option\" value=\"ip\" type=\"hidden\">\n");
       }
@@ -7124,7 +7135,7 @@
               qos_s_entry_limit_conf_t *eventLimitConf = qos_getQSLimitEvent(u, QS_LIMIT_DEFAULT, &limitTableIndex);
               if(eventLimitConf) {
                 if(eventLimitConf->limitTime > (time(NULL) - searchE.limit[limitTableIndex].limitTime)) {
-                  ap_rprintf(r, "<td colspan=\"1\">%d, %ld&nbsp;sec</td>",
+                  ap_rprintf(r, "<td colspan=\"1\">%hu, %ld&nbsp;sec</td>",
                              searchE.limit[limitTableIndex].limit, time(NULL) - searchE.limit[limitTableIndex].limitTime);
                 } else {
                   ap_rprintf(r, "<td colspan=\"1\">no</td>");
@@ -7711,20 +7722,21 @@
  * @param thread
  * @param selfv Base server_rec
  */
-static void *qos_req_rate_thread(apr_thread_t *thread, void *selfv) {
+static void *APR_THREAD_FUNC qos_req_rate_thread(apr_thread_t *thread, void *selfv) {
   server_rec *bs = selfv;
   qos_srv_config *sconf = (qos_srv_config*)ap_get_module_config(bs->module_config, &qos_module);
   // list of ip addr. for whose we shall inc. block count
   apr_uint64_t *ips = calloc(sconf->max_clients * 2, APR_ALIGN_DEFAULT(sizeof(apr_uint64_t)));
   while(!sconf->inctx_t->exit) {
     apr_uint64_t *ip = ips;
-    int currentcon = 0;
-    int req_rate = qos_req_rate_calc(sconf, &currentcon);
+    int current_con = 0;
+    int req_rate = qos_req_rate_calc(sconf, &current_con);
     apr_time_t now = apr_time_sec(apr_time_now());
     apr_time_t interval = now - sconf->qs_req_rate_tm;
     int i;
     apr_table_entry_t *entry;
-    sleep(1);
+    // every second
+    apr_sleep(APR_USEC_PER_SEC);
     if(sconf->inctx_t->exit) {
       break;
     }
@@ -7755,7 +7767,7 @@
               cconf->has_lowrate = 1; /* mark connection low rate */
             }
             /* enable only if min. num of connection reached */
-            if(currentcon <= sconf->req_rate_start) {
+            if(current_con < sconf->req_rate_start) {
               level = APLOG_DEBUG;
               cconf->has_lowrate = 1; /* mark connection low rate */
             }
@@ -7802,7 +7814,7 @@
                   cconf->has_lowrate = 1; /* mark connection low rate */
                 }
                 /* enable only if min. num of connection reached */
-                if(currentcon <= sconf->req_rate_start) {
+                if(current_con < sconf->req_rate_start) {
                   level = APLOG_DEBUG;
                   cconf->has_lowrate = 1; /* mark connection low rate */
                 }
@@ -7865,7 +7877,9 @@
       clientEntry = qos_cc_getOrSet(u->qos_cc, &searchE, 0);
 
       /* increment block event */
-      (*clientEntry)->block++;
+      if((*clientEntry)->block < USHRT_MAX) {
+        (*clientEntry)->block++;
+      }
       if((*clientEntry)->block == 1) {
         /* ... and start timer */
         (*clientEntry)->blockTime = apr_time_sec(apr_time_now());
@@ -7878,7 +7892,7 @@
   // called via apr_pool_cleanup_register():
   // apr_thread_mutex_destroy(sconf->inctx_t->lock);
   free(ips);
-  if(m_worker_mpm || m_event_mpm) {
+  if(m_threaded_mpm) {
     apr_thread_exit(thread, APR_SUCCESS);
   }
   return NULL;
@@ -7896,7 +7910,7 @@
   qos_srv_config *sconf = (qos_srv_config*)ap_get_module_config(bs->module_config, &qos_module);
   sconf->inctx_t->exit = 1;
   /* may long up to one second */
-  if(m_worker_mpm || m_event_mpm) {
+  if(m_threaded_mpm) {
     apr_status_t status;
     apr_thread_join(&status, sconf->inctx_t->thread);
   }
@@ -7959,14 +7973,9 @@
     if((s = apr_atoi64(d)) > 0)
 #endif
       {
+        qs_set_evmsg(r, "L;"); 
         if(!sconf->log_only) {
-          int sec = s / 1000;
-          int nsec = s % 1000;
-          struct timespec delay;
-          qs_set_evmsg(r, "L;"); 
-          delay.tv_sec  = sec;
-          delay.tv_nsec = nsec * 1000000;
-          nanosleep(&delay,NULL);     
+          apr_sleep(s*1000);
         } 
     }
   }
@@ -8005,13 +8014,14 @@
  * Verifies Apache and MPM version and writes error message (notice)
  * for incompatibel version/type.
  *
- * Apache 2.2 MPM worker binaries is the only configuration which
+ * Apache MPM worker binaries is the only configuration which
  * has been fully tested (as mentioned in the documentation, see index.html).
  *
  * - old (2.0.x, 2.2.x) MPM Apache prefork versions do not unload the
  *   DSO properly or child exit may cause a segfault (pool cleanup)
- * - Apache 2.4 should work but is not yet fully tested
- *   (see CHANGES.txt for more informaton)
+ * - regular expression are only fully supported with Apach 2.4
+ * - Apache 2.4 should work (but is not fully tested)
+ *   (see CHANGES.txt for more information)
  * - Apache 2.0 does not support all directives (e.g. QS_ClientPrefer) and
  *   we do no longer test against this version (the module does probably
  *   not even compile with version 2.0)
@@ -8019,30 +8029,60 @@
  */
 static void qos_version_check(server_rec *bs) {
   ap_version_t version;
+
   if(strcasecmp(ap_show_mpm(), "event") == 0) {
+    ap_directive_t *pdir;
     m_event_mpm = 1; // disable features like keep-alive control
-  }
-  if(strcasecmp(ap_show_mpm(), "prefork") == 0) {
-    // mod_qos is fully tested for MPM worker (and works with event)
-    m_worker_mpm = 0; // disable child cleanup
+    for(pdir = ap_conftree; pdir != NULL; pdir = pdir->next) {
+      if(strcasecmp(pdir->directive, "AsyncRequestWorkerFactor") == 0) {
+        double val = 0;
+        char *endptr;
+        const char *arg = pdir->args;
+        if(arg == NULL) {
+          continue;
+        }
+        val = strtod(arg, &endptr);
+        if(*endptr) {
+          continue;
+        }
+        if(val < 0) {
+          continue;
+        }
+        m_event_mpm_worker_factor = val;        
+        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, bs, 
+                     QOS_LOGD_PFX"found AsyncRequestWorkerFactor directive '%f'",
+                     m_event_mpm_worker_factor);
+      }
+    }
+  } else if(strcasecmp(ap_show_mpm(), "worker") != 0) {
+    // mod_qos is fully tested for MPM worker (and "works" with event)
     ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, bs, 
                  QOS_LOG_PFX(009)"loaded MPM is '%s'"
-                 " but mod_qos should be used with MPM 'Worker' only.",
+                 " but mod_qos should be used with MPM 'Worker' or 'Event' only.",
                  ap_show_mpm());
   }
 
+  if(strcasecmp(ap_show_mpm(), "prefork") == 0) {
+    m_threaded_mpm = 0; // disable child cleanup (if neither worker nor event MPM)
+  }
+  
   ap_get_server_revision(&version);
-  if(version.major != 2 || (version.minor != 2 && version.minor != 4)) {
-    // 2.2 and 2.4 should be ok / older or newer versions are not tested
+  if(version.major == 2 && version.minor == 4 && version.patch == 49) {
+    // 2.4.49 compat: prevents Apache segfault on connection close
+    m_forced_close = 0;
+  }
+
+  if(version.major != 2 || version.minor != 4) {
+    // 2.4 should work fine / older or newer versions are not tested
     ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, bs, 
                  QOS_LOG_PFX(009)"server version is %d.%d"
-                 " but mod_qos should be used with Apache 2.2 or 2.4 only.",
+                 " but mod_qos should be used with Apache 2.4 only.",
                  version.major, version.minor);
   }
 }
 
 /**
- * enforces the QS_RedirectIf varibale
+ * enforces the QS_RedirectIf variable
  * @param r
  * @param sconf
  * @param rules Rules array
@@ -8050,11 +8090,7 @@
  */
 static int qos_redirectif(request_rec *r, qos_srv_config *sconf, 
                           apr_array_header_t *rules) {
-#ifdef AP_REGEX_H
   ap_regmatch_t regm[AP_MAX_REG_MATCH];
-#else
-  regmatch_t regm[AP_MAX_REG_MATCH];
-#endif
   int i;
   qos_redirectif_entry_t *entries = (qos_redirectif_entry_t *)rules->elts;
   for(i = 0; i < rules->nelts; ++i) {
@@ -8263,7 +8299,9 @@
       clientEntry = qos_cc_getOrSet(u->qos_cc, &searchE, 0);
 
       /* increment block event */
-      (*clientEntry)->block++;
+      if((*clientEntry)->block < USHRT_MAX) {
+        (*clientEntry)->block++;
+      }
       if((*clientEntry)->block == 1) {
         /* ... and start timer */
         (*clientEntry)->blockTime = apr_time_sec(apr_time_now());
@@ -8304,7 +8342,9 @@
       u->qos_cc->connections--;
     }
     clientEntry = qos_cc_getOrSet(u->qos_cc, &searchE, 0);
-    (*clientEntry)->events++; // update event activity even there is no valid request (logger)
+    if((*clientEntry)->events < UINT_MAX) {
+      (*clientEntry)->events++; // update event activity even there is no valid request (logger)
+    }
     if(cconf->set_vip_by_header) {
       (*clientEntry)->vip = 1;
     }
@@ -8477,7 +8517,12 @@
       }
       if(sconf->geo_limit != -1) {
         if(all_connections >= sconf->geo_limit) {
-          if(pB == NULL || apr_table_get(sconf->geo_priv, pB->country) == NULL) {
+          if(sconf->geo_excludeUnknown == 1 && (pB == NULL || pB->country[0] == '\0')) {
+            ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, 
+                         QOS_LOGD_PFX"skip QS_ClientGeoCountryPriv enforcement"
+                         " for client address %s which could not be mapped to country code",
+                         QS_CONN_REMOTEIP(c) ? QS_CONN_REMOTEIP(c) : "UNKNOWN");
+          } else if(pB == NULL || apr_table_get(sconf->geo_priv, pB->country) == NULL) {
             ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, c->base_server,
                          QOS_LOG_PFX(101)"access denied%s,"
                          " QS_ClientGeoCountryPriv rule: max=%d,"
@@ -8585,7 +8630,7 @@
   if(c->sbh == NULL) {
     // proxy connections do NOT have any relation to the score board, don't handle them
     ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, 
-                 QOS_LOGD_PFX"skip processing of outgoing connection %s<->%s",
+                 QOS_LOGD_PFX"skip processing of outgoing/virtual connection %s<->%s",
                  QS_CONN_REMOTEIP(c) ? QS_CONN_REMOTEIP(c) : "UNKNOWN",
                  c->local_ip ? c->local_ip : "UNKNOWN");
     return ret;
@@ -8635,7 +8680,7 @@
             ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, c->base_server,
                          QOS_LOG_PFX(060)"access denied, "
                          "QS_ClientEventBlockCount rule: "
-                         "max=%d, current=%d, "
+                         "max=%d, current=%hu, "
                          "message repeated %d times, "
                          "c=%s",
                          sconf->qos_cc_block,
@@ -8646,21 +8691,25 @@
         } else {
           ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, c->base_server,
                        QOS_LOG_PFX(060)"access denied, QS_ClientEventBlockCount rule: "
-                       "max=%d, current=%d, age=%"APR_TIME_T_FMT", c=%s",
+                       "max=%d, current=%hu, age=%"APR_TIME_T_FMT", c=%s",
                        sconf->qos_cc_block,
                        (*clientEntry)->block,
                        now - (*clientEntry)->blockTime,
                        QS_CONN_REMOTEIP(c) == NULL ? "-" : QS_CONN_REMOTEIP(c));
         }
         if(!sconf->log_only) {
-          apr_table_set(c->notes, QS_BLOCK_SEEN, ""); // supress NullConnection messages
+          apr_table_set(c->notes, QS_BLOCK_SEEN, ""); // suppress NullConnection messages
           c->keepalive = AP_CONN_CLOSE;
           c->aborted = 1;
           if(c->cs) {
             c->cs->state = CONN_STATE_LINGER;
           }
           apr_table_set(c->notes, QS_CONN_ABORT, QS_CONN_ABORT);
-          ret = m_retcode;
+          if (m_forced_close == 0) {
+            ret = DECLINED;
+          } else {
+            ret = m_retcode;
+          }
         }
       } else {
         /* release */
@@ -8668,7 +8717,7 @@
           // write remaining log lines
           ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, c->base_server,
                        QOS_LOG_PFX(060)"access denied (previously), QS_ClientEventBlockCount rule: "
-                       "max=%d, current=%d, "
+                       "max=%d, current=%hu, "
                        "message repeated %d times, "
                        "c=%s",
                        sconf->qos_cc_block,
@@ -8698,15 +8747,26 @@
                                                                 &qos_module);
   char *value;
   const char *ignore;
+
+  if(sconf->log_env == 1) {
+    qos_log_env(r, ">PR_2");
+  }
+
   if(!ap_is_initial_req(r) || !sconf->user_tracking_cookie) {
     return DECLINED;
   }
+
   value = qos_get_remove_cookie(r, sconf->user_tracking_cookie);
   qos_get_create_user_tracking(r, sconf, value);
 
   if(!sconf->user_tracking_cookie_force) {
     return DECLINED;
   }
+
+  if(qos_request_check(r, sconf) != APR_SUCCESS) {
+    return HTTP_BAD_REQUEST;
+  }
+
   if(strcmp("/favicon.ico", r->parsed_uri.path) == 0) {
     return DECLINED;
   }
@@ -8755,7 +8815,7 @@
         }
       }
     } /* else, "grant access" to the error page */
-    /* but prevent page caching (the browser shall always acces the
+    /* but prevent page caching (the browser shall always access the
        server when redireced to this url */
     apr_table_add(r->headers_out, "Cache-Control", "no-cache, no-store");
   } else if(apr_table_get(r->subprocess_env, QOS_USER_TRACKING_NEW) != NULL) {
@@ -8806,7 +8866,7 @@
   if(sconf->geodb) {
     if(sconf->qos_cc_forwardedfor) {
       // override country determined on a per connection basis
-      const char *forwardedfor = apr_table_get(r->headers_in, sconf->qos_cc_forwardedfor);
+      const char *forwardedfor = qos_forwardedfor_fromHeader(r, sconf->qos_cc_forwardedfor);
       if(forwardedfor) {
         unsigned long ip = qos_geo_str2long(r->pool, forwardedfor);
         if(ip) {
@@ -8880,6 +8940,11 @@
   if(isVipIP) {
     apr_table_set(r->subprocess_env, QS_ISVIPREQ, isVipIP);
   }
+
+  if(sconf->log_env == 1) {
+    qos_log_env(r, ">PR_1");
+  }
+
   if(qos_request_check(r, sconf) != APR_SUCCESS) {
     return HTTP_BAD_REQUEST;
   }
@@ -9008,6 +9073,10 @@
     qos_dir_config *dconf = (qos_dir_config*)ap_get_module_config(r->per_dir_config,
                                                                   &qos_module);
 
+    if(sconf->log_env == 1) {
+      qos_log_env(r, ">HP_2");
+    }
+
     qos_deflate(r);
    
     /** QS_LimitRequestBody */
@@ -9044,6 +9113,10 @@
     qos_dir_config *dconf = (qos_dir_config*)ap_get_module_config(r->per_dir_config,
                                                                   &qos_module);
 
+    if(sconf->log_env == 1) {
+      qos_log_env(r, ">HP_1");
+    }
+
     /*
      * QS_DenyBody requires mod_parp
      */
@@ -9089,6 +9162,10 @@
     qs_req_ctx *rctx = NULL;
     const char *error_page = sconf->error_page;
 
+    if(sconf->log_env == 1) {
+      qos_log_env(r, ">HP_3");
+    }
+
     qos_deflate_contentlength(r);
 
     /* QS_SetEnvIfResBody */
@@ -9146,10 +9223,10 @@
     if(r->parsed_uri.query) {
       qos_setenvifquery(r, sconf, dconf);
     }
-    if(apr_table_elts(sconf->setenvif_t)->nelts > 0) {
+    if(sconf->setenvif_t->nelts > 0) {
       qos_setenvif(r, sconf->setenvif_t);
     }
-    if(apr_table_elts(dconf->setenvif_t)->nelts > 0) {
+    if(dconf->setenvif_t->nelts > 0) {
       qos_setenvif(r, dconf->setenvif_t);
     }
     if(apr_table_elts(sconf->setenv_t)->nelts > 0) {
@@ -9338,14 +9415,9 @@
         if(rctx->is_vip) {
           qs_set_evmsg(r, "S;"); 
         } else {
-          int sec = req_per_sec_block / 1000;
-          int nsec = req_per_sec_block % 1000;
-          struct timespec delay;
           qs_set_evmsg(r, "L;"); 
-          delay.tv_sec  = sec;
-          delay.tv_nsec = nsec * 1000000;
           if(!sconf->log_only) {
-            nanosleep(&delay,NULL);
+            apr_sleep(req_per_sec_block*1000);
           }
           /* don't wait more than once */
           req_per_sec_block = 0;
@@ -9379,7 +9451,9 @@
         qos_delay_ctx_t *dctx = apr_pcalloc(r->pool, sizeof(qos_delay_ctx_t));
         dctx->rctx = rctx;
         dctx->entry = event_kbytes_per_sec;
-        ap_add_output_filter("qos-out-filter-delay", dctx, r, r->connection);
+        if(!sconf->log_only) {
+          ap_add_output_filter("qos-out-filter-delay", dctx, r, r->connection);
+        }
       }
     }
     
@@ -9425,14 +9499,9 @@
      * QS_EventPerSecLimit
      */
     if(req_per_sec_block) {
-      int sec = req_per_sec_block / 1000;
-      int nsec = req_per_sec_block % 1000;
-      struct timespec delay;
       qs_set_evmsg(r, "L;"); 
-      delay.tv_sec  = sec;
-      delay.tv_nsec = nsec * 1000000;
       if(!sconf->log_only) {
-        nanosleep(&delay,NULL);
+        apr_sleep(req_per_sec_block*1000);
       }
     }
 
@@ -9709,7 +9778,7 @@
           int blen = nbytes > len ? len : nbytes - 1;
           /* 1. overlap: this buffer avoids that we miss a string if it is cut apart
              within two buckets 
-             e.g., [Logi][n Page] instaed of [Login Page] when searching for "Login Page" */
+             e.g., [Logi][n Page] instead of [Login Page] when searching for "Login Page" */
           if(rctx->body_window == NULL) {
             // first call, create a window buffer
             rctx->body_window = apr_pcalloc(r->pool, (len*2)+1);
@@ -9756,7 +9825,7 @@
  * @param request_time Time this request has started
  * @param entry Rule entry to update / measure
  * @param length Bytes we are going to transfer
- * @return Wait time in nanoseconds
+ * @return Wait time in microsseconds
  */
 static apr_off_t qos_calc_kbytes_per_sec_wait_time(apr_time_t request_time,
                                                    qs_acentry_t *entry,
@@ -9874,7 +9943,7 @@
 }
 
 /**
- * Out filter measuring the minimal download bandwith.
+ * Out filter measuring the minimal download bandwidth.
  *
  * @param f
  * @param bb
@@ -9907,7 +9976,7 @@
 }
 
 /**
- * Merges two  rule tables. Entires whose key/name begin with a "+" are added
+ * Merges two  rule tables. Entries whose key/name begin with a "+" are added
  * while those with a "-" prefix are removed.
  *
  * @param p Pool to allocate new table from.
@@ -10270,6 +10339,11 @@
       apr_table_set(r->subprocess_env, QS_ISVIPREQ, "yes");
     }
   }
+
+  if(sconf->log_env == 1) {
+    qos_log_env(r, ">FX_1");
+  }
+
 #if APR_HAS_THREADS
   qos_disable_rate(r, sconf, dconf);
 #endif
@@ -10313,11 +10387,14 @@
   }
   qos_propagate_notes(r);
   qos_propagate_events(r);
+  if(sconf->log_env == 1) {
+    qos_log_env(r, "<LG_1");
+  }
   qos_end_res_rate(r, sconf);
-  if(apr_table_elts(sconf->setenvif_t)->nelts > 0) {
+  if(sconf->setenvif_t->nelts > 0) {
     qos_setenvif(r, sconf->setenvif_t);
   }
-  if(apr_table_elts(dconf->setenvif_t)->nelts > 0) {
+  if(dconf->setenvif_t->nelts > 0) {
     qos_setenvif(r, dconf->setenvif_t);
   }
   if(sconf->has_qos_cc) {
@@ -10358,7 +10435,9 @@
         actEntry->counter--;
       }
       if(apr_table_get(r->notes, QS_R010_ALREADY_BLOCKED) == NULL) {
-        actEntry->req++;
+        if(actEntry->req < LONG_MAX) { 
+           actEntry->req++;
+        }
         if(now > (actEntry->interval + QS_BW_SAMPLING_RATE)) {
           actEntry->req_per_sec = actEntry->req / (now - actEntry->interval);
           actEntry->req = 0;
@@ -10396,7 +10475,7 @@
 #endif
 
   if(sconf->qslog_p) {
-    // ISBiDUkEQaC equiv %h %>s %B %{Content-Lenght}i %D %{mod_qos_user_id}e %k %{Event}e %{mod_qos_ev}e %{QS_AllConn}e '%v:%U'
+    // ISBiDUkEQaC equiv %h %>s %B %{Content-Length}i %D %{mod_qos_user_id}e %k %{Event}e %{mod_qos_ev}e %{QS_AllConn}e '%v:%U'
     apr_size_t nbytes;
     const char *clID = apr_table_get(r->subprocess_env, QSLOG_CLID); // client identifier (individual users)
     const char *event = apr_table_get(r->subprocess_env, QSLOG_EVENT); // generic event variable
@@ -10449,33 +10528,6 @@
   return DECLINED;
 }
 
-static int qos_chroot(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *bs) {
-  qos_srv_config *sconf = (qos_srv_config*)ap_get_module_config(bs->module_config, &qos_module);
-#ifndef QS_HAS_APACHE_PATH
-  qos_user_t *u = qos_get_user_conf(bs->process->pool);
-  if(u->server_start == 2) {
-#endif
-    if(sconf->chroot) {
-      int rc = 0;
-      ap_log_error(APLOG_MARK, APLOG_INFO, 0, bs, 
-                   QOS_LOG_PFX(000)"change root to %s", sconf->chroot);
-      if((rc = chroot(sconf->chroot)) < 0) {
-        ap_log_error(APLOG_MARK, APLOG_EMERG, 0, bs, 
-                     QOS_LOG_PFX(000)"chroot failed: %s", strerror(errno));
-        return !DECLINED;
-      }
-      if((rc = chdir("/")) < 0) {
-        ap_log_error(APLOG_MARK, APLOG_EMERG, 0, bs, 
-                     QOS_LOG_PFX(000)"chroot failed (chdir /): %s", strerror(errno));
-        return !DECLINED;
-      }
-    }
-#ifndef QS_HAS_APACHE_PATH
-  }
-#endif
-  return DECLINED;
-}
-
 /**
  * inits each child
  */
@@ -10590,13 +10642,18 @@
   qos_srv_config *bsconf = (qos_srv_config*)ap_get_module_config(bs->module_config, &qos_module);
   char *rev = qos_revision(ptemp);
   qos_user_t *u;
-  int maxClients = qs_calc_maxClients(bs, bsconf);
+  int maxClients;
   int cc_net_prefer_limit = 0;
   apr_status_t rv;
   ap_directive_t *pdir = ap_conftree;
   const char *error_page = detectErrorPage(ptemp, bs, pdir);
   int auto_error_page = 0;
 
+  /* verify if this Apache version is supported/mod_qos has been tested for
+     and enable/disable features */
+  qos_version_check(bs);
+
+  maxClients = qs_calc_maxClients(bs, bsconf);
   QOS_MY_GENERATION(m_generation);
   bsconf->max_clients = maxClients;
   
@@ -10617,9 +10674,6 @@
                  QOS_LOG_PFX(100)"QS_ClientGeoCountryDB has not been configured");
   }
 
-  // verify if this Apache version is supported/mod_qos has been tested for
-  qos_version_check(bs);
-
   if(bsconf->max_conn_close_percent) {
     bsconf->max_conn_close = maxClients * bsconf->max_conn_close_percent / 100;
   }
@@ -10671,6 +10725,11 @@
   }
   qos_audit_check(ap_conftree);
   qos_is_https = APR_RETRIEVE_OPTIONAL_FN(ssl_is_https);
+  qos_ssl_var = APR_RETRIEVE_OPTIONAL_FN(ssl_var_lookup);
+  if(qos_is_https == NULL || qos_ssl_var == NULL) {
+    ap_log_error(APLOG_MARK, APLOG_INFO, 0, bs, 
+                 QOS_LOG_PFX(009)"could not retrieve mod_ssl functions");
+  }
   if(m_requires_parp) {
     if(qos_module_check("mod_parp.c") != APR_SUCCESS) {
       qos_parp_hp_table_fn = NULL;
@@ -10724,11 +10783,7 @@
             entryConf->preg = NULL;
             if(newentry->condStr) {
               entryConf->condStr = apr_pstrdup(bs->process->pool, newentry->condStr);
-#ifdef AP_REGEX_H
               entryConf->preg = ap_pregcomp(bs->process->pool, newentry->condStr, AP_REG_EXTENDED);
-#else
-              entryConf->preg = ap_pregcomp(bs->process->pool, newentry->condStr, REG_EXTENDED);
-#endif
             }
           } else {
             // new variable
@@ -10946,7 +11001,7 @@
     int i = 0;
     qos_user_t *u = qos_get_user_conf(sconf->act->ppool);
     qos_s_entry_t **clientEntry = NULL;
-    /* table requires heap (100'000 ~ 4MB) but we avaoid io with drawn lock */
+    /* table requires heap (100'000 ~ 4MB) but we avoid io with drawn lock */
     apr_table_t *iptable = apr_table_make(r->pool, u->qos_cc->max);
     apr_table_entry_t *entry;
     apr_time_t now = apr_time_sec(r->request_time);
@@ -10969,7 +11024,7 @@
           }
         }
         k = apr_psprintf(r->pool,
-                         "%010d %s vip=%s lowprio=%s block=%d/%ld limit=%d/%ld %ld",
+                         "%010d %s vip=%s lowprio=%s block=%hu/%ld limit=%d/%ld %ld",
                          i,
                          qos_ip_long2str(r->pool, clientEntry[i]->ip6),
                          clientEntry[i]->vip ? "yes" : "no",
@@ -11191,7 +11246,9 @@
           (*clientEntry)->limit[limitTableIndex].limitTime = 0;
         }
         // increment limit event
-        (*clientEntry)->limit[limitTableIndex].limit++;
+        if((*clientEntry)->limit[limitTableIndex].limit < USHRT_MAX) {
+          (*clientEntry)->limit[limitTableIndex].limit++;
+        }
         if((*clientEntry)->limit[limitTableIndex].limit == 1) {
           // first, start timer
           (*clientEntry)->limit[limitTableIndex].limitTime = now;
@@ -11211,7 +11268,7 @@
         limitTime = (eventLimitConf->limitTime >= (time(NULL) - (*clientEntry)->limit[limitTableIndex].limitTime)) ? 
           (eventLimitConf->limitTime - (time(NULL) - (*clientEntry)->limit[limitTableIndex].limitTime)) : 0;
       }
-      msg = apr_psprintf(r->pool, "%s vip=%s lowprio=%s block=%d/%ld limit=%d/%ld", ip,
+      msg = apr_psprintf(r->pool, "%s vip=%s lowprio=%s block=%hu/%ld limit=%d/%ld", ip,
                          (*clientEntry)->vip ? "yes" : "no",
                          ((*clientEntry)->lowrate + QOS_LOW_TIMEOUT) > now ? "yes" : "no",
                          (*clientEntry)->block,
@@ -11254,7 +11311,7 @@
                   qos_unique_id(r, "072"));
     return DECLINED;
   }
-  if(r->parsed_uri.path && (strstr(r->parsed_uri.path, "favicon.ico") != NULL)) {
+  if(strstr(r->parsed_uri.path, "favicon.ico") != NULL) {
     apr_table_add(r->err_headers_out, "Cache-Control", "public, max-age=2592000");
     return qos_favicon(r);
   }
@@ -11278,7 +11335,7 @@
     }
     ap_rputs("<html><head><title>mod_qos</title>\n", r);
     ap_rprintf(r,"<link rel=\"shortcut icon\" href=\"%s%sfavicon.ico\"/>\n", 
-               r->parsed_uri.path,
+               ap_escape_html(r->pool, r->parsed_uri.path),
                hasSlash ? "" : "/");
     ap_rputs("<meta http-equiv=\"content-type\" content=\"text/html; charset=ISO-8859-1\">\n", r);
     ap_rputs("<meta name=\"author\" content=\"Pascal Buchbinder\">\n", r);
@@ -11445,7 +11502,7 @@
   dconf->redirectif = apr_array_make(p, 20, sizeof(qos_redirectif_entry_t));
   dconf->disable_reqrate_events = apr_table_make(p, 1);
   dconf->setenvstatus_t = apr_table_make(p, 5);
-  dconf->setenvif_t = apr_table_make(p, 1);
+  dconf->setenvif_t = apr_array_make(p, 20, sizeof(qos_setenvif_t));
   dconf->setenvifquery_t = apr_table_make(p, 1);
   dconf->setenvcmp = apr_array_make(p, 2, sizeof(qos_cmp_entry_t));
   return dconf;
@@ -11516,8 +11573,7 @@
   dconf->setenvstatus_t = apr_table_copy(p, b->setenvstatus_t);
   qos_table_merge(dconf->setenvstatus_t, o->setenvstatus_t);
 
-  dconf->setenvif_t = apr_table_copy(p, b->setenvif_t);
-  qos_table_merge(dconf->setenvif_t, o->setenvif_t);
+  dconf->setenvif_t = apr_array_append(p, b->setenvif_t, o->setenvif_t);
 
   dconf->setenvifquery_t = apr_table_copy(p, b->setenvifquery_t);
   qos_table_merge(dconf->setenvifquery_t, o->setenvifquery_t);
@@ -11533,9 +11589,8 @@
   apr_pool_create(&act_pool, NULL);
   sconf =(qos_srv_config *)apr_pcalloc(p, sizeof(qos_srv_config));
   sconf->pool = p;
-  sconf->chroot = NULL;
   sconf->location_t = apr_table_make(sconf->pool, 2);
-  sconf->setenvif_t = apr_table_make(sconf->pool, 1);
+  sconf->setenvif_t = apr_array_make(sconf->pool, 20, sizeof(qos_setenvif_t));
   sconf->setenv_t = apr_table_make(sconf->pool, 1);
   sconf->setreqheader_t = apr_table_make(sconf->pool, 5);
   sconf->setreqheaderlate_t = apr_table_make(sconf->pool, 5);
@@ -11603,6 +11658,7 @@
   sconf->reshfilter_table = apr_table_make(p, 5);
   sconf->disable_reqrate_events = apr_table_make(p, 1);
   sconf->log_only = 0;
+  sconf->log_env = -1;
   sconf->has_qos_cc = 0;
   sconf->cc_exclude_ip = apr_table_make(sconf->pool, 2);
   sconf->qos_cc_size = 50000;
@@ -11618,6 +11674,7 @@
   sconf->geodb = NULL;
   sconf->geo_limit = -1;
   sconf->geo_priv = apr_table_make(p, 20);
+  sconf->geo_excludeUnknown = -1;
   sconf->qslog_p = NULL;
   sconf->qsstatus = 0;
   sconf->qsevents = 0;
@@ -11698,10 +11755,12 @@
   qos_srv_config *b = (qos_srv_config *)basev;
   qos_srv_config *o = (qos_srv_config *)addv;
   /* GLOBAL ONLY directives: */
-  o->chroot = b->chroot;
   o->hfilter_table = b->hfilter_table;
   o->reshfilter_table = b->reshfilter_table;
   o->log_only = b->log_only;
+  if(o->log_env == -1) {
+    o->log_env = b->log_env;
+  }
   o->has_qos_cc = b->has_qos_cc;
   o->cc_exclude_ip = b->cc_exclude_ip;
   o->qos_cc_size = b->qos_cc_size;
@@ -11719,6 +11778,7 @@
   o->geodb = b->geodb;
   o->geo_limit = b->geo_limit;
   o->geo_priv = b->geo_priv;
+  o->geo_excludeUnknown = b->geo_excludeUnknown;
   o->qslog_p = b->qslog_p;
   o->qsstatus = b->qsstatus;
   o->qsevents = b->qsevents;
@@ -11741,7 +11801,7 @@
     o->error_page = b->error_page;
   }
   qos_table_merge(o->location_t, b->location_t);
-  qos_table_merge(o->setenvif_t, b->setenvif_t);
+  o->setenvif_t =  apr_array_append(p, b->setenvif_t, o->setenvif_t);
   qos_table_merge(o->setenv_t, b->setenv_t);
   qos_table_merge(o->setreqheader_t, b->setreqheader_t);
   qos_table_merge(o->setreqheaderlate_t, b->setreqheaderlate_t);
@@ -11860,6 +11920,16 @@
   return NULL;
 }
 
+const char *qos_logenv_cmd(cmd_parms *cmd, void *dcfg, int flag) {
+  qos_srv_config *sconf = (qos_srv_config*)ap_get_module_config(cmd->server->module_config,
+                                                                &qos_module);
+  sconf->log_env = flag;
+  return NULL;
+}
+
+/**
+ * QS_MaxClients
+ */
 const char *qos_maxclients_cmd(cmd_parms *cmd, void *dcfg, const char *arg1) {
   qos_srv_config *sconf = (qos_srv_config*)ap_get_module_config(cmd->server->module_config,
                                                                 &qos_module);
@@ -11992,13 +12062,9 @@
     return apr_psprintf(cmd->pool, "%s: number must be numeric value >=0", 
                         cmd->directive->directive);
   }
-#ifdef AP_REGEX_H
   rule->regex = ap_pregcomp(cmd->pool, match, AP_REG_EXTENDED);
-#else
-  rule->regex = ap_pregcomp(cmd->pool, match, REG_EXTENDED);
-#endif
   if(rule->regex == NULL) {
-    return apr_psprintf(cmd->pool, "%s: failed to compile regular expession (%s)",
+    return apr_psprintf(cmd->pool, "%s: failed to compile regular expression (%s)",
                        cmd->directive->directive, match);
   }
   rule->event = NULL;
@@ -12022,19 +12088,14 @@
     return apr_psprintf(cmd->pool, "%s: number must be numeric value >=0", 
                         cmd->directive->directive);
   }
-#ifdef AP_REGEX_H
   rule->regex = ap_pregcomp(cmd->pool, match, AP_REG_EXTENDED);
   rule->condition = ap_pregcomp(cmd->pool, pattern, AP_REG_EXTENDED);
-#else
-  rule->regex = ap_pregcomp(cmd->pool, match, REG_EXTENDED);
-  rule->condition = ap_pregcomp(cmd->pool, pattern, REG_EXTENDED);
-#endif
   if(rule->regex == NULL) {
-    return apr_psprintf(cmd->pool, "%s: failed to compile regular expession (%s)",
+    return apr_psprintf(cmd->pool, "%s: failed to compile regular expression (%s)",
                        cmd->directive->directive, match);
   }
   if(rule->condition == NULL) {
-    return apr_psprintf(cmd->pool, "%s: failed to compile regular expession (%s)",
+    return apr_psprintf(cmd->pool, "%s: failed to compile regular expression (%s)",
                        cmd->directive->directive, pattern);
   }
   rule->event = NULL;
@@ -12059,13 +12120,9 @@
     return apr_psprintf(cmd->pool, "%s: number must be numeric value >0", 
                         cmd->directive->directive);
   }
-#ifdef AP_REGEX_H
   rule->regex = ap_pregcomp(cmd->pool, match, AP_REG_EXTENDED);
-#else
-  rule->regex = ap_pregcomp(cmd->pool, match, REG_EXTENDED);
-#endif
   if(rule->regex == NULL) {
-    return apr_psprintf(cmd->pool, "%s: failed to compile regular expession (%s)",
+    return apr_psprintf(cmd->pool, "%s: failed to compile regular expression (%s)",
                        cmd->directive->directive, match);
   }
   rule->event = NULL;
@@ -12091,13 +12148,9 @@
     return apr_psprintf(cmd->pool, "%s: number must be numeric value >0", 
                         cmd->directive->directive);
   }
-#ifdef AP_REGEX_H
   rule->regex = ap_pregcomp(cmd->pool, match, AP_REG_EXTENDED);
-#else
-  rule->regex = ap_pregcomp(cmd->pool, match, REG_EXTENDED);
-#endif
   if(rule->regex == NULL) {
-    return apr_psprintf(cmd->pool, "%s: failed to compile regular expession (%s)",
+    return apr_psprintf(cmd->pool, "%s: failed to compile regular expression (%s)",
                        cmd->directive->directive, match);
   }
   rule->event = NULL;
@@ -12132,11 +12185,7 @@
   sconf->has_event_filter = 1;
   if(p) {
     p++;
-#ifdef AP_REGEX_H
     rule->regex_var = ap_pregcomp(cmd->pool, p, AP_REG_EXTENDED);
-#else
-    rule->regex_var = ap_pregcomp(cmd->pool, p, REG_EXTENDED);
-#endif
     if(rule->regex_var == NULL) {
       return apr_psprintf(cmd->pool, "%s: failed to compile regex (%s)",
                           cmd->directive->directive, p);
@@ -12221,11 +12270,7 @@
                         cmd->directive->directive);
   }
   new->condStr = apr_pstrdup(cmd->pool, argv[3]);
-#ifdef AP_REGEX_H
   new->preg = ap_pregcomp(cmd->pool, new->condStr, AP_REG_EXTENDED);
-#else
-  new->preg = ap_pregcomp(cmd->pool, new->condStr, REG_EXTENDED);
-#endif
   if(new->preg == NULL) {
     return apr_psprintf(cmd->pool, "%s: failed to compile regex (%s)",
                         cmd->directive->directive, new->condStr);
@@ -12412,17 +12457,12 @@
                                                const char *pcres) {
   qos_srv_config *sconf = (qos_srv_config*)ap_get_module_config(cmd->server->module_config,
                                                                 &qos_module);
-  const char *errptr = NULL;
-  int erroffset;
-  pcre *pr = pcre_compile(pcres, PCRE_DOTALL | PCRE_CASELESS, &errptr, &erroffset, NULL);
-  if(pr == NULL) {
-    return apr_psprintf(cmd->pool, "%s: could not compile pcre at position %d,"
-                        " reason: %s", 
-                        cmd->directive->directive,
-                        erroffset, errptr);
+  ap_regex_t *preg = ap_pregcomp(cmd->pool, pcres, AP_REG_DOTALL | AP_REG_ICASE);
+  if(preg == NULL) {
+    return apr_psprintf(cmd->pool, "%s: could not compile regular expression '%s'",
+                        cmd->directive->directive, pcres);
   }
-  apr_pool_cleanup_register(cmd->pool, pr, (int(*)(void*))pcre_free, apr_pool_cleanup_null);
-  apr_table_setn(sconf->setenvresheadermatch_t, apr_pstrdup(cmd->pool, hdr), (char *)pr);
+  apr_table_setn(sconf->setenvresheadermatch_t, apr_pstrdup(cmd->pool, hdr), (char *)preg);
   return NULL;
 }
 
@@ -12438,13 +12478,9 @@
     new = apr_array_push(sconf->redirectif);
   }
   new->name = apr_pstrdup(cmd->pool, var);
-#ifdef AP_REGEX_H
   new->preg = ap_pregcomp(cmd->pool, pattern, (AP_REG_EXTENDED | AP_REG_ICASE));
-#else
-  new->preg = ap_pregcomp(cmd->pool, pattern, (REG_EXTENDED | REG_ICASE));
-#endif
   if(new->preg == NULL) {
-    return apr_psprintf(cmd->pool, "%s: could not compile regex %s",
+    return apr_psprintf(cmd->pool, "%s: could not compile regular expression %s",
                         cmd->directive->directive, pattern);
   }
   if(strncasecmp(url, "307:", 4) == 0) {
@@ -12474,13 +12510,9 @@
     pregval->value[0] = '\0';
     pregval->value++;
   }
-#ifdef AP_REGEX_H
   pregval->preg = ap_pregcomp(cmd->pool, pattern, AP_REG_EXTENDED);
-#else
-  pregval->preg = ap_pregcomp(cmd->pool, pattern, REG_EXTENDED);
-#endif
   if(pregval->preg == NULL) {
-    return apr_psprintf(cmd->pool, "%s: could not compile regex %s",
+    return apr_psprintf(cmd->pool, "%s: could not compile regular expression '%s'",
                         cmd->directive->directive, pattern);
   }
   apr_table_addn(sconf->setenvres_t, apr_pstrdup(cmd->pool, var), (char *)pregval);
@@ -12492,7 +12524,14 @@
                                    const char *a3) {
   qos_srv_config *sconf = (qos_srv_config*)ap_get_module_config(cmd->server->module_config,
                                                                 &qos_module);
-  qos_setenvif_t *setenvif = apr_pcalloc(cmd->pool, sizeof(qos_setenvif_t));
+  qos_setenvif_t *setenvif;
+  if(cmd->path) {
+    qos_dir_config *dconf = (qos_dir_config*)dcfg;
+    setenvif = apr_array_push(dconf->setenvif_t);
+  } else {
+    setenvif = apr_array_push(sconf->setenvif_t);
+  }
+
   if(a3) {
     // mode 1 (boolean AND operator)
     setenvif->variable1 = apr_pstrdup(cmd->pool, v1);
@@ -12523,11 +12562,7 @@
     pattern[0] = '\0';
     pattern++;
     setenvif->variable2 = NULL;
-#ifdef AP_REGEX_H
     setenvif->preg = ap_pregcomp(cmd->pool, pattern, AP_REG_EXTENDED);
-#else
-    setenvif->preg = ap_pregcomp(cmd->pool, pattern, REG_EXTENDED);
-#endif
     if(setenvif->preg == NULL) {
       return apr_psprintf(cmd->pool, "%s: failed to compile regex (%s)",
                           cmd->directive->directive, pattern);
@@ -12546,12 +12581,6 @@
       setenvif->value++;
     }
   }
-  if(cmd->path) {
-    qos_dir_config *dconf = (qos_dir_config*)dcfg;
-    apr_table_setn(dconf->setenvif_t, apr_pstrcat(cmd->pool, v1, v2, a3, NULL), (char *)setenvif);
-  } else {
-    apr_table_setn(sconf->setenvif_t, apr_pstrcat(cmd->pool, v1, v2, a3, NULL), (char *)setenvif);
-  }
   return NULL;
 }
 
@@ -12596,11 +12625,7 @@
                                                                 &qos_module);
   qos_setenvifquery_t *setenvif = apr_pcalloc(cmd->pool, sizeof(qos_setenvifquery_t));
   char *p;
-#ifdef AP_REGEX_H
   setenvif->preg = ap_pregcomp(cmd->pool, rx, AP_REG_EXTENDED);
-#else
-  setenvif->preg = ap_pregcomp(cmd->pool, rx, REG_EXTENDED);
-#endif
   if(setenvif->preg == NULL) {
     return apr_psprintf(cmd->pool, "%s: failed to compile regex (%s)",
                         cmd->directive->directive, rx);
@@ -12633,22 +12658,7 @@
                                                                 &qos_module);
   qos_setenvifparpbody_t *setenvif = apr_pcalloc(cmd->pool, sizeof(qos_setenvifparpbody_t));
   char *p;
-  const char *errptr = NULL;
-  int erroffset;
-#ifdef AP_REGEX_H
-  setenvif->pregx = ap_pregcomp(cmd->pool, rx, AP_REG_EXTENDED | AP_REG_ICASE);
-#else
-  setenvif->pregx = ap_pregcomp(cmd->pool, rx, REG_EXTENDED | REG_ICASE);
-#endif
-  setenvif->preg = pcre_compile(rx, PCRE_DOTALL | PCRE_CASELESS, &errptr, &erroffset, NULL);
-  if(setenvif->preg == NULL) {
-    return apr_psprintf(cmd->pool, "%s: could not compile pcre at position %d,"
-                        " reason: %s", 
-                        cmd->directive->directive,
-                        erroffset, errptr);
-  }
-  setenvif->extra = qos_pcre_study(cmd->pool, setenvif->preg);
-  apr_pool_cleanup_register(cmd->pool, setenvif->preg, (int(*)(void*))pcre_free, apr_pool_cleanup_null);
+  setenvif->pregx = ap_pregcomp(cmd->pool, rx, AP_REG_DOTALL | AP_REG_EXTENDED | AP_REG_ICASE);
   if(setenvif->pregx == NULL) {
     return apr_psprintf(cmd->pool, "%s: failed to compile regex (%s)",
                         cmd->directive->directive, rx);
@@ -12672,11 +12682,7 @@
                                                                 &qos_module);
   qos_setenvifquery_t *setenvif = apr_pcalloc(cmd->pool, sizeof(qos_setenvifquery_t));
   char *p;
-#ifdef AP_REGEX_H
   setenvif->preg = ap_pregcomp(cmd->pool, rx, AP_REG_EXTENDED);
-#else
-  setenvif->preg = ap_pregcomp(cmd->pool, rx, REG_EXTENDED);
-#endif
   if(setenvif->preg == NULL) {
     return apr_psprintf(cmd->pool, "%s: failed to compile regex (%s)",
                         cmd->directive->directive, rx);
@@ -12758,33 +12764,6 @@
 }
 
 /**
- * path to chrooted jail
- */
-const char *qos_chroot_cmd(cmd_parms *cmd, void *dcfg, const char *arg) {
-  char cwd[2048] = "";
-  qos_srv_config *sconf = ap_get_module_config(cmd->server->module_config, &qos_module);
-  const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
-  if (err != NULL) {
-    return err;
-  }
-  sconf->chroot = apr_pstrdup(cmd->pool, arg);
-  if(getcwd(cwd, sizeof(cwd)) == NULL) {
-    return apr_psprintf(cmd->pool, "%s: failed to examine current working directory",
-                        cmd->directive->directive);
-  }
-  if(chdir(sconf->chroot) < 0) {
-    return apr_psprintf(cmd->pool, "%s: change dir to %s failed",
-                        cmd->directive->directive, sconf->chroot);
-  }
-  if(chdir(cwd) < 0) {
-    return apr_psprintf(cmd->pool, "%s: change dir to %s failed",
-                        cmd->directive->directive, cwd);
-  }
- 
-  return NULL;
-}
-
-/**
  * global error code setting
  */
 const char *qos_error_code_cmd(cmd_parms *cmd, void *dcfg, const char *arg) {
@@ -12808,6 +12787,18 @@
   return NULL;
 }
 
+/**
+ * global connection close behavior
+ */
+const char *qos_forced_close_cmd(cmd_parms *cmd, void *dcfg, int flag) {
+  const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
+  if (err != NULL) {
+    return err;
+  }
+  m_forced_close = flag;
+  return NULL;
+}
+
 /** QS_UserTrackingCookieName */
 
 #ifdef AP_TAKE_ARGV
@@ -12929,11 +12920,7 @@
   if(p) {
     p[0] = '\0';
     p++;
-#ifdef AP_REGEX_H
     sconf->header_name_regex = ap_pregcomp(cmd->pool, p, AP_REG_EXTENDED);
-#else
-    sconf->header_name_regex = ap_pregcomp(cmd->pool, p, REG_EXTENDED);
-#endif
     if(sconf->header_name_regex == NULL) {
       return apr_psprintf(cmd->pool, "%s: failed to compile regex (%s)",
                           cmd->directive->directive, p);
@@ -12958,11 +12945,7 @@
   if(p) {
     p[0] = '\0';
     p++;
-#ifdef AP_REGEX_H
     sconf->ip_header_name_regex = ap_pregcomp(cmd->pool, p, AP_REG_EXTENDED);
-#else
-    sconf->ip_header_name_regex = ap_pregcomp(cmd->pool, p, REG_EXTENDED);
-#endif
     if(sconf->ip_header_name_regex == NULL) {
       return apr_psprintf(cmd->pool, "%s: failed to compile regex (%s)",
                           cmd->directive->directive, p);
@@ -13023,7 +13006,7 @@
     sconf->max_conn_close = atoi(n);
     sconf->max_conn_close_percent = sconf->max_conn_close;
     if(sconf->max_conn_close > 99) {
-      return apr_psprintf(cmd->pool, "%s: number must be a percentage <99", 
+      return apr_psprintf(cmd->pool, "%s: number must be a percentage <100", 
                           cmd->directive->directive);
     }
   } else {
@@ -13031,7 +13014,7 @@
     sconf->max_conn_close_percent = 0;
   }
   if(sconf->max_conn_close == 0) {
-    return apr_psprintf(cmd->pool, "%s: number must be numeric value >0", 
+    return apr_psprintf(cmd->pool, "%s: number must be >0", 
                         cmd->directive->directive);
   }
   return NULL;
@@ -13266,8 +13249,6 @@
                          qs_rfilter_type_e type, int options) {
   qos_dir_config *dconf = (qos_dir_config*)dcfg;
   qos_rfilter_t *flt = apr_pcalloc(cmd->pool, sizeof(qos_rfilter_t));
-  const char *errptr = NULL;
-  int erroffset;
   flt->type = type;
   if(((id[0] != '+') && (id[0] != '-')) || (strlen(id) < 2)) {
     return apr_psprintf(cmd->pool, "%s: invalid rule id", 
@@ -13283,15 +13264,12 @@
                         cmd->directive->directive);
   }
   if(flt->type != QS_DENY_EVENT) {
-    flt->pr = pcre_compile(pcres, PCRE_DOTALL | options, &errptr, &erroffset, NULL);
-    if(flt->pr == NULL) {
-      return apr_psprintf(cmd->pool, "%s: could not compile pcre at position %d,"
-                          " reason: %s", 
+    flt->preg = ap_pregcomp(cmd->pool, pcres, AP_REG_DOTALL | options);
+    if(flt->preg == NULL) {
+      return apr_psprintf(cmd->pool, "%s: could not compile regular expression '%s'",
                           cmd->directive->directive,
-                          erroffset, errptr);
+                          pcres);
     }
-    flt->extra = qos_pcre_study(cmd->pool, flt->pr);
-    apr_pool_cleanup_register(cmd->pool, flt->pr, (int(*)(void*))pcre_free, apr_pool_cleanup_null);
   }
   flt->text = apr_pstrdup(cmd->pool, pcres);
   apr_table_setn(dconf->rfilter_table, apr_pstrdup(cmd->pool, id), (char *)flt);
@@ -13299,15 +13277,15 @@
 }
 const char *qos_deny_rql_cmd(cmd_parms *cmd, void *dcfg,
                              const char *id, const char *action, const char *pcres) {
-  return qos_deny_cmd(cmd, dcfg, id, action, pcres, QS_DENY_REQUEST_LINE, PCRE_CASELESS);
+  return qos_deny_cmd(cmd, dcfg, id, action, pcres, QS_DENY_REQUEST_LINE, AP_REG_ICASE);
 }
 const char *qos_deny_path_cmd(cmd_parms *cmd, void *dcfg,
                               const char *id, const char *action, const char *pcres) {
-  return qos_deny_cmd(cmd, dcfg, id, action, pcres, QS_DENY_PATH, PCRE_CASELESS);
+  return qos_deny_cmd(cmd, dcfg, id, action, pcres, QS_DENY_PATH, AP_REG_ICASE);
 }
 const char *qos_deny_query_cmd(cmd_parms *cmd, void *dcfg,
                                const char *id, const char *action, const char *pcres) {
-  return qos_deny_cmd(cmd, dcfg, id, action, pcres, QS_DENY_QUERY, PCRE_CASELESS);
+  return qos_deny_cmd(cmd, dcfg, id, action, pcres, QS_DENY_QUERY, AP_REG_ICASE);
 }
 const char *qos_deny_event_cmd(cmd_parms *cmd, void *dcfg,
                                const char *id, const char *action, const char *event) {
@@ -13345,8 +13323,6 @@
 const char *qos_milestone_cmd(cmd_parms *cmd, void *dcfg, const char *action,
                               const char *pattern, const char *thinktimestr) {
   qos_srv_config *sconf = ap_get_module_config(cmd->server->module_config, &qos_module);
-  const char *errptr = NULL;
-  int erroffset;
   qos_milestone_t *ms;
   if(sconf->milestones == NULL) {
     sconf->milestones = apr_array_make(cmd->pool, 100, sizeof(qos_milestone_t));
@@ -13362,16 +13338,11 @@
   } else {
     ms->thinktime = 0;
   }
-  ms->preg = pcre_compile(pattern, PCRE_DOTALL, &errptr, &erroffset, NULL);
+  ms->preg = ap_pregcomp(cmd->pool, pattern, AP_REG_DOTALL);
   if(ms->preg == NULL) {
-    return apr_psprintf(cmd->pool, "%s: could not compile pcre %s at position %d,"
-                        " reason: %s", 
-                        cmd->directive->directive,
-                        pattern,
-                        erroffset, errptr);
+    return apr_psprintf(cmd->pool, "%s: could not compile regular expression '%s'",
+                        cmd->directive->directive, pattern);
   }
-  apr_pool_cleanup_register(cmd->pool, ms->preg, (int(*)(void*))pcre_free, apr_pool_cleanup_null);
-  ms->extra = qos_pcre_study(cmd->pool, ms->preg);
   ms->pattern = apr_pstrdup(cmd->pool, pattern);
   if(strcasecmp(action, "deny") == 0) {
     ms->action = QS_DENY;
@@ -13513,8 +13484,6 @@
   {
   qos_srv_config *sconf = (qos_srv_config*)ap_get_module_config(cmd->server->module_config,
                                                                 &qos_module);
-  const char *errptr = NULL;
-  int erroffset;
   qos_fhlt_r_t *he;
 #ifdef AP_TAKE_ARGV
   const char *header;
@@ -13541,7 +13510,7 @@
   he->size = 9000;
 #endif
   he->text = apr_pstrdup(cmd->pool, rule);
-  he->pcre = pcre_compile(rule, PCRE_DOTALL, &errptr, &erroffset, NULL);
+  he->preg = ap_pregcomp(cmd->pool, rule, AP_REG_DOTALL);
   if(strcasecmp(action, "deny") == 0) {
     he->action = QS_FLT_ACTION_DENY;
   } else if(strcasecmp(action, "drop") == 0) {
@@ -13550,20 +13519,15 @@
     return apr_psprintf(cmd->pool, "%s: invalid action %s",
                         cmd->directive->directive, action);
   }
-  if(he->pcre == NULL) {
-    return apr_psprintf(cmd->pool, "%s: could not compile pcre %s at position %d,"
-                        " reason: %s", 
-                        cmd->directive->directive,
-                        rule,
-                        erroffset, errptr);
+  if(he->preg == NULL) {
+    return apr_psprintf(cmd->pool, "%s: could not compile regular expression '%s'",
+                        cmd->directive->directive, rule);
   }
-  he->extra = qos_pcre_study(cmd->pool, he->pcre);
   if(he->size <= 0) {
     return apr_psprintf(cmd->pool, "%s: size must be numeric value >0",
                         cmd->directive->directive);
   }
   apr_table_setn(sconf->hfilter_table, apr_pstrdup(cmd->pool, header), (char *)he);
-  apr_pool_cleanup_register(cmd->pool, he->pcre, (int(*)(void*))pcre_free, apr_pool_cleanup_null);
   return NULL;
 }
 
@@ -13572,8 +13536,6 @@
                                          const char *rule, const char *size) {
   qos_srv_config *sconf = (qos_srv_config*)ap_get_module_config(cmd->server->module_config,
                                                                 &qos_module);
-  const char *errptr = NULL;
-  int erroffset;
   qos_fhlt_r_t *he;
   const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
   if (err != NULL) {
@@ -13582,22 +13544,17 @@
   he = apr_pcalloc(cmd->pool, sizeof(qos_fhlt_r_t));
   he->size = atoi(size);
   he->text = apr_pstrdup(cmd->pool, rule);
-  he->pcre = pcre_compile(rule, PCRE_DOTALL, &errptr, &erroffset, NULL);
+  he->preg = ap_pregcomp(cmd->pool, rule, AP_REG_DOTALL);
   he->action = QS_FLT_ACTION_DROP;
-  if(he->pcre == NULL) {
-    return apr_psprintf(cmd->pool, "%s: could not compile pcre %s at position %d,"
-                        " reason: %s", 
-                        cmd->directive->directive,
-                        rule,
-                        erroffset, errptr);
+  if(he->preg == NULL) {
+    return apr_psprintf(cmd->pool, "%s: could not compile regular expression '%s'",
+                        cmd->directive->directive, rule);
   }
-  he->extra = qos_pcre_study(cmd->pool, he->pcre);
   if(he->size <= 0) {
     return apr_psprintf(cmd->pool, "%s: size must be numeric value >0",
                         cmd->directive->directive);
   }
   apr_table_setn(sconf->reshfilter_table, apr_pstrdup(cmd->pool, header), (char *)he);
-  apr_pool_cleanup_register(cmd->pool, he->pcre, (int(*)(void*))pcre_free, apr_pool_cleanup_null);
   return NULL;  
 }
 
@@ -13625,12 +13582,11 @@
                         errors);
   }
 
-  //apr_pool_pre_cleanup_register(cmd->pool, geodb, qos_cleanup_geodb);
-
   return NULL;
 }
 
-const char *qos_geopriv_cmd(cmd_parms *cmd, void *dcfg, const char *list, const char *con) {
+const char *qos_geopriv_cmd(cmd_parms *cmd, void *dcfg, const char *list, const char *con,
+                            const char *excludeUnknown) {
   qos_srv_config *sconf = (qos_srv_config*)ap_get_module_config(cmd->server->module_config,
                                                                 &qos_module);
   char *next = apr_pstrdup(cmd->pool, list);
@@ -13658,6 +13614,13 @@
     return apr_psprintf(cmd->pool, "%s: already configured with a different limitation",
                         cmd->directive->directive);
   }
+  if(excludeUnknown != NULL) {
+    if(strcasecmp(excludeUnknown, excludeUnknown) != 0) {
+      return apr_psprintf(cmd->pool, "%s: invalid argument %s",
+                          cmd->directive->directive, excludeUnknown);
+    }
+    sconf->geo_excludeUnknown = 1;
+  }
   sconf->geo_limit = geo_limit;
   return NULL;
 }
@@ -13785,9 +13748,9 @@
   }
   sconf->has_qos_cc = 1;
   sconf->qos_cc_block = atoi(arg1);
-  if((sconf->qos_cc_block < 0) || ((sconf->qos_cc_block == 0) && (strcmp(arg1, "0") != 0))) {
-    return apr_psprintf(cmd->pool, "%s: number must be numeric value >=0", 
-                        cmd->directive->directive);
+  if((sconf->qos_cc_block < 0) || sconf->qos_cc_block >= (USHRT_MAX-1) || ((sconf->qos_cc_block == 0) && (strcmp(arg1, "0") != 0))) {
+    return apr_psprintf(cmd->pool, "%s: number must be numeric value >=0 and <%d.", 
+                        cmd->directive->directive, USHRT_MAX-1);
   }
   if(arg2) {
     sconf->qos_cc_blockTime = atoi(arg2);
@@ -13814,9 +13777,9 @@
   }
   sconf->has_qos_cc = 1;
   limit = atoi(arg_number);
-  if((limit < 0) || ((limit == 0) && (strcmp(arg_number, "0") != 0))) {
-    return apr_psprintf(cmd->pool, "%s: number must be numeric value >=0", 
-                        cmd->directive->directive);
+  if((limit < 0) || limit >= (USHRT_MAX-1) || ((limit == 0) && (strcmp(arg_number, "0") != 0))) {
+    return apr_psprintf(cmd->pool, "%s: number must be numeric value >=0 and <%d.", 
+                        cmd->directive->directive, USHRT_MAX-1);
   }
   if(arg_sec) {
     limitTime = atoi(arg_sec);
@@ -13834,11 +13797,7 @@
   entry->preg = NULL;
   if(arg_condition) {
     entry->condStr = apr_pstrdup(cmd->pool, arg_condition);
-#ifdef AP_REGEX_H
     entry->preg = ap_pregcomp(cmd->pool, entry->condStr, AP_REG_EXTENDED);
-#else
-    entry->preg = ap_pregcomp(cmd->pool, entry->condStr, REG_EXTENDED);
-#endif
     if(entry->preg == NULL) {
       return apr_psprintf(cmd->pool, "%s: failed to compile regex (%s)",
                           cmd->directive->directive, entry->condStr);
@@ -14154,7 +14113,7 @@
   AP_INIT_TAKE1("QS_SrvMaxConnExcludeIP", qos_max_conn_ex_cmd, NULL,
                 RSRC_CONF,
                 "QS_SrvMaxConnExcludeIP <addr>, excludes an IP address or"
-                " address range from beeing limited."),
+                " address range from being limited."),
 
   AP_INIT_FLAG("QS_SrvMaxConnPerIPIgnoreVIP", qos_max_conn_ip_vip_off_cmd, NULL,
                 RSRC_CONF,
@@ -14181,14 +14140,14 @@
   AP_INIT_TAKE12("QS_SrvRequestRate", qos_req_rate_cmd, NULL,
                  RSRC_CONF,
                  "QS_SrvRequestRate <bytes per seconds> [<max bytes per second>],"
-                 " defines the minumum upload"
+                 " defines the minimum upload"
                  " throughput a client must generate. See also QS_SrvMinDataRate."),
 
 #ifdef AP_TAKE_ARGV
   AP_INIT_TAKE_ARGV("QS_SrvMinDataRate", qos_min_rate_cmd, NULL,
                     RSRC_CONF,
                     "QS_SrvMinDataRate <bytes per seconds> [<max bytes per second> [<connections>]],"
-                    " defines the minumum upload/download"
+                    " defines the minimum upload/download"
                     " throughput a client must generate (the bytes send/received by the client"
                     " per seconds). This bandwidth is measured while transmitting the data"
                     " (request line, header fields, request body, or response data). The"
@@ -14207,11 +14166,11 @@
                     " enable this feature (0 by default)."
                     " No limitation is set by default."),
 #else
-  AP_INIT_TAKE2("QS_SrvMinDataRate", qos_min_rate_cmd, NULL,
+  AP_INIT_TAKE12("QS_SrvMinDataRate", qos_min_rate_cmd, NULL,
                     RSRC_CONF,
                     "QS_SrvMinDataRate <bytes per seconds> [<max bytes per second>],"
-                    " defines the minumum upload/download"
-                    " throughput a client must generate (the bytes send/received by the client"
+                    " defines the minimum upload/download throughput"
+                    " a client must generate (the bytes send/received by the client"
                     " per seconds). This bandwidth is measured while transmitting the data"
                     " (request line, header fields, request body, or response data). The"
                     " client connection get closed if the client does not fulfill the"
@@ -14253,9 +14212,9 @@
   /* generic request filter */
   AP_INIT_TAKE3("QS_DenyRequestLine", qos_deny_rql_cmd, NULL,
                 ACCESS_CONF,
-                "QS_DenyRequestLine '+'|'-'<id> 'log'|'deny' <pcre>, generic"
+                "QS_DenyRequestLine '+'|'-'<id> 'log'|'deny' <regular expression>, generic"
                 " request line (method, path, query and protocol) filter used"
-                " to deny access for requests matching the defined expression (pcre)."
+                " to deny access for requests matching the defined regular expression."
                 " '+' adds a new rule while '-' removes a rule for a location."
                 " The action is either 'log' (access is granted but rule"
                 " match is logged) or 'deny' (access is denied)."),
@@ -14281,13 +14240,13 @@
 
   AP_INIT_TAKE3("QS_PermitUri", qos_permit_uri_cmd, NULL,
                 ACCESS_CONF,
-                "QS_PermitUri, '+'|'-'<id> 'log'|'deny' <pcre>, generic"
+                "QS_PermitUri, '+'|'-'<id> 'log'|'deny' <regular expression>, generic"
                 " request filter applied to the request uri (path and query)."
                 " Only requests matching at least one QS_PermitUri pattern are"
                 " allowed. If a QS_PermitUri pattern has been defined an the"
                 " request does not match any rule, the request is denied albeit of"
-                " any server resource availability (white list). All rules"
-                " must define the same action. pcre is case sensitve."),
+                " any server resource availability (allow list). All rules"
+                " must define the same action. Regular expression is case sensitive."),
 
   AP_INIT_FLAG("QS_DenyBody", qos_denybody_cmd, NULL,
                ACCESS_CONF,
@@ -14339,21 +14298,21 @@
   AP_INIT_TAKE1("QS_ResponseHeaderFilter", qos_resheaderfilter_cmd, NULL,
                 ACCESS_CONF,
                 "QS_ResponseHeaderFilter 'on'|'off', filters response headers by allowing"
-                " only these headers which match the request header rules defined by"
-                " mod_qos. Request headers which do not conform these definitions"
+                " only these headers which match the response header rules defined by"
+                " mod_qos. Response headers which do not conform these definitions"
                 " are dropped."),
 
 #ifdef AP_TAKE_ARGV
   AP_INIT_TAKE_ARGV("QS_RequestHeaderFilterRule", qos_headerfilter_rule_cmd, NULL,
                     RSRC_CONF,
-                    "QS_RequestHeaderFilterRule <header name> 'drop'|'deny' <pcre>  <size>, used"
+                    "QS_RequestHeaderFilterRule <header name> 'drop'|'deny' <regular expression>  <size>, used"
                     " to add custom request header filter rules which override the internal"
                     " filter rules of mod_qos."
                     " Directive is allowed in global server context only."),
 #else
   AP_INIT_TAKE3("QS_RequestHeaderFilterRule", qos_headerfilter_rule_cmd, NULL,
                     RSRC_CONF,
-                    "QS_RequestHeaderFilterRule <header name> 'drop'|'deny' <pcre>, used"
+                    "QS_RequestHeaderFilterRule <header name> 'drop'|'deny' <regular expression>, used"
                     " to add custom request header filter rules which override the internal"
                     " filter rules of mod_qos."
                     " Directive is allowed in global server context only."),
@@ -14361,7 +14320,7 @@
 
   AP_INIT_TAKE3("QS_ResponseHeaderFilterRule", qos_resheaderfilter_rule_cmd, NULL,
                 RSRC_CONF,
-                "QS_ResponseHeaderFilterRule <header name> <pcre> <size>, used"
+                "QS_ResponseHeaderFilterRule <header name> <regular expression> <size>, used"
                 " to add custom response header filter rules which override the internal"
                 " filter rules of mod_qos."
                 " Directive is allowed in global server context only."),
@@ -14474,14 +14433,14 @@
                  " are set in the request environment variable list (not case"
                  " sensitive). This is used to combine multiple variables"
                  " to a new event type. Alternatively, a regular expression"
-                 " can be specifed for variable1's value and variable2 must be"
+                 " can be specified for variable1's value and variable2 must be"
                  " omitted in order to simply set a new variable if"
                  " the regular expression matches."),
 
   AP_INIT_TAKE_ARGV("QS_SetEnvIfCmp", qos_cmp_cmd, NULL,
                     ACCESS_CONF,
                     "QS_SetEnvIfCmpP <env-variable1> eq|ne|gt|lt <env-variable2> [!]<env-variable>[=<value>],"
-                    " sets the specifed environment variable if the specifed env-variables"
+                    " sets the specified environment variable if the specified env-variables"
                     " are alphabetically or numerical equal (eq), not equal (ne),"
                     " greater (gt), less (lt)."),
 
@@ -14581,18 +14540,18 @@
   AP_INIT_TAKE12("QS_SetEnvResHeader", qos_event_setenvresheader_cmd, NULL,
                  RSRC_CONF,
                  "QS_SetEnvResHeader <header name> [drop], sets the defined"
-                 " HTTP response header to the request environment variables."
+                 " HTTP response header (name and value) to the request environment variables"
                  " Deletes the header if the action 'drop' has been specified."),
 
   AP_INIT_TAKE2("QS_SetEnvResHeaderMatch", qos_event_setenvresheadermatch_cmd, NULL,
                 RSRC_CONF,
                 "QS_SetEnvResHeaderMatch <header name> <regex>, sets the defined"
-                " HTTP response header to the request environment variables"
-                " if the specified regular expression (pcre) matches the header value."),
+                " HTTP response header (name and value) to the request environment variables"
+                " if the specified regular expression matches the header value."),
 
   AP_INIT_TAKE3("QS_SetEnvRes", qos_setenvres_cmd, NULL,
                 RSRC_CONF,
-                "QS_SetEnvRes <variable> <regex> <variable2>[=<value>], sets the environmet"
+                "QS_SetEnvRes <variable> <regex> <variable2>[=<value>], sets the environment"
                 " variable2 if the regular expression matches against the value of"
                 " the environment variable. Occurrences of $1..$9 within the value"
                 " and replace them by parenthesized subexpressions of the regular expression."),
@@ -14641,7 +14600,7 @@
   AP_INIT_TAKE_ARGV("QS_ClientContentTypes", qos_client_contenttype, NULL,
                     RSRC_CONF,
                     "QS_ClientContentTypes <html> <css/js> <images> <other> <304>,"
-                    " defines the distribution of HTTP response content types a client normaly"
+                    " defines the distribution of HTTP response content types a client normally"
                     " receives when accessing the server. mod_qos normally learns the average"
                     " behavior automatically by default but you may specify a static configuration"
                     " in order to avoid influences by a high number of abnormal clients."),
@@ -14656,7 +14615,7 @@
   AP_INIT_TAKE1("QS_ClientEventBlockExcludeIP", qos_client_ex_cmd, NULL,
                  RSRC_CONF,
                  "QS_ClientEventBlockExcludeIP <addr>, excludes an IP address or"
-                " address range from beeing limited by QS_ClientEventBlockCount."),
+                " address range from being limited by QS_ClientEventBlockCount."),
 
   AP_INIT_TAKE123("QS_ClientEventLimitCount", qos_client_limit_cmd, NULL,
                   RSRC_CONF,
@@ -14690,7 +14649,7 @@
   AP_INIT_TAKE1("QS_ClientEventRequestLimit", qos_client_event_req_cmd, NULL,
                 RSRC_CONF,
                 "QS_ClientEventRequestLimit <number>, defines the allowed"
-                " number of concurrent requests comming from the same client"
+                " number of concurrent requests coming from the same client"
                 " source IP address"
                 " having the QS_EventRequest variable set."
                 " Directive is allowed in global server context only."),
@@ -14698,7 +14657,7 @@
   AP_INIT_NO_ARGS("QS_ClientSerialize", qos_client_serial_cmd, NULL,
                   RSRC_CONF,
                   "QS_ClientSerialize, serializes requests having the "QS_SERIALIZE" variable"
-                  " set if they are comming from the same IP address."),
+                  " set if they are coming from the same IP address."),
 
   AP_INIT_TAKE1("QS_ClientIpFromHeader", qos_client_forwardedfor_cmd, NULL,
                 RSRC_CONF,
@@ -14712,12 +14671,15 @@
                 RSRC_CONF,
                 "QS_ClientGeoCountryDB <path>, path to the geograpical database file."),
 
-  AP_INIT_TAKE2("QS_ClientGeoCountryPriv", qos_geopriv_cmd, NULL,
+  AP_INIT_TAKE23("QS_ClientGeoCountryPriv", qos_geopriv_cmd, NULL,
                 RSRC_CONF,
-                "QS_ClientGeoCountryPriv <list> <connections>, defines a comma separated list of"
-                " country codes for origin client IP address which are allowed to"
-                " access the server if the number of busy TCP connections reaches"
-                " the defined number of connections."),
+                "QS_ClientGeoCountryPriv <list> <connections> ['excludeUnknown'],"
+                 " defines a comma separated list of country codes"
+                 " for origin client IP address which are allowed to"
+                 " access the server if the number of busy TCP connections reaches"
+                 " the defined number of connections while others are denied access."
+                 " Clients whose IP can't be mapped to a country code can be excluded"
+                 " from the limitation by configuring the 'excludeUnknown' argument."),
 
   /* error documents */
   AP_INIT_TAKE1("QS_ErrorPage", qos_error_page_cmd, NULL,
@@ -14729,6 +14691,12 @@
                 "QS_ErrorResponseCode <code>, defines the HTTP response code which"
                 " is used when a request is denied, default is 500."),
 
+  AP_INIT_FLAG("QS_ForcedClose", qos_forced_close_cmd, NULL,
+               RSRC_CONF,
+               "QS_ForcedClose 'on'|'off', defines if mod_qos connection handler shall"
+               " exit with an error code (on) or not. Default is on (except for"
+               " Apache 2.4.49)."),
+
   /* module settings / various stuff */
   AP_INIT_FLAG("QS_LogOnly", qos_logonly_cmd, NULL,
                RSRC_CONF,
@@ -14736,6 +14704,11 @@
                " where no limitations are enforced. Default is off."
                " Directive is allowed in global server context only."),
 
+  AP_INIT_FLAG("QS_LogEnv", qos_logenv_cmd, NULL,
+               RSRC_CONF,
+               "QS_LogEnv 'on'|'off', enables logging of environment"
+               " variables."),
+
   AP_INIT_FLAG("QS_SupportIPv6", qos_enable_ipv6_cmd, NULL,
                RSRC_CONF,
                "QS_SupportIPv6 'on'|'off', enables IPv6 address support."
@@ -14744,9 +14717,8 @@
   AP_INIT_TAKE1("QS_SemMemFile", qos_mfile_cmd, NULL,
                 RSRC_CONF,
                 "QS_SemMemFile <path>, optional path to a directory or file"
-                " which shall be used for file based samaphores/shared memory"
-                " usage."
-                " Default is "QS_MFILE"."),
+                " which shall be used for file based semaphores/shared memory"
+                " usage, e.g. /var/tmp."),
 
   AP_INIT_TAKE1("QS_MaxClients", qos_maxclients_cmd, NULL,
                 RSRC_CONF,
@@ -14759,14 +14731,6 @@
                "QS_DisableHandler 'on'|'off', disables the qos-viewer"
                " and qos-console for a virtual host"),
 
-#if QS_APACHE_22
-#ifndef QS_HAS_APACHE_PATH
-  AP_INIT_TAKE1("QS_Chroot", qos_chroot_cmd, NULL,
-                RSRC_CONF,
-                "QS_Chroot <path>, change root directory."),
-#endif
-#endif
-
 #if APR_HAS_THREADS
   AP_INIT_FLAG("QS_Status", qos_qsstatus_cmd, NULL,
                RSRC_CONF,
@@ -14807,12 +14771,10 @@
   static const char *postlog[] = { "mod_logio.c", NULL };
   static const char *parp[] = { "mod_parp.c", NULL };
   static const char *prelast[] = { "mod_setenvif.c", "mod_setenvifplus.c", "mod_ssl.c", NULL };
+  static const char *preFix[] = { "mod_ssl.c", "mod_setenvifplus.c", NULL };
   
   ap_hook_post_config(qos_post_config, preconf, NULL, APR_HOOK_MIDDLE);
-#ifndef QS_HAS_APACHE_PATH
-  /* use post config hook only for non-patched Apache server (worker.c/prefork.c) */
-  ap_hook_post_config(qos_chroot, prelast, NULL, APR_HOOK_REALLY_LAST);
-#endif
+
   ap_hook_child_init(qos_child_init, NULL, NULL, APR_HOOK_MIDDLE);
 
   // before ssl_hook_pre_connection@APR_HOOK_MIDDLE but after logio_pre_conn@APR_HOOK_MIDDLE
@@ -14830,7 +14792,7 @@
   ap_hook_header_parser(qos_header_parser1, post, parp, APR_HOOK_FIRST);
   ap_hook_header_parser(qos_header_parser, pre, NULL, APR_HOOK_MIDDLE);
 
-  ap_hook_fixups(qos_fixup, pre, NULL, APR_HOOK_MIDDLE);
+  ap_hook_fixups(qos_fixup, preFix, NULL, APR_HOOK_MIDDLE);
 
   ap_hook_handler(qos_handler, NULL, NULL, APR_HOOK_MIDDLE);
 
@@ -14859,10 +14821,10 @@
  ***********************************************************************/
 module AP_MODULE_DECLARE_DATA qos_module ={ 
   STANDARD20_MODULE_STUFF,
-  qos_dir_config_create,                    /**< dir config creater */
+  qos_dir_config_create,                    /**< dir config creator */
   qos_dir_config_merge,                     /**< dir merger */
   qos_srv_config_create,                    /**< server config */
   qos_srv_config_merge,                     /**< server merger */
   qos_config_cmds,                          /**< command table */
-  qos_register_hooks,                       /**< hook registery */
+  qos_register_hooks,                       /**< hook registration */
 };
diff -Nru libapache2-mod-qos-11.63/apache2/mod_qos.h libapache2-mod-qos-11.74/apache2/mod_qos.h
--- libapache2-mod-qos-11.63/apache2/mod_qos.h	2019-05-25 09:08:59.000000000 -0400
+++ libapache2-mod-qos-11.74/apache2/mod_qos.h	2023-05-18 08:34:25.000000000 -0400
@@ -15,7 +15,7 @@
  * See http://mod-qos.sourceforge.net/ for further
  * details.
  *
- * Copyright (C) 2019 Pascal Buchbinder
+ * Copyright (C) 2023 Pascal Buchbinder
  *
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
diff -Nru libapache2-mod-qos-11.63/debian/changelog libapache2-mod-qos-11.74/debian/changelog
--- libapache2-mod-qos-11.63/debian/changelog	2019-07-04 09:51:55.000000000 -0400
+++ libapache2-mod-qos-11.74/debian/changelog	2024-02-07 13:33:49.000000000 -0500
@@ -1,3 +1,19 @@
+libapache2-mod-qos (11.74-1+deb12u1) bookworm; urgency=medium
+
+  * Non-maintainer upload.
+  * Rebuild for bookworm.
+
+ -- Jérôme Charaoui <jerome@riseup.net>  Wed, 07 Feb 2024 13:33:49 -0500
+
+libapache2-mod-qos (11.74-1) unstable; urgency=high
+
+  * QA upload
+  * New upstream version (Closes: #1000072)
+  * debian/patches: Remove 01_spelling.patch; applied by upstream
+  * debian/control: Replace 'libpcre3-dev' with 'libpcre2-dev'
+
+ -- Marcelo Jorge Vieira <metal@debian.org>  Sat, 17 Jun 2023 20:39:16 -0300
+
 libapache2-mod-qos (11.63-1) unstable; urgency=medium
 
   * New upstream version 11.63
diff -Nru libapache2-mod-qos-11.63/debian/control libapache2-mod-qos-11.74/debian/control
--- libapache2-mod-qos-11.63/debian/control	2019-07-04 09:51:55.000000000 -0400
+++ libapache2-mod-qos-11.74/debian/control	2024-02-07 13:33:49.000000000 -0500
@@ -1,7 +1,7 @@
 Source: libapache2-mod-qos
 Priority: optional
-Maintainer: Sergey B Kirpichev <skirpichev@gmail.com>
-Build-Depends: debhelper (>= 9), libssl-dev (>= 0.9.8g), libapr1-dev, libaprutil1-dev, libpcre3-dev, libpng-dev, dh-apache2, apache2-dev (>= 2.4.2-1~), dh-autoreconf
+Maintainer: Debian QA Group <packages@qa.debian.org>
+Build-Depends: debhelper (>= 9), libssl-dev (>= 0.9.8g), libapr1-dev, libaprutil1-dev, libpcre2-dev, libpng-dev, dh-apache2, apache2-dev (>= 2.4.53-1~), dh-autoreconf
 Standards-Version: 4.3.0
 Section: httpd
 Homepage: http://mod-qos.sourceforge.net/
diff -Nru libapache2-mod-qos-11.63/debian/patches/01_spelling.patch libapache2-mod-qos-11.74/debian/patches/01_spelling.patch
--- libapache2-mod-qos-11.63/debian/patches/01_spelling.patch	2019-07-04 09:51:55.000000000 -0400
+++ libapache2-mod-qos-11.74/debian/patches/01_spelling.patch	1969-12-31 19:00:00.000000000 -0500
@@ -1,285 +0,0 @@
-Description: Spelling fixes from lintian
-Author: Sergey B Kirpichev
-Forwarded: no
-
----
- apache2/mod_qos.c      |   26 +++++++++++++-------------
- tools/man1/mod_qos.1   |    6 +++---
- tools/man1/qsfilter2.1 |    6 +++---
- tools/man1/qslog.1     |    4 ++--
- tools/man1/qslogger.1  |    2 +-
- tools/src/qsfilter2.c  |    6 +++---
- tools/src/qslog.c      |    4 ++--
- tools/src/qslogger.c   |    2 +-
- tools/src/qspng.c      |    2 +-
- 9 files changed, 29 insertions(+), 29 deletions(-)
-
---- a/apache2/mod_qos.c
-+++ b/apache2/mod_qos.c
-@@ -3949,7 +3949,7 @@ static int qos_json(request_rec *r, qos_
- #endif
-         data = copyq;
-         if(strlen(data) != len) {
--          *msg = apr_pstrdup(r->pool, "null chracter within data structure in query");
-+          *msg = apr_pstrdup(r->pool, "null character within data structure in query");
-           return HTTP_BAD_REQUEST;
-         }
-       } else {
-@@ -3962,7 +3962,7 @@ static int qos_json(request_rec *r, qos_
-       apr_table_t *tl = apr_table_make(r->pool, 200);
-       int rc;
-       if(strlen(value) != len) {
--        *msg = apr_pstrdup(r->pool, "null chracter within data structure");
-+        *msg = apr_pstrdup(r->pool, "null character within data structure");
-         return HTTP_BAD_REQUEST;
-       }
-       rc = j_val(r->pool, &value, tl, "J", 0);
-@@ -14154,7 +14154,7 @@ static const command_rec qos_config_cmds
-   AP_INIT_TAKE1("QS_SrvMaxConnExcludeIP", qos_max_conn_ex_cmd, NULL,
-                 RSRC_CONF,
-                 "QS_SrvMaxConnExcludeIP <addr>, excludes an IP address or"
--                " address range from beeing limited."),
-+                " address range from being limited."),
- 
-   AP_INIT_FLAG("QS_SrvMaxConnPerIPIgnoreVIP", qos_max_conn_ip_vip_off_cmd, NULL,
-                 RSRC_CONF,
-@@ -14181,14 +14181,14 @@ static const command_rec qos_config_cmds
-   AP_INIT_TAKE12("QS_SrvRequestRate", qos_req_rate_cmd, NULL,
-                  RSRC_CONF,
-                  "QS_SrvRequestRate <bytes per seconds> [<max bytes per second>],"
--                 " defines the minumum upload"
-+                 " defines the minimum upload"
-                  " throughput a client must generate. See also QS_SrvMinDataRate."),
- 
- #ifdef AP_TAKE_ARGV
-   AP_INIT_TAKE_ARGV("QS_SrvMinDataRate", qos_min_rate_cmd, NULL,
-                     RSRC_CONF,
-                     "QS_SrvMinDataRate <bytes per seconds> [<max bytes per second> [<connections>]],"
--                    " defines the minumum upload/download"
-+                    " defines the minimum upload/download"
-                     " throughput a client must generate (the bytes send/received by the client"
-                     " per seconds). This bandwidth is measured while transmitting the data"
-                     " (request line, header fields, request body, or response data). The"
-@@ -14210,7 +14210,7 @@ static const command_rec qos_config_cmds
-   AP_INIT_TAKE2("QS_SrvMinDataRate", qos_min_rate_cmd, NULL,
-                     RSRC_CONF,
-                     "QS_SrvMinDataRate <bytes per seconds> [<max bytes per second>],"
--                    " defines the minumum upload/download"
-+                    " defines the minimum upload/download"
-                     " throughput a client must generate (the bytes send/received by the client"
-                     " per seconds). This bandwidth is measured while transmitting the data"
-                     " (request line, header fields, request body, or response data). The"
-@@ -14287,7 +14287,7 @@ static const command_rec qos_config_cmds
-                 " allowed. If a QS_PermitUri pattern has been defined an the"
-                 " request does not match any rule, the request is denied albeit of"
-                 " any server resource availability (white list). All rules"
--                " must define the same action. pcre is case sensitve."),
-+                " must define the same action. pcre is case sensitive."),
- 
-   AP_INIT_FLAG("QS_DenyBody", qos_denybody_cmd, NULL,
-                ACCESS_CONF,
-@@ -14474,14 +14474,14 @@ static const command_rec qos_config_cmds
-                  " are set in the request environment variable list (not case"
-                  " sensitive). This is used to combine multiple variables"
-                  " to a new event type. Alternatively, a regular expression"
--                 " can be specifed for variable1's value and variable2 must be"
-+                 " can be specified for variable1's value and variable2 must be"
-                  " omitted in order to simply set a new variable if"
-                  " the regular expression matches."),
- 
-   AP_INIT_TAKE_ARGV("QS_SetEnvIfCmp", qos_cmp_cmd, NULL,
-                     ACCESS_CONF,
-                     "QS_SetEnvIfCmpP <env-variable1> eq|ne|gt|lt <env-variable2> [!]<env-variable>[=<value>],"
--                    " sets the specifed environment variable if the specifed env-variables"
-+                    " sets the specified environment variable if the specified env-variables"
-                     " are alphabetically or numerical equal (eq), not equal (ne),"
-                     " greater (gt), less (lt)."),
- 
-@@ -14641,7 +14641,7 @@ static const command_rec qos_config_cmds
-   AP_INIT_TAKE_ARGV("QS_ClientContentTypes", qos_client_contenttype, NULL,
-                     RSRC_CONF,
-                     "QS_ClientContentTypes <html> <css/js> <images> <other> <304>,"
--                    " defines the distribution of HTTP response content types a client normaly"
-+                    " defines the distribution of HTTP response content types a client normally"
-                     " receives when accessing the server. mod_qos normally learns the average"
-                     " behavior automatically by default but you may specify a static configuration"
-                     " in order to avoid influences by a high number of abnormal clients."),
-@@ -14656,7 +14656,7 @@ static const command_rec qos_config_cmds
-   AP_INIT_TAKE1("QS_ClientEventBlockExcludeIP", qos_client_ex_cmd, NULL,
-                  RSRC_CONF,
-                  "QS_ClientEventBlockExcludeIP <addr>, excludes an IP address or"
--                " address range from beeing limited by QS_ClientEventBlockCount."),
-+                " address range from being limited by QS_ClientEventBlockCount."),
- 
-   AP_INIT_TAKE123("QS_ClientEventLimitCount", qos_client_limit_cmd, NULL,
-                   RSRC_CONF,
-@@ -14690,7 +14690,7 @@ static const command_rec qos_config_cmds
-   AP_INIT_TAKE1("QS_ClientEventRequestLimit", qos_client_event_req_cmd, NULL,
-                 RSRC_CONF,
-                 "QS_ClientEventRequestLimit <number>, defines the allowed"
--                " number of concurrent requests comming from the same client"
-+                " number of concurrent requests coming from the same client"
-                 " source IP address"
-                 " having the QS_EventRequest variable set."
-                 " Directive is allowed in global server context only."),
-@@ -14698,7 +14698,7 @@ static const command_rec qos_config_cmds
-   AP_INIT_NO_ARGS("QS_ClientSerialize", qos_client_serial_cmd, NULL,
-                   RSRC_CONF,
-                   "QS_ClientSerialize, serializes requests having the "QS_SERIALIZE" variable"
--                  " set if they are comming from the same IP address."),
-+                  " set if they are coming from the same IP address."),
- 
-   AP_INIT_TAKE1("QS_ClientIpFromHeader", qos_client_forwardedfor_cmd, NULL,
-                 RSRC_CONF,
---- a/tools/src/qsfilter2.c
-+++ b/tools/src/qsfilter2.c
-@@ -373,7 +373,7 @@ static void usage(char *cmd, int man) {
-   qs_man_print(man, " users or to protect the server from malicious patterns. The\n");
-   qs_man_print(man, " QS_Permit* rules implement a positive security model (whitelist).\n");
-   qs_man_print(man, " These directives are used to define allowed request line patterns.\n");
--  qs_man_print(man, " Request which do not match any of thses patterns are not allowed\n");
-+  qs_man_print(man, " Request which do not match any of these patterns are not allowed\n");
-   qs_man_print(man, " to access the server.\n");
-   if(man) printf("\n\n");
-   qs_man_print(man, " %s is an audit log analyzer used to generate filter\n", cmd);
-@@ -450,7 +450,7 @@ static void usage(char *cmd, int man) {
-   if(man) printf("\n.TP\n");
-   qs_man_print(man, "  -p\n");
-   if(man) printf("\n");
--  qs_man_print(man, "     Repesents query by pcre only (no literal strings).\n");
-+  qs_man_print(man, "     Represents query by pcre only (no literal strings).\n");
-   if(man) printf("\n.TP\n");
-   qs_man_print(man, "  -s\n");
-   if(man) printf("\n");
-@@ -458,7 +458,7 @@ static void usage(char *cmd, int man) {
-   if(man) printf("\n.TP\n");
-   qs_man_print(man, "  -m\n");
-   if(man) printf("\n");
--  qs_man_print(man, "     Uses one pcre for multipe query values (recommended mode).\n");
-+  qs_man_print(man, "     Uses one pcre for multiple query values (recommended mode).\n");
-   if(man) printf("\n.TP\n");
-   qs_man_print(man, "  -o\n");
-   if(man) printf("\n");
---- a/tools/src/qslog.c
-+++ b/tools/src/qslog.c
-@@ -2086,7 +2086,7 @@ static void usage(const char *cmd, int m
-   qs_man_println(man, "  - number of requests within measured time (req)\n");
-   qs_man_println(man, "  - bytes sent to the client per second ("NBS")\n");
-   qs_man_println(man, "  - bytes received from the client per second ("NBIS")\n");
--  qs_man_println(man, "  - repsonse status codes within the last minute (1xx,2xx,3xx,4xx,5xx)\n");
-+  qs_man_println(man, "  - response status codes within the last minute (1xx,2xx,3xx,4xx,5xx)\n");
-   qs_man_println(man, "  - average response duration ("NAV")\n");
-   qs_man_println(man, "  - average response duration in milliseconds ("NAVMS")\n");
-   qs_man_println(man, "  - distribution of response durations in seconds within the last minute\n");
-@@ -2118,7 +2118,7 @@ static void usage(const char *cmd, int m
-   qs_man_print(man, "     Defines the log data format and the positions of data\n");
-   qs_man_print(man, "     elements processed by this utility.\n");
-   qs_man_print(man, "     See to the 'LogFormat' directive of the httpd.conf file\n");
--  qs_man_print(man, "     to see the format defintions of the servers access log data.\n");
-+  qs_man_print(man, "     to see the format definitions of the servers access log data.\n");
-   if(man) printf("\n");
-   qs_man_println(man, "     %s knows the following elements:\n", cmd);
-   qs_man_println(man, "     I defines the client ip address (%%h)\n");
---- a/tools/src/qslogger.c
-+++ b/tools/src/qslogger.c
-@@ -264,7 +264,7 @@ static void usage(const char *cmd, int m
-   qs_man_print(man, "  -l <level>\n");
-   if(man) printf("\n");
-   qs_man_print(man, "     Defines the minimal severity a message must have in order to\n");
--  qs_man_print(man, "     be forwarded. Default is 'DEBUG' (fowarding everything).\n");
-+  qs_man_print(man, "     be forwarded. Default is 'DEBUG' (forwarding everything).\n");
-   if(man) printf("\n.TP\n");
-   qs_man_print(man, "  -x <prefix>\n");
-   if(man) printf("\n");
---- a/tools/src/qspng.c
-+++ b/tools/src/qspng.c
-@@ -86,7 +86,7 @@ static const qs_png_elt_t qs_png_elts[]
-   { "qV", "created VIP sessions",  55, 50, 155 },
-   { "qS", "session pass",          55, 75, 160 },
-   { "qD", "access denied",         55, 70, 170 },
--  { "qK", "conection closed",      55, 60, 145 },
-+  { "qK", "connection closed",      55, 60, 145 },
-   { "qT", "dynamic keep-alive",    55, 55, 153 },
-   { "qL", "slow down",             55, 65, 140 },
-   { "qA", "connection aborts",     55, 50, 175 },
---- a/tools/man1/qsfilter2.1
-+++ b/tools/man1/qsfilter2.1
-@@ -5,7 +5,7 @@ qsfilter2 \- an utility to generate mod_
- .SH SYNOPSIS
- qsfilter2 \-i <path> [\-c <path>] [\-d <num>] [\-h] [\-b <num>] [\-p|\-s|\-m|\-o] [\-l <len>] [\-n] [\-e] [\-u 'uni'] [\-k <prefix>] [\-t] [\-f <path>] [\-v 0|1|2] 
- .SH DESCRIPTION
--mod_qos implements a request filter which validates each request line. The module supports both, negative and positive security model. The QS_Deny* directives are used to specify request line patterns which are not allowed to access the server (negative security model / blacklist). These rules are used to restrict access to certain resources which should not be available to users or to protect the server from malicious patterns. The QS_Permit* rules implement a positive security model (whitelist). These directives are used to define allowed request line patterns. Request which do not match any of thses patterns are not allowed to access the server. 
-+mod_qos implements a request filter which validates each request line. The module supports both, negative and positive security model. The QS_Deny* directives are used to specify request line patterns which are not allowed to access the server (negative security model / blacklist). These rules are used to restrict access to certain resources which should not be available to users or to protect the server from malicious patterns. The QS_Permit* rules implement a positive security model (whitelist). These directives are used to define allowed request line patterns. Request which do not match any of these patterns are not allowed to access the server.
- 
- qsfilter2 is an audit log analyzer used to generate filter rules (perl compatible regular expressions) which may be used by mod_qos to deny access for suspect requests (QS_PermitUri rules). It parses existing audit log files in order to generate request patterns covering all allowed requests. 
- .SH OPTIONS
-@@ -41,13 +41,13 @@ Always use a string representing the han
- Replaces url pattern by the regular expression when detecting a base64/hex encoded string. Detecting sensibility is defined by a numeric value. You should use values higher than 5 (default) or 0 to disable this function. 
- .TP
- \-p 
--Repesents query by pcre only (no literal strings). 
-+Represents query by pcre only (no literal strings).
- .TP
- \-s 
- Uses one single pcre for the whole query string. 
- .TP
- \-m 
--Uses one pcre for multipe query values (recommended mode). 
-+Uses one pcre for multiple query values (recommended mode).
- .TP
- \-o 
- Does not care the order of query parameters. 
---- a/tools/man1/qslog.1
-+++ b/tools/man1/qslog.1
-@@ -10,7 +10,7 @@ qslog is a real time access log analyzer
-   \- number of requests within measured time (req)
-   \- bytes sent to the client per second (b/s)
-   \- bytes received from the client per second (ib/s)
--  \- repsonse status codes within the last minute (1xx,2xx,3xx,4xx,5xx)
-+  \- response status codes within the last minute (1xx,2xx,3xx,4xx,5xx)
-   \- average response duration (av)
-   \- average response duration in milliseconds (avms)
-   \- distribution of response durations in seconds within the last minute
-@@ -28,7 +28,7 @@ qv=VIP IP,qS=session pass, qD=access den
- .SH OPTIONS
- .TP
- \-f <format_string> 
--Defines the log data format and the positions of data elements processed by this utility. See to the 'LogFormat' directive of the httpd.conf file to see the format defintions of the servers access log data. 
-+Defines the log data format and the positions of data elements processed by this utility. See to the 'LogFormat' directive of the httpd.conf file to see the format definitions of the servers access log data.
-      qslog knows the following elements:
-      I defines the client ip address (%h)
-      R defines the request line (%r)
---- a/tools/man1/qslogger.1
-+++ b/tools/man1/qslogger.1
-@@ -19,7 +19,7 @@ Defines the syslog facility. Default is
- Becomes another user, e.g. www\-data. 
- .TP
- \-l <level> 
--Defines the minimal severity a message must have in order to be forwarded. Default is 'DEBUG' (fowarding everything). 
-+Defines the minimal severity a message must have in order to be forwarded. Default is 'DEBUG' (forwarding everything).
- .TP
- \-x <prefix> 
- Allows you to add a prefix (literal string) to every message. 
---- a/tools/man1/mod_qos.1
-+++ b/tools/man1/mod_qos.1
-@@ -63,7 +63,7 @@ QS_DenyQuery, same as QS_DenyRequestLine
- .TP
- QS_DenyEvent '+'|'\-'<id> 'log'|'deny' [!]<variable>, matches requests having the defined process environment variable set (or NOT set if prefixed by a '!'). The action taken for matching rules is either 'log' (access is granted but the rule match is logged) or 'deny' (access is denied).
- .TP
--QS_PermitUri, '+'|'\-'<id> 'log'|'deny' <pcre>, generic request filter applied to the request uri (path and query). Only requests matching at least one QS_PermitUri pattern are allowed. If a QS_PermitUri pattern has been defined an the request does not match any rule, the request is denied albeit of any server resource availability (white list). All rules must define the same action. pcre is case sensitve.
-+QS_PermitUri, '+'|'\-'<id> 'log'|'deny' <pcre>, generic request filter applied to the request uri (path and query). Only requests matching at least one QS_PermitUri pattern are allowed. If a QS_PermitUri pattern has been defined an the request does not match any rule, the request is denied albeit of any server resource availability (white list). All rules must define the same action. pcre is case sensitive.
- .TP
- QS_DenyBody 'on'|'off', enabled body data filter (obsolete).
- .TP
-@@ -109,9 +109,9 @@ QS_VipIpUser, marks a source IP address
- .TP
- QS_UserTrackingCookieName <name> [<path>] [<domain>] ['session'] ['jsredirect'], enables the user tracking cookie by defining a cookie name. The "path" parameter is an option cookie check page which is used to ensure the client accepts cookies. The "domain" option defines the Domain attriibute for the Set\-Cookie header. The option "session" indicates that the cookie shall be a session cookie expiring when the user closes it's browser. User tracking requires mod_unique_id. This feature is disabled by default. Ignores QS_LogOnly.
- .TP
--QS_SetEnvIf [!]<variable1>[=<regex>] [[!]<variable2>] [!]<variable=value>, sets (or unsets) the 'variable=value' (literal string) if variable1 (literal string) AND variable2 (literal string) are set in the request environment variable list (not case sensitive). This is used to combine multiple variables to a new event type. Alternatively, a regular expression can be specifed for variable1's value and variable2 must be omitted in order to simply set a new variable if the regular expression matches.
-+QS_SetEnvIf [!]<variable1>[=<regex>] [[!]<variable2>] [!]<variable=value>, sets (or unsets) the 'variable=value' (literal string) if variable1 (literal string) AND variable2 (literal string) are set in the request environment variable list (not case sensitive). This is used to combine multiple variables to a new event type. Alternatively, a regular expression can be specified for variable1's value and variable2 must be omitted in order to simply set a new variable if the regular expression matches.
- .TP
--QS_SetEnvIfCmpP <env\-variable1> eq|ne|gt|lt <env\-variable2> [!]<env\-variable>[=<value>], sets the specifed environment variable if the specifed env\-variables are alphabetically or numerical equal (eq), not equal (ne), greater (gt), less (lt).
-+QS_SetEnvIfCmpP <env\-variable1> eq|ne|gt|lt <env\-variable2> [!]<env\-variable>[=<value>], sets the specified environment variable if the specified env\-variables are alphabetically or numerical equal (eq), not equal (ne), greater (gt), less (lt).
- .TP
- QS_SetEnvIfQuery <regex> [!]<variable>[=value], directive works quite similar to the SetEnvIf directive of the Apache module mod_setenvif, but the specified regex is applied against the query string portion of the request line. The directive recognizes the occurrences of $1..$9 within value and replaces them by the sub\-expressions of the defined regex pattern.
- .TP
diff -Nru libapache2-mod-qos-11.63/debian/patches/series libapache2-mod-qos-11.74/debian/patches/series
--- libapache2-mod-qos-11.63/debian/patches/series	2019-07-04 09:51:55.000000000 -0400
+++ libapache2-mod-qos-11.74/debian/patches/series	1969-12-31 19:00:00.000000000 -0500
@@ -1 +0,0 @@
-01_spelling.patch
diff -Nru libapache2-mod-qos-11.63/doc/CHANGES.txt libapache2-mod-qos-11.74/doc/CHANGES.txt
--- libapache2-mod-qos-11.63/doc/CHANGES.txt	2019-05-25 09:08:59.000000000 -0400
+++ libapache2-mod-qos-11.74/doc/CHANGES.txt	2023-05-18 08:34:25.000000000 -0400
@@ -1,3 +1,101 @@
+Version 11.74 
+
+- Fixed: Potential counter overflow for early event detection
+  (increment before block) or log only mode.
+
+Version 11.73
+
+  This release introduces support of the PCRE2 (10.x) library in place of
+  the now end-of-life PCRE version 1 (8.x) API.
+
+ - Removes PCRE API dependency from mod_qos.c. The module no longer has an
+   explicit dependency to the PCRE library but uses ap_pregcomp(),
+   ap_regexec(), and ap_regexec_len() from ap_regex.h.
+   Wrapping the PCRE (v1) and PCRE2 interface by the Apache httpd allows you
+   to use either the old or the new API version (depends on locating
+   pcre2-config). PCRE2 compatibility requires Apache httpd 2.4.53 or newer.
+
+ - Support utilities migrated to PCRE2 API (version 10.x).
+   Tested with PCRE2 version 10.41.
+
+ - Removed compatibility to Apache 2.0 and 2.2.
+
+Version 11.72
+
+ - Improve the support of Apache "event" MPM by calculating
+   a higher QS_MaxClients default value based on the
+   AsyncRequestWorkerFactor setting.
+
+Version 11.71
+
+ - Removed directive QS_Chroot.
+
+ - Minor code changes (improvements #39/#40 reported by
+   Rainer Jung - many thanks).
+
+ - QS_LogOnly also disables QS_EventKBytesPerSecLimit and
+   QS_LocKBytesPerSecLimit (deactivates delay output filter).
+
+ - Uses apr_temp_dir_get() to determine temp. directory for
+   semaphores/shared memory (default used to be /var/tmp).
+   Use QS_SemMemFile to override it.
+
+Version 11.70
+
+ - QS_ClientGeoCountryPriv skips clients whose IP address can't
+   be mapped to a country code if the argument 'excludeUnknown'
+   is specified.
+
+Version 11.69
+
+ - Internal: QS_SetEnvIf directives use an array to store all
+   rules (to ensure they are applied in the order they appear
+   in the configuration file).
+
+ - Apache 2.4.49 compatibility fix introduced by mod_qos 11.68 is no
+   longer applied for Apache version 2.4.50 and newer.
+   'QS_ForcedClose off' could be used to enable gentle connection
+   close handling manually.
+
+Version 11.68
+
+ - Compatibility with Apache 2.4.49 (avoid segfault when returning
+   error code in pre-connection hook / issue similar to CVE-2017-3169).
+
+Version 11.67
+
+ - The QS_LogEnv directive can be used to enable environment variable
+   logging. mod_qos writes all environment variables which are set when
+   entering a handler to the log.
+
+Version 11.66
+
+ - QS_ClientIpFromHeader supports pseudo IP by creating a hash
+   of a HTTP request header's value if the header name is prefixed
+   by '#', e.g. #Authorization to use the HTTP basic auth header.
+   It's also possible to use the client's SSL client certificate's
+   subject and issuer DN if you specify #SSL_CLIENT_S_DN instead
+   of a real HTTP header name.
+   Note: Does not work for IP geolocation.
+
+Version 11.65
+
+ - Fixed: QS_SrvMinDataRate did not enforce (log only) min data rate
+   in simple mode (only one arg).
+   Improved min. data rate calculation and updated documentation.
+
+ - Fixed: Several typos in documentation.
+
+Version 11.64
+
+ - Updated request header filter rules (allows signed HTTP exchanges content
+   type in Accept header).
+
+ - qsgeo: New pattern to detect "readable" format (no longer adding IP address
+   range twice for some file formats).
+
+ - QS_Status: adds the QS_AllConn variable to the maxClients object.
+
 Version 11.63
 
  - Adds the option 'jsredirect' to the QS_UserTrackingCookieName directive:
@@ -8,7 +106,7 @@
    - QS_UT_QUERY: query string to call (ajax) the cookie page again to
                   obtain the cookie.
    - QS_UT_NAME: name of the cookie
-   - QS_UT_INITIAL_URI: inital page to redirect to
+   - QS_UT_INITIAL_URI: initial page to redirect to
    Sample page: http://mod-qos.sourceforge.net/cookie-ir.shtml
 
 Version 11.62
@@ -36,7 +134,7 @@
 Version 11.59
 
  - QS_EventRequestLimit writes the current counter value to the
-   QS_EventRequestLimit_<env-variable>_Counter envrionment variable.
+   QS_EventRequestLimit_<env-variable>_Counter environment variable.
 
  - New directive QS_SetEnvIfCmp.
 
@@ -148,7 +246,7 @@
 Version 11.42c
 
  - qslog supports QSCOUNTERPATH (-pc mode) environment variable which
-   defines a file containg a list of QS_ClientEventLimitCount rules.
+   defines a file containing a list of QS_ClientEventLimitCount rules.
    The 'E' format character defines the event string in the log
    to match (literal string) the event1 and event2 event names against.
 
@@ -161,7 +259,7 @@
    Sample qslog rule:
     QS_LimitEv:AU04-2*AU05/600=20
 
-   Special us case mathing against the HTTP status code ('S' character)
+   Special us case matching against the HTTP status code ('S' character)
    is used if the rule 'name' starts with STATUS.
    Example mod_qos configuration:
     QS_ClientEventLimitCount 10 300 QS_LimisS
@@ -247,7 +345,7 @@
 Version 11.33
 
  - QS_ClientLowPrio variable's value contains the status flag representing
-   the tracked attribues.
+   the tracked attributes.
 
  - Sets QS_IsVipRequest variable for marked IP addresses at connection
    processing handler and propagetes it to every request.
@@ -281,7 +379,7 @@
 Version 11.29
 
  - mod_qos_ev variable sets character "u" if server is accessed by a
-   client wihout a user tracking cookie (but QS_UserTrackingCookieName
+   client without a user tracking cookie (but QS_UserTrackingCookieName
    has been configured).
 
  - Minor (non-functional) DSCP implementation code changes (incl. new log
@@ -319,7 +417,7 @@
 
 Version 11.23
 
- - Directive QS_SetEnvIf supports singe variable match.
+ - Directive QS_SetEnvIf supports single variable match.
 
  - qslog -p:
    * fallback to simple hour/minutes detection
@@ -510,14 +608,14 @@
  - Minor changes to the status viewer.
 
  - Modified error messages 060 and 067 (adding the "age" parameter which
-   indicates the seconds since the event occured the first time).
+   indicates the seconds since the event occurred the first time).
 
  - Fixed: Message 065 contained wrong directive name.
 
 Version 11.2
 
  - Adds variable QS_ResponseDelayTime showing the delay time (us)
-   calcualted for reponse throttling.
+   calculated for response throttling.
 
  - New variable QS_Timeout.
 
@@ -653,7 +751,7 @@
    for the default QS_Limit variable, in order to be processed by other
    rules.
 
- - Add Content-Security-Policy to the default response header white list.
+ - Add Content-Security-Policy to the default response header allow list.
 
  - qslog features enhanced "-pc" mode providing more information:
    * Collects content type information (%{content-type}o).
@@ -715,7 +813,7 @@
 
 Version 10.10
 
- - Add DNT HTTP request header to the default request header white list.
+ - Add DNT HTTP request header to the default request header allow list.
 
  - qslog "-pc" supports counting established connections.
 
@@ -794,7 +892,7 @@
 
  - Add the qsgeo utility to the distribution archive file.
 
- - Fixed: Supress warning message about missing mod_unique_id if 
+ - Fixed: Suppress warning message about missing mod_unique_id if 
    mod_navajo.cpp is available.
 
  - New connection correlation id QS_ConnectionId (available as
@@ -847,7 +945,7 @@
 
  - Fixed: Don't show connections in the overview if not measured.
 
- - Internal: QS_EventRequestLimit are added (insted of set) to the event
+ - Internal: QS_EventRequestLimit are added (instead of set) to the event
    table in order to prevent multiple increments by the very same request.
 
 Version 9.75
@@ -887,7 +985,7 @@
  - QS_ClientEventBlockCount is processed at pre_connection hook (more
    aggressive, before mod_ssl).
 
- - Supress warning message about missing mod_unique_id if mod_navajo is
+ - Suppress warning message about missing mod_unique_id if mod_navajo is
    available.
 
 Version 9.71
@@ -919,12 +1017,12 @@
  - Adjust attributes/number of requests required to identify the client
    behavior.
 
- - Update request header white list rule for Content-Type.
+ - Update request header allow list rule for Content-Type.
 
 Version 9.69
 
  - Client behavior (content type a client is downloading) is calculated
-   in a percent of the whole trafic type distribution. The directive
+   in a percent of the whole traffic type distribution. The directive
    QS_ClientTolerance supports only values between 5 and 80.
 
  - Add directive QS_ClientContentTypes to define the normally downloaded
@@ -949,7 +1047,7 @@
 
  - qslog extracts additional time formats (offline mode).
 
- - Added "X-Do-Not-Track" to the built-in request header white list.
+ - Added "X-Do-Not-Track" to the built-in request header allow list.
 
  - Minor changes within the status viewer (machine-readable view).
 
@@ -1007,7 +1105,7 @@
  - New variable QS_ErrorNotes.
 
  - Add "Transfer-Encoding" (very strict) to the built-in request header
-   white list.
+   allow list.
 
 Version 9.57
 
@@ -1126,7 +1224,7 @@
 
  - Console "action=search&address=*" returns a list of all clients.
 
- - Fixed: Removes the apr_shm_destroy() calls to avaoid double-free
+ - Fixed: Removes the apr_shm_destroy() calls to avoid double-free
    errors on Linux with old APR library versions.
 
 Version 9.41
@@ -1410,7 +1508,7 @@
 
 Version 8.13
 
- - New directives QS_DenyQueryBody and QS_PermitUriBody obsolte
+ - New directives QS_DenyQueryBody and QS_PermitUriBody obsolete
    QS_DenyBody.
 
  - Fixed: QS_Deny*/QS_Permit* directives can handle strings containing
@@ -1540,7 +1638,7 @@
 
  - Process event filter only if some rules have been defined.
 
- - Recovery rate (decreas limitation) for bandwidth and and request
+ - Recovery rate (decrease limitation) for bandwidth and and request
    limit has been increased from 16% to 25%.
 
 Version 7.11
@@ -1555,7 +1653,7 @@
 Version 7.8
 
  - Directive QS_SrvMinDataRate/QS_SrvRequestRate supports min/max
-   limitation in order to increase the minimum upload/download bandwith
+   limitation in order to increase the minimum upload/download bandwidth
    on multiple simultaneously connections.
 
  - Fixed: Activation of QS_SrvMinDataRate did not work
@@ -1573,7 +1671,7 @@
 
 Version 7.5
 
- - New diretive QS_ErrorResponseCode
+ - New directive QS_ErrorResponseCode
 
  - Multiple directives (QS_LocRequestLimit, QS_LocRequestLimitMatch,
    QS_CondLocRequestLimitMatch, QS_ClientEventBlockCount, and
@@ -1601,7 +1699,7 @@
 
 Version 7.0
 
- - New directive QS_SrvRequestRate enforces minimum upload bandwith
+ - New directive QS_SrvRequestRate enforces minimum upload bandwidth
    (used for TCP DoS prevention). Requires thread support.
 
  - QS_ClientPrefer allows definition of free connections in percent
@@ -1613,7 +1711,7 @@
 
 Version 6.7
 
- - Detects low priotity clients (clients sending slow or using small
+ - Detects low priority clients (clients sending slow or using small
    data packets get marked as low priority clients). 
 
  - New directives QS_VipUser and QS_VipIpUser.
@@ -1701,7 +1799,7 @@
 
 Version 5.10
 
- - Rules do not use individual mutex any longer. This allows an unlimted
+ - Rules do not use individual mutex any longer. This allows an unlimited
    number of rules.
 
 Version 5.9
@@ -1768,7 +1866,7 @@
 
  - Add new directive QS_DenyInheritanceOff
 
- - Add qsfilter2, a tool to generate request URI white list rules.
+ - Add qsfilter2, a tool to generate request URI allow list rules.
 
  - Use mod_unique_id to tag error messages.
 
diff -Nru libapache2-mod-qos-11.63/doc/glossary.html libapache2-mod-qos-11.74/doc/glossary.html
--- libapache2-mod-qos-11.63/doc/glossary.html	2019-05-25 09:08:59.000000000 -0400
+++ libapache2-mod-qos-11.74/doc/glossary.html	2023-05-18 08:34:25.000000000 -0400
@@ -32,7 +32,7 @@
 
  See http://mod-qos.sourceforge.net/ for further details.
 
- Copyright (C) 2019 Pascal Buchbinder
+ Copyright (C) 2023 Pascal Buchbinder
 
  Licensed to the Apache Software Foundation (ASF) under one or more
  contributor license agreements.  See the NOTICE file distributed with
@@ -178,7 +178,7 @@
 <h2>Concurrency Counter</h2>
 <p>
 A "concurrency counter" is used to determine how many times something 
-happens at the same time, e.g. HTTP requests accessing the same 
+happens at the same time (concurrent), e.g. HTTP requests accessing the same 
 resource/URL at the same time. The rules using this counter type are either 
 defined by an <a href="#variables">environment variable name</a> or an 
 URL pattern (regular expression or a string matching the request's URL). 
@@ -221,25 +221,25 @@
 <td>
 As long as the server has enough resources, users can access both 
 applications the same time without influencing each other.<br> 
-All requests are processed quickly and the workers become free 
+All requests are processed quickly and the workers (w) become free 
 again to serve new requests.
 <br><br>
 </td>
 <td>
-  <img src="images/qsloc1.png" height="212" width="439" alt="trouble-free"/>
+<small>&nbsp;</small>  <img src="images/qsloc1.png" height="216" width="408" alt="trouble-free"/>
 </td>
   </tr>
   <tr>
 <td>&nbsp;&nbsp;&nbsp;&nbsp;</td>
 <td>
 But if the application "<font color="blue">B</font>" becomes slow, 
-the duration of request processing increases and all workers become busy. 
+the duration of request processing increases and all workers (w) become busy. 
 There are no free workers left and application 
 "<font color="green">A</font>" becomes unavailable because of that.
 <br><br>
 </td>
 <td>
-  <img src="images/qsloc2.png" height="223" width="439" alt="disruption"/>
+  <img src="images/qsloc2.png" height="212" width="422" alt="disruption"/>
 </td>
   </tr>
   <tr>
@@ -250,11 +250,11 @@
 rule can help in such a situation. mod_qos limits the 
 number of requests to application "<font color="blue">B</font>" 
 so that application "<font color="green">A</font>" remains 
-available even application "<font color="blue">B</font>" 
-has problems.
+available even if application "<font color="blue">B</font>" 
+has performance problems.
 </td>
 <td>
-  <img src="images/qsloc3.png" height="241" width="439" alt="disruption"/>
+  <img src="images/qsloc3.png" height="244" width="422" alt="disruption"/>
 </td>
   </tr>
 </table>
@@ -333,7 +333,9 @@
 <li><a href="index.html#QS_LocKBytesPerSecLimit"><syntax>QS_LocKBytesPerSecLimit</syntax></a></li>
 <li><a href="index.html#QS_EventKBytesPerSecLimit"><syntax>QS_EventKBytesPerSecLimit</syntax></a></li>
 </ul>
-</p>
+<i>Note: Throughput control should always be used with a <a href="#concurrency">concurrency counter</a> 
+because the added delay increases the number of simultaneous requests.
+</i></p>
 <a name="requestPerSecond"></a>
 <h3>Requests per Second</h3>
 <p>
@@ -347,6 +349,7 @@
 <li><a href="index.html#QS_LocRequestPerSecLimitMatch"><syntax>QS_LocRequestPerSecLimitMatch</syntax></a></li>
 <li><a href="index.html#QS_LocRequestPerSecLimit"><syntax>QS_LocRequestPerSecLimit</syntax></a></li>
 <li><a href="index.html#QS_EventPerSecLimit"><syntax>QS_EventPerSecLimit</syntax></a></li>
+<li><a href="index.html#QS_ClientEventPerSecLimit"><syntax>QS_ClientEventPerSecLimit</syntax></a></li>
 </ul>
 </p>
 
@@ -357,7 +360,7 @@
 <h2>Serialization</h2>
 <p>
 <a href="index.html">mod_qos</a> offers you the option to serialize requests. 
-Serialization means, that requests are processed one after the other. Incomming
+Serialization means, that requests are processed one after the other. Incoming
 requests are queued if another request is in process and have to wait until
 the previous request is finished.
 </p>
@@ -376,7 +379,7 @@
 Serialization might be applied on a per 
 <a href="index.html#QS_SrvSerialize">server level</a> (serializing all HTTP
 requests) or on a <a href="index.html#QS_ClientSerialize">per client level</a>
-(serializing multiple requests comming from the same client/IP address).
+(serializing multiple requests coming from the same client/IP address).
 </p>
 
 
@@ -489,7 +492,7 @@
 <p>
 This feature is enabled by the following directive:
 <ul>
-<li><syntax>QS_UserTrackingCookieName &lt;name&gt; [&lt;path&gt;] [&lt;domain&gt;] ['session']</syntax><br>
+<li><syntax>QS_UserTrackingCookieName &lt;name&gt; [&lt;path&gt;] [&lt;domain&gt;] ['session'] ['jsredirect']</syntax><br>
 The parameter "name" defines the cookie's name and "domain" (optional) 
 the domain attribute for the Set-Cookie header. The string "session" can 
 be defined if the cookie should not be stored by the session (but can 
@@ -571,7 +574,7 @@
 </table>
 </p><p>
 Or you can use it to process any existing log file using the post processing 
-optin <code>-p</code>. This does not only work for 
+option <code>-p</code>. This does not only work for 
 <a href="http://httpd.apache.org/docs/current/mod/mod_log_config.html";>Apache log  <img src="images/link.png"/></a> files but for any other log file as well. You just have to know what's in the log 
 and configure the format string argument <code>-f</code> of the 
 <code><a href="qslog.1.html">qslog</a></code> command accordingly.
@@ -581,7 +584,7 @@
 <img src="images/qslogFormat.png" height="381" width="738" alt="log format definition"/>  
 </p>
 <p>
-The ouput shows the data as a function of time: a summary of what happened every minute. 
+The output shows the data as a function of time: a summary of what happened every minute. 
 Each line includes all measured values as semicolon spearated name/value pairs (CSV).
 </p>
 <p>
@@ -595,6 +598,6 @@
 </table>
 <br>
 <hr>
-<SMALL><SMALL>&copy; 2019, Pascal Buchbinder</SMALL></SMALL>
+<SMALL><SMALL>&copy; 2023, Pascal Buchbinder</SMALL></SMALL>
 </body>
 </html>
diff -Nru libapache2-mod-qos-11.63/doc/headerfilterrules.txt libapache2-mod-qos-11.74/doc/headerfilterrules.txt
--- libapache2-mod-qos-11.63/doc/headerfilterrules.txt	2019-05-25 09:08:59.000000000 -0400
+++ libapache2-mod-qos-11.74/doc/headerfilterrules.txt	2023-05-18 08:34:25.000000000 -0400
@@ -1,51 +1,51 @@
 
 QS_RequestHeaderFilter rules:
 
- name=Accept, action=drop, size=300, pattern=^([a-zA-Z0-9_\*\+\-]+/[a-zA-Z0-9_\*\+\.\-]+(;[ ]?[a-zA-Z0-9]+=[0-9]+)?[ ]?(;[ ]?q=[0-9\.]+)?){1}([ ]?,[ ]?([a-zA-Z0-9_\*\+\-]+/[a-zA-Z0-9_\*\+\.\-]+(;[ ]?[a-zA-Z0-9]+=[0-9]+)?[ ]?(;[ ]?q=[0-9\.]+)?))*$
- name=Accept-Charset, action=drop, size=300, pattern=^([a-zA-Z0-9\*\-]+(;[ ]?q=[0-9\.]+)?){1}([ ]?,[ ]?([a-zA-Z0-9\*\-]+(;[ ]?q=[0-9\.]+)?))*$
- name=Accept-Encoding, action=drop, size=500, pattern=^([a-zA-Z0-9\*\-]+(;[ ]?q=[0-9\.]+)?){1}([ ]?,[ ]?([a-zA-Z0-9\*\-]+(;[ ]?q=[0-9\.]+)?))*$
- name=Accept-Language, action=drop, size=200, pattern=^([a-zA-Z\*\-]+[0-9]{0,3}(;[ ]?q=[0-9\.]+)?){1}([ ]?,[ ]?([a-zA-Z\*\-]+[0-9]{0,3}(;[ ]?q=[0-9\.]+)?))*$
+ name=Accept, action=drop, size=300, pattern=^([a-zA-Z0-9_*+-]+/[a-zA-Z0-9_*+.-]+(;[ ]?[a-zA-Z0-9]+=[0-9]+)?[ ]?(;[ ]?[qv]=[a-z0-9.]+)?){1}([ ]?,[ ]?([a-zA-Z0-9_*+-]+/[a-zA-Z0-9_*+.-]+(;[ ]?[a-zA-Z0-9]+=[0-9]+)?[ ]?(;[ ]?[qv]=[a-z0-9.]+)?))*$
+ name=Accept-Charset, action=drop, size=300, pattern=^([a-zA-Z0-9*-]+(;[ ]?q=[0-9.]+)?){1}([ ]?,[ ]?([a-zA-Z0-9*-]+(;[ ]?q=[0-9.]+)?))*$
+ name=Accept-Encoding, action=drop, size=500, pattern=^([a-zA-Z0-9*-]+(;[ ]?q=[0-9.]+)?){1}([ ]?,[ ]?([a-zA-Z0-9*-]+(;[ ]?q=[0-9.]+)?))*$
+ name=Accept-Language, action=drop, size=200, pattern=^([a-zA-Z*-]+[0-9]{0,3}(;[ ]?q=[0-9.]+)?){1}([ ]?,[ ]?([a-zA-Z*-]+[0-9]{0,3}(;[ ]?q=[0-9.]+)?))*$
  name=Access-Control-Request-Method, action=drop, size=10, pattern=^[a-zA-Z]+$
  name=Access-Control-Request-Headers, action=drop, size=500, pattern=^([a-zA-Z0-9-]+){1}([ ]?,[ ]?([a-zA-Z0-9-]+))*$
- name=Authorization, action=drop, size=4000, pattern=^[a-zA-Z0-9 \+/\$=:]+$
+ name=Authorization, action=drop, size=4000, pattern=^[a-zA-Z0-9 +/$=:]+$
  name=Cache-Control, action=drop, size=100, pattern=^(no-cache|no-store|max-age=[0-9]+|max-stale(=[0-9]+)?|min-fresh=[0-9]+|no-transform|only-if-chached){1}([ ]?,[ ]?(no-cache|no-store|max-age=[0-9]+|max-stale(=[0-9]+)?|min-fresh=[0-9]+|no-transform|only-if-chached))*$
- name=Connection, action=drop, size=100, pattern=^([teTE]+,[ ]?)?([a-zA-Z0-9\-]+){1}([ ]?,[ ]?([teTE]+))?$
- name=Content-Encoding, action=deny, size=100, pattern=^[a-zA-Z0-9\-]+(,[ ]*[a-zA-Z0-9\-]+)*$
+ name=Connection, action=drop, size=100, pattern=^([teTE]+,[ ]?)?([a-zA-Z0-9-]+){1}([ ]?,[ ]?([teTE]+))?$
+ name=Content-Encoding, action=deny, size=100, pattern=^[a-zA-Z0-9-]+(,[ ]*[a-zA-Z0-9-]+)*$
  name=Content-Language, action=drop, size=100, pattern=^([0-9a-zA-Z]{0,8}(-[0-9a-zA-Z]{0,8})*)(,[ ]*([0-9a-zA-Z]{0,8}(-[0-9a-zA-Z]{0,8})*))*$
  name=Content-Length, action=deny, size=10, pattern=^[0-9]+$
- name=Content-Location, action=deny, size=200, pattern=^[:/\?#\[\]@!\$&'\(\)\*\+,;=a-zA-Z0-9\._~% \-]+$
- name=Content-md5, action=deny, size=50, pattern=^[a-zA-Z0-9 \+/\$=:]+$
+ name=Content-Location, action=deny, size=200, pattern=^[:/?#\[\]@!$&'()*+,;=a-zA-Z0-9._~% -]+$
+ name=Content-md5, action=deny, size=50, pattern=^[a-zA-Z0-9 +/$=:]+$
  name=Content-Range, action=deny, size=50, pattern=^(bytes[ ]+([0-9]+-[0-9]+)/([0-9]+|\*))$
- name=Content-Type, action=deny, size=200, pattern=^(["a-zA-Z0-9\*/; =\-]+){1}([ ]?,[ ]?(["a-zA-Z0-9\*/; =\-]+))*$
- name=Cookie, action=drop, size=3000, pattern=^[:/\?#\[\]@!\$&'\(\)\*\+,;="a-zA-Z0-9\._~% \-]+$
- name=Cookie2, action=drop, size=3000, pattern=^[:/\?#\[\]@!\$&'\(\)\*\+,;="a-zA-Z0-9\._~% \-]+$
+ name=Content-Type, action=deny, size=200, pattern=^(["a-zA-Z0-9*/; =-]+){1}([ ]?,[ ]?(["a-zA-Z0-9*/; =-]+))*$
+ name=Cookie, action=drop, size=3000, pattern=^[:/?#\[\]@!$&'()*+,;="a-zA-Z0-9._~% -]+$
+ name=Cookie2, action=drop, size=3000, pattern=^[:/?#\[\]@!$&'()*+,;="a-zA-Z0-9._~% -]+$
  name=DNT, action=drop, size=3, pattern=^[0-9]+$
- name=Expect, action=drop, size=200, pattern=^[a-zA-Z0-9= ;\.,\-]+$
- name=From, action=drop, size=100, pattern=^[a-zA-Z0-9=@;\.,\(\)\-]+$
- name=Host, action=drop, size=100, pattern=^[a-zA-Z0-9\.\-]+(:[0-9]+)?$
- name=If-Invalid, action=drop, size=500, pattern=^[a-zA-Z0-9_\.:;\(\) /\+!\-]+$
- name=If-Match, action=drop, size=100, pattern=^(W/)?[a-zA-Z0-9=@;\.,\*"\-]+$
+ name=Expect, action=drop, size=200, pattern=^[a-zA-Z0-9= ;.,-]+$
+ name=From, action=drop, size=100, pattern=^[a-zA-Z0-9=@;.,()-]+$
+ name=Host, action=drop, size=100, pattern=^[a-zA-Z0-9.-]+(:[0-9]+)?$
+ name=If-Invalid, action=drop, size=500, pattern=^[a-zA-Z0-9_.:;() /+!-]+$
+ name=If-Match, action=drop, size=100, pattern=^(W/)?[a-zA-Z0-9=@;.,*"-]+$
  name=If-Modified-Since, action=drop, size=100, pattern=^[a-zA-Z0-9 :,]+$
- name=If-None-Match, action=drop, size=100, pattern=^(W/)?[a-zA-Z0-9=@;\.,\*"\-]+$
- name=If-Range, action=drop, size=100, pattern=^[a-zA-Z0-9=@;\.,\*"\-]+$
+ name=If-None-Match, action=drop, size=100, pattern=^(W/)?[a-zA-Z0-9=@;.,*"-]+$
+ name=If-Range, action=drop, size=100, pattern=^[a-zA-Z0-9=@;.,*"-]+$
  name=If-Unmodified-Since, action=drop, size=100, pattern=^[a-zA-Z0-9 :,]+$
- name=If-Valid, action=drop, size=500, pattern=^[a-zA-Z0-9_\.:;\(\) /\+!\-]+$
+ name=If-Valid, action=drop, size=500, pattern=^[a-zA-Z0-9_.:;() /+!-]+$
  name=Keep-Alive, action=drop, size=20, pattern=^[0-9]+$
  name=Max-Forwards, action=drop, size=20, pattern=^[0-9]+$
- name=Origin, action=drop, size=2000, pattern=^[:/\?#\[\]@!\$&'\(\)\*\+,;=a-zA-Z0-9\._~% \-]+$
- name=Proxy-Authorization, action=drop, size=400, pattern=^[a-zA-Z0-9 \+/\$=:]+$
- name=Pragma, action=drop, size=200, pattern=^[a-zA-Z0-9= ;\.,\-]+$
- name=Range, action=drop, size=200, pattern=^[a-zA-Z0-9=_\.:;\(\) /\+!\-]+$
- name=Referer, action=drop, size=2000, pattern=^[:/\?#\[\]@!\$&'\(\)\*\+,;=a-zA-Z0-9\._~% \-]+$
- name=TE, action=drop, size=100, pattern=^([a-zA-Z0-9\*\-]+(;[ ]?q=[0-9\.]+)?){1}([ ]?,[ ]?([a-zA-Z0-9\*\-]+(;[ ]?q=[0-9\.]+)?))*$
+ name=Origin, action=drop, size=2000, pattern=^[:/?#\[\]@!$&'()*+,;=a-zA-Z0-9._~% -]+$
+ name=Proxy-Authorization, action=drop, size=400, pattern=^[a-zA-Z0-9 +/$=:]+$
+ name=Pragma, action=drop, size=200, pattern=^[a-zA-Z0-9= ;.,-]+$
+ name=Range, action=drop, size=200, pattern=^[a-zA-Z0-9=_.:;() /+!-]+$
+ name=Referer, action=drop, size=2000, pattern=^[:/?#\[\]@!$&'()*+,;=a-zA-Z0-9._~% -]+$
+ name=TE, action=drop, size=100, pattern=^([a-zA-Z0-9*-]+(;[ ]?q=[0-9.]+)?){1}([ ]?,[ ]?([a-zA-Z0-9*-]+(;[ ]?q=[0-9.]+)?))*$
  name=Transfer-Encoding, action=deny, size=100, pattern=^(chunked|Chunked|compress|Compress|deflate|Deflate|gzip|Gzip|identity|Identity)([ ]?,[ ]?(chunked|Chunked|compress|Compress|deflate|Deflate|gzip|Gzip|identity|Identity))*$
  name=Unless-Modified-Since, action=drop, size=100, pattern=^[a-zA-Z0-9 :,]+$
  name=User-Agent, action=drop, size=300, pattern=^[a-zA-Z0-9]+[a-zA-Z0-9_.:;()\[\]@ /+!=,-]+$
  name=Upgrade-Insecure-Requests, action=drop, size=1, pattern=^1$
- name=Via, action=drop, size=100, pattern=^[a-zA-Z0-9_\.:;\(\) /\+!\-]+$
- name=X-Forwarded-For, action=drop, size=100, pattern=^[a-zA-Z0-9_\.:\-]+(, [a-zA-Z0-9_\.:\-]+)*$
- name=X-Forwarded-Host, action=drop, size=100, pattern=^[a-zA-Z0-9_\.:\-]+$
- name=X-Forwarded-Server, action=drop, size=100, pattern=^[a-zA-Z0-9_\.:\-]+$
+ name=Via, action=drop, size=100, pattern=^[a-zA-Z0-9_.:;() /+!-]+$
+ name=X-Forwarded-For, action=drop, size=100, pattern=^[a-zA-Z0-9_.:-]+(, [a-zA-Z0-9_.:-]+)*$
+ name=X-Forwarded-Host, action=drop, size=100, pattern=^[a-zA-Z0-9_.:-]+$
+ name=X-Forwarded-Server, action=drop, size=100, pattern=^[a-zA-Z0-9_.:-]+$
  name=X-lori-time-1, action=drop, size=20, pattern=^[0-9]+$
  name=X-Do-Not-Track, action=drop, size=20, pattern=^[0-9]+$
 
@@ -94,4 +94,4 @@
  name=X-Frame-Options, action=drop, size=4000, pattern=^[\x20-\xFF]*$
  name=X-XSS-Protection, action=drop, size=4000, pattern=^[\x20-\xFF]*$
 
-mod_qos 11.63
+mod_qos 11.74
Les fichiers binaires /tmp/mRp2__oNJk/libapache2-mod-qos-11.63/doc/images/directive_seq.gif et /tmp/VNuQHZw_4K/libapache2-mod-qos-11.74/doc/images/directive_seq.gif sont différents
Les fichiers binaires /tmp/mRp2__oNJk/libapache2-mod-qos-11.63/doc/images/qsloc1.png et /tmp/VNuQHZw_4K/libapache2-mod-qos-11.74/doc/images/qsloc1.png sont différents
Les fichiers binaires /tmp/mRp2__oNJk/libapache2-mod-qos-11.63/doc/images/qsloc2.png et /tmp/VNuQHZw_4K/libapache2-mod-qos-11.74/doc/images/qsloc2.png sont différents
Les fichiers binaires /tmp/mRp2__oNJk/libapache2-mod-qos-11.63/doc/images/qsloc3.png et /tmp/VNuQHZw_4K/libapache2-mod-qos-11.74/doc/images/qsloc3.png sont différents
Les fichiers binaires /tmp/mRp2__oNJk/libapache2-mod-qos-11.63/doc/images/SrvMinDataRate.png et /tmp/VNuQHZw_4K/libapache2-mod-qos-11.74/doc/images/SrvMinDataRate.png sont différents
diff -Nru libapache2-mod-qos-11.63/doc/index.html libapache2-mod-qos-11.74/doc/index.html
--- libapache2-mod-qos-11.63/doc/index.html	2019-05-25 09:08:59.000000000 -0400
+++ libapache2-mod-qos-11.74/doc/index.html	2023-05-18 08:34:25.000000000 -0400
@@ -34,7 +34,7 @@
 
  See http://mod-qos.sourceforge.net/ for further details.
 
- Copyright (C) 2019 Pascal Buchbinder
+ Copyright (C) 2023 Pascal Buchbinder
 
  Licensed to the Apache Software Foundation (ASF) under one or more
  contributor license agreements.  See the NOTICE file distributed with
@@ -124,8 +124,8 @@
 throttling, and dropping of TCP connections.
 </p>
 <p>
-The current release of the mod_qos module implements control 
-mechanisms:
+The <a title="change log" href="CHANGES.txt">current release</a> of the mod_qos 
+module implements various control mechanisms:
 <ul>
 <li type=square>
 The maximum number of <a href="glossary.html#concurrency">concurrent</a> 
@@ -166,6 +166,9 @@
 <li type=square>
 Prefers known IP addresses when server runs out of free TCP connections.
 </li>
+<li type=square>
+Serialization of requests.
+</li>
 </ul>
 </p>
 <hr>
@@ -218,14 +221,15 @@
 <a name="build"></a>
 <h2>Build</h2>
 <p>
-mod_qos requires OpenSSL, PCRE, threading and shared memory support. mod_qos 
-was originally developed and fully tested for Apache version 2.2 
-<a href="http://httpd.apache.org/docs/2.2/mod/worker.html";>MPM worker <img src="images/link.png"/></a> 
-binaries, but works with Apache version 2.4 as well. The module is optimized to be used in a 
+mod_qos requires OpenSSL, PCRE, threading and shared memory support. 
+mod_qos is designed to be used with Apache's
+<a href="http://httpd.apache.org/docs/current/mod/worker.html";>MPM worker <img src="images/link.png"/></a> 
+binaries but works, with some restrictions, also with other Apache 2.4 multi-processing modules.
+The module is optimized to be used in a 
 <a href="http://httpd.apache.org/docs/current/mod/mod_proxy.html";>reverse proxy 
 <img src="images/link.png"/></a> server.<p>
 <p>
-<small><i>Notes:<br>&nbsp; You should definitely choose the <a href="https://httpd.apache.org/docs/current/mod/worker.html";>worker MPM <img src="images/link.png"/></a> 
+<small><i>Notes:<br>&nbsp; You should choose the <a href="https://httpd.apache.org/docs/current/mod/worker.html";>worker MPM <img src="images/link.png"/></a> 
 if you intend to use any <a href="#connectionlevelcontrol">connection level control</a> directive. <br>
 &nbsp; If you decide to use <a href="https://httpd.apache.org/docs/current/howto/http2.html";>HTTP/2 <img src="images/link.png"/></a>, 
 you should only use the <a href="#requestlevelcontrol">request level control</a> directives  
@@ -244,8 +248,8 @@
 <table border="0" cellspacing="5" cellpadding="10" width="100%">
 <tr><td bgcolor="#E2EDE2">
 <pre>
-cd mod_qos-11.63/apache2
-apxs -i -c mod_qos.c -lcrypto -lpcre
+cd mod_qos-11.74/apache2
+apxs -i -c mod_qos.c -lcrypto -lpcre2-8
 cd ../..
 </pre>
 </td></tr>
@@ -315,12 +319,12 @@
 <p>
 The <a href="#utilities">support tools</a> may be built (at least on some 
 Linux platforms) using the GNU autotools. Some of these 
-utilities require third-party libraries such as apr, apr-util, PCRE, 
+utilities require third-party libraries such as apr, apr-util, PCRE2, 
 libpng, and OpenSSL.
 <table border="0" cellspacing="5" cellpadding="10" width="100%">
 <tr><td bgcolor="#E2EDE2">
 <pre>
-cd mod_qos-11.63/tools
+cd mod_qos-11.74/tools
 ./configure
 make
 </pre>
@@ -343,7 +347,7 @@
 <a name="source"></a>
 <h2>Source Code</h2>
 <p>
-<a href="../apache2">mod_qos</a> is available for Apache version 2.2 respectively 2.4.
+<a href="../apache2">mod_qos</a> is available for Apache version 2.4.
 </p>
 
 <!-- DIST END -->
@@ -367,9 +371,11 @@
 <p>
 <a name="QS_LogOnly"></a>
 The <code>QS_LogOnly on</code> directive may be used to put mod_qos 
-into a permissive mode where rule violations are logged only but no 
-actions are applied to requests or connections to enforce a rule. 
-This may be used for test purposes.
+into a permissive mode where rule violations are logged only but 
+requests/connections are not blocked. This may be used for test purposes.<br>
+Should not be activated if you are using any 
+<a href="glossary.html#throughput">throughput control</a> 
+directive (open loop).
 </p>
 
 <p>
@@ -390,7 +396,7 @@
 <a name="QS_LocRequestLimitMatch"></a>
 <syntax>QS_LocRequestLimitMatch &lt;regex&gt; &lt;number&gt;</syntax><br>
 Defines the number of <a href="glossary.html#concurrency">concurrent</a> 
-requests for the specified request pattern (applied to the unparsed URL). 
+requests for the specified request pattern (path and query). 
 The rule with the lowest number of allowed concurrent connections has the 
 highest priority if multiple expressions match the request. 
 By default, no limitations are active.
@@ -460,7 +466,7 @@
 <a name="QS_LocKBytesPerSecLimit"></a>
 <syntax>QS_LocKBytesPerSecLimit &lt;location&gt; &lt;number&gt;</syntax><br>
 Throttles the download <a href="glossary.html#throughput">bandwidth</a> to the defined
-kbytes per second. Works simlar as the
+kbytes per second. Works similar as the
 <a href="#QS_LocKBytesPerSecLimitMatch"><code>QS_LocKBytesPerSecLimitMatch</code></a> 
 directive slowing down HTTP responses by adding a delay to each response. 
 By default, no limitation is active. This directive should be used in 
@@ -933,7 +939,7 @@
 <a name="QS_ErrorNotes"></a>
 <syntax>QS_ErrorNotes</syntax><br>
 The error code (number only) of a mod_qos <a href="#errorlog">log message</a> 
-that has occured during a request.
+that has occurred during a request.
 </li>
 <li>
 <a name="QS_Country"></a>
@@ -976,6 +982,11 @@
 </pre>
 </td></tr>
 </table>
+<a name="QS_LogEnv"></a>
+<small><i>Note: The <code>QS_LogEnv</code> directive can be used to enable environment variable logging. mod_qos 
+writes all environment variables which are set when entering a <a href="glossary.html#directives">handler</a> 
+to the log.</i></small>
+<br>
 
 <a name="conditionalrules"></a>
 <h3>Conditional Rules</h3>
@@ -1051,7 +1062,7 @@
 <code><a href="#QS_LocRequestLimit">QS_LocRequestLimit</a></code>, but 
 counts the requests having the same environment variable (and optionally 
 matching its value, too) rather than those that have the same URL pattern. 
-<br><small><i>Note: The counter's value is stored in the enviroment variable 
+<br><small><i>Note: The counter's value is stored in the environment variable 
 QS_EventRequestLimit_&lt;env-variable&gt;_Counter.
 </i></small>
 </li>
@@ -1152,7 +1163,7 @@
 <a name="QS_SetEnvIfCmp"></a>
 <li>
 <syntax>QS_SetEnvIfCmp &lt;env-variable1&gt; eq|ne|gt|lt &lt;env-variable2&gt; [!]&lt;env-variable&gt;[=&lt;value&gt;]</syntax><br>
-Sets the defined environment variable if the specifed env-variables[1|2] 
+Sets the defined environment variable if the specified env-variables[1|2] 
 are numerical or alphabetically (case insensitive) equal (<code>eq</code>), 
 not equal (<code>ne</code>) greater (<code>gt</code>), or less (<code>lt</code>).<br> 
 This directive may be used on a per-<a href="http://httpd.apache.org/docs/current/mod/core.html.en#location";>location <img src="images/link.png"/></a> 
@@ -1256,7 +1267,7 @@
 <li>
 <a name="QS_SetEnvRes"></a>
 <syntax>QS_SetEnvRes &lt;env-variable&gt; &lt;regex&gt; &lt;env-variable2&gt;[=&lt;value&gt;]</syntax><br>
-Sets the environmet variable (env-variable2) if the regular expression (regex) matches 
+Sets the environment variable (env-variable2) if the regular expression (regex) matches 
 against the value of the environment variable (env-variable). Occurrences of $1..$9 within 
 the value are replaced by parenthesized subexpressions of the regular expression.
 </li>
@@ -1270,13 +1281,13 @@
 <li>
 <a name="QS_SetEnvResHeader"></a>
 <syntax>QS_SetEnvResHeader &lt;header name&gt; [drop]</syntax><br>
-Sets the defined HTTP response header to the request environment variables. 
+Sets the defined HTTP response header (name and value) to the request environment variables. 
 Deletes the specified header if the action 'drop' has been specified.
 </li>
 <li>
 <a name="QS_SetEnvResHeaderMatch"></a>
 <syntax>QS_SetEnvResHeaderMatch &lt;header name&gt; &lt;regex&gt;</syntax><br>
-Sets the defined HTTP response header to the request environment variables if 
+Sets the defined HTTP response header (name and value) to the request environment variables if 
 the specified regular expression (pcre, not case sensitive) matches 
 the header value.
 </li>
@@ -1415,7 +1426,7 @@
 <a name="QS_PermitUri"></a>
 <syntax>QS_PermitUri '+'|'-'&lt;id&gt; 'log'|'deny' &lt;pcre&gt;</syntax><br>
 Generic URL (path and query) filter implementing a request pattern 
-whitelist. Only requests matching at least one <code>QS_PermitUri</code> 
+allow list. Only requests matching at least one <code>QS_PermitUri</code> 
 pattern are allowed. If a <code>QS_PermitUri</code> pattern has 
 been defined and the request does not match any rule, the request 
 is denied. 
@@ -1435,7 +1446,7 @@
 Filters request headers using validation rules <a href="headerfilterrules.txt">provided by mod_qos</a>. 
 Suspicious headers (not matching the pattern or those which are too long) are normally 
 dropped (removed from the request). Abnormal <code>content-*</code> headers cause 
-request blocking. Only the defined headers are allowed (whitelist). Custom 
+request blocking. Only the defined headers are allowed (allow list). Custom 
 rules (additional headers or different pattern/size definitions) may be 
 added using the 
 <code><a href="#QS_RequestHeaderFilterRule">QS_RequestHeaderFilterRule</a></code> 
@@ -1454,7 +1465,7 @@
 directives and therefore a header sent a by client 
 can override an environment variable having the same name.</li>
 <li>
-You might also configure blacklist rules (delete unwanted headers) using the 
+You might also configure deny list rules (delete unwanted headers) using the 
 <code><a href="#QS_UnsetReqHeader">QS_UnsetReqHeader</a></code> or 
 <code><a href="#QS_UnsetResHeader">QS_UnsetResHeader</a></code> directive.
 </li>
@@ -1557,11 +1568,11 @@
 Sample configuration:<br><a name="qsfiltersample"></a>
 <pre>
 # configure the audit log writing the request body data to a file
-# (use this log to generate whitelist rules using <a href="qsfilter2.1.html">qsfilter2</a>
+# (use this log to generate allow list rules using <a href="qsfilter2.1.html">qsfilter2</a>
 # when <a href="#QS_PermitUriBody">QS_PermitUriBody</a> has been enabled)
 # format:
 #   %h:
-#   The remote host (used to filter by IP adress).
+#   The remote host (used to filter by IP address).
 #   %>s:
 #   The HTTP response status code.
 #   %{qos-loc}n
@@ -1728,12 +1739,12 @@
 with low priority (see the <code><a href="#QS_ClientPrefer">QS_ClientPrefer</a></code> directive). 
 The "max bytes per second" activates <u><a href="images/SrvMinDataRate.png">dynamic minimum throughput control</a></u>: 
 The required minimal throughput is increased in parallel to the number of concurrent clients 
-sending/receiving data (starts increasing when reaching the "connections" threshold). 
-The "max bytes per second" setting is reached when the number of 
+sending/receiving data (starts increasing when reaching the "connections" threshold) 
+as a percentage of the "max bytes per second" which maximum is reached when the number of 
 sending/receiving clients is equal to the <code>MaxClients</code> setting. 
 The "connections" argument is used to specify the number of busy TCP connections a 
-server must have to enable this feature (0 by default). It is used to disable the 
-<code>QS_SrvMinDataRate</code> rule enforcement on idle servers.<br>
+server must have to enable this feature (used to disable the 
+<code>QS_SrvMinDataRate</code> rule enforcement on idle servers).<br>
 This directives must only be used in the global server context.
 </li>
 <li>
@@ -1796,7 +1807,7 @@
 </li>
 <li>
 Throttling the download bandwidth: 
-mod_qos does not support bandwith limitation on a per connection 
+mod_qos does not support bandwidth limitation on a per connection 
 basis but you might use the <code>RATE_LIMIT</code> filter 
 provided by the Apache module 
 <a href="https://httpd.apache.org/docs/2.4/mod/mod_ratelimit.html";>mod_ratelimit <img src="images/link.png"/></a> 
@@ -1808,8 +1819,9 @@
 <tr><td bgcolor="#E2EDE2">
 Sample configuration:<br>
 <pre>
-# minimum request rate (bytes/sec at request reading):
-<a href="#QS_SrvRequestRate">QS_SrvRequestRate</a>                                 120
+# minimum data rate (bytes/sec) when the server
+# has 150 or more open TCP connections:
+<a href="#QS_SrvMinDataRate">QS_SrvMinDataRate</a>                                 64 256 150
 
 # limits the connections for this virtual host:
 <a href="#QS_SrvMaxConn">QS_SrvMaxConn</a>                                     800
@@ -1860,7 +1872,7 @@
 <syntax>QS_ClientEventPerSecLimit &lt;number&gt;</syntax><br>
 Defines how often a client may cause a 
 <code><a href="#QS_Event">QS_Event</a></code> 
-per second. Such events are requests having the 
+<a href="glossary.html#requestPerSecond">per second</a>. Such events are requests having the 
 <code><a href="#QS_Event">QS_Event</a></code> variable set, e.g., defined by 
 using the <code><a href="http://httpd.apache.org/docs/current/mod/mod_setenvif.html#setenvif";>SetEnvIf <img src="images/link.png"/></a></code> directive. 
 The rule is enforced by adding a delay to requests causing 
@@ -1907,9 +1919,11 @@
 request header (e.g., X-Forwarded-For) instead of taking the IP address 
 of the client which has opened the TCP connection. The header must only 
 contain a single IP address.<br>
-You might even use the <a href="http://modsetenvifplus.sourceforge.net/#SetHashHeaderPlus";><code>SetHashHeaderPlus</code> <img src="images/link.png"/></a> 
-directive to create a hash representing a client using arbitrary HTTP 
-request attributes.
+You might also use a pseudo IP address by creating a hash from the 
+header's value if you prefix the header name by a '#', 
+e.g. <code>#Authorization</code> to use the HTTP basic auth header. 
+as the pseudo IP address. The special name <code>#SSL_CLIENT_S_DN</code> 
+creates a pseudo IP from the SSL client certificate's subject and issuer DN.
 </li>
 <li>The current value of this counter is stored within the variable suffixed 
 by <code><a href="#_Counter">_Counter</a></code>, e.g. <code>QS_Limit_Counter</code> for further 
@@ -1936,7 +1950,7 @@
 <syntax>QS_ClientSerialize</syntax><br>
 <a href="glossary.html#serialization">Serializes</a> requests having the
 <a href="#QS_Serialize"><code>QS_Serialize</code></a> 
-variable set if they are comming from the same IP address.<br>
+variable set if they are coming from the same IP address.<br>
 <small><i>Notes:
 <ul>
 <li>You may use the <code>QS_ClientIpFromHeader &lt;header&gt;</code> directive to 
@@ -1962,7 +1976,7 @@
 <code><a href="#QS_VipIPHeaderName">QS_VipIPHeaderName</a></code> 
 directive in order to identify <a href="#privilegedusers">VIP</a> clients.<br>
 The distinction between high and low priority clients is made
-based on penality points which are calculated based of these attributes:
+based on penalty points which are calculated based of these attributes:
 <ul>
 <li>Data transfer behavior (clients sending data slowly / their transfer rate) (0x01).</li>
 <li>Accessing "unusual" content types (see <code><a href="#QS_ClientTolerance">QS_ClientTolerance</a></code> 
@@ -1991,7 +2005,7 @@
 <li>
 <a name="QS_ClientContentTypes"></a>
 <syntax>QS_ClientContentTypes &lt;html&gt; &lt;css/js&gt; &lt;images&gt; &lt;other&gt; &lt;304&gt;</syntax><br>
-Defines the distribution of HTTP response content types a client normaly 
+Defines the distribution of HTTP response content types a client normally 
 receives when accessing the server. Can only be used in conjunction with the 
 <code><a href="#QS_ClientPrefer">QS_ClientPrefer</a></code> directive. 
 <code><a href="#QS_ClientTolerance">QS_ClientTolerance</a></code> defines 
@@ -2026,15 +2040,18 @@
 <small><i>Note: You may use the <code>QS_ClientIpFromHeader &lt;header&gt;</code> directive to 
 override the client's IP address based on the value within the defined HTTP request 
 header (e.g., X-Forwarded-For) instead of taking the IP address of the client which has opened 
-the TCP connection.</i></small>
-
+the TCP connection to evaluate this variable.</i></small>
 </li>
 <li>
 <a name="QS_ClientGeoCountryPriv"></a>
-<syntax>QS_ClientGeoCountryPriv &lt;list&gt; &lt;connections&gt;</syntax><br>
+<syntax>QS_ClientGeoCountryPriv &lt;list&gt; &lt;connections&gt; ['excludeUnknown']</syntax><br>
 Defines a comma separated list of country codes for origin client IPv4 address 
 which are allowed to access the server even if the number of busy TCP 
-connections reaches the defined number of connections.
+connections reaches the defined number of connections.<br>
+Uses the geographical database loaded by 
+<a href="#QS_ClientGeoCountryDB"><code>QS_ClientGeoCountryDB</code></a>.
+<br>Clients whose IP can't be mapped to a country code can be excluded 
+from the limitation by configuring the 'excludeUnknown' argument.
 </li>
 </ul>
 
@@ -2138,7 +2155,7 @@
 <a href="https://httpd.apache.org/docs/current/mod/mod_unique_id.html";>mod_unique_id <img src="images/link.png"/></a>. 
 This unique identifier is stored as a cookie. The user tracking 
 feature is enabled by setting the 
-<code>QS_UserTrackingCookieName &lt;name&gt; [&lt;path&gt;] [&lt;domain&gt;] ['session']</code> 
+<code>QS_UserTrackingCookieName &lt;name&gt; [&lt;path&gt;] [&lt;domain&gt;] ['session'] ['jsredirect']</code> 
 directive.<br>
 Options of the <code>QS_UserTrackingCookieName</code> directive are:
 <ul>
@@ -2156,28 +2173,28 @@
 <li><code>domain</code> defines optionally the domain attribute for 
 the Set-Cookie header.</li>
 <li>The <code>session</code> flag indicates that a short lived (per 
-session) cookie shall be creaed which won't be stored by the browser 
+session) cookie shall be created which won't be stored by the browser 
 permanently.</li>
-</ul>
-<small><i>
-Notes:
-<ul>
-<li><code>QS_UserTrackingCookieName</code> ignores the 
-<code><a href="#QS_LogOnly">QS_LogOnly</a></code> 
-directive.</li>
-<li>The cookie is secured by the <code><a href="#QS_SessionKey">QS_SessionKey</a></code> 
-and you should set this directive to have a constant key.</li>
 <li>When using the additional option <code>'jsredirect'</code>, 
 the client (browser) has to interpret Javascript used within the 
 <a href="http://mod-qos.sourceforge.net/cookie-ir.shtml";>cookie check page</a> 
 to fetch the cookie and to execute the redirect back to the initially 
 requested page (adding Javascript to the cookie challenge).<br>
 The following <a href="glossary.html#ssi">SSI variables</a> can be used:<ul>
-<li><code>QS_UT_QUERY<code>: Query string to call (ajax) the cookie 
+<li><code>QS_UT_QUERY</code>: Query string to call (ajax) the cookie 
 page again to obtain the cookie.</li>
 <li><code>QS_UT_NAME</code>: Name of the cookie.</li>
-<li><code>QS_UT_INITIAL_URI</code>: Inital page to redirect to.</li>
+<li><code>QS_UT_INITIAL_URI</code>: Initial page to redirect to.</li>
+</ul>
 </ul>
+<small><i>
+Notes:
+<ul>
+<li><code>QS_UserTrackingCookieName</code> ignores the 
+<code><a href="#QS_LogOnly">QS_LogOnly</a></code> 
+directive.</li>
+<li>The cookie is secured by the <code><a href="#QS_SessionKey">QS_SessionKey</a></code> 
+and you should set this directive to have a constant key.</li>
 </ul>
 </li>
 </i></small>
@@ -2191,7 +2208,7 @@
 </li>
 <li>
 <a name="QS_ConnectionId"></a>
-<syntax>QS_ConnectionId</syntax> <br> Connecton correlation id used to 
+<syntax>QS_ConnectionId</syntax> <br> Connection correlation id used to 
 mark all messages belonging to the same TCP connection.
 </li>
 </ul>
@@ -2232,7 +2249,7 @@
 Instead of using the standard Apache log <code>CustomLog</code> directive, 
 you may use the <code>QSLog</code> directive of mod_qos alternatively. This
 allows you to configure a single log file for your Apache instance (globally, 
-not per virtal host) and you don't have to specify the format (-f) option.
+not per virtual host) and you don't have to specify the format (-f) option.
 <table border="0" cellspacing="5" cellpadding="10" width="100%">
 <tr><td bgcolor="#E2EDE2">
 <pre>
@@ -2273,13 +2290,13 @@
 <a href="http://httpd.apache.org/docs/current/mod/mod_status.html";>mod_status <img src="images/link.png"/></a> 
 (although in a reduced scope).<br>
 <small><i>Note: Compile mod_qos with the preprocessor definition 
-<code>-DQS_NO_STATUS_HOOK</code> to disable its regisration to 
+<code>-DQS_NO_STATUS_HOOK</code> to disable its registration to 
 the status page rendered by mod_status.</i></small>
 </p>
 <p>
 <a name="QS_DisableHandler"></a>
 Use the directive <code>QS_DisableHandler on</code> to disable the qos-viewer and qos-console for 
-a virtual host in order to prevent accidental activation of these functions, includng by configuration 
+a virtual host in order to prevent accidental activation of these functions, including by configuration 
 settings of per-directory files (e.g., .htaccess).
 </p>
 <p>
@@ -2430,7 +2447,7 @@
 <a name="qssign"></a>
 <li><syntax><a href="qssign.1.html">qssign</a></syntax><br>A log data integrity 
 check tool. It reads log data from stdin (pipe) and writes the signed data 
-to stdout adding a sequence number and signatur to ever log line.<br>
+to stdout adding a sequence number and signature to ever log line.<br>
 <a href="https://sourceforge.net/p/mod-qos/source/HEAD/tree/trunk/tools/logstash-filter-qssign/lib/logstash/filters/qssign.rb?format=raw";><code>qssign.rb</code></a> is a <a href="http://www.logstash.net/";>Logstash <img src="images/link.png"/></a> filter 
 plugin which may be used to verify the signatures of log messages in real time.</li>
 <a name="qstail"></a>
@@ -2473,7 +2490,7 @@
 </td></tr>
 </table>
 The <code><a href="qslog.1.html">qslog</a></code> tool may be used 
-to analyze your log files in order to idenitify "slow" resources by 
+to analyze your log files in order to identify "slow" resources by 
 using the <code>-pu</code>, <code>-puc</code>, or <code>-c</code> option.
 </p>
 
@@ -2509,7 +2526,7 @@
 download different content from the web server. So the client gets many 
 connections while other users may not be able to access the server because
 no free connections remain for them. mod_qos can limit the number 
-of concurrent connections for a singe IP source address. 
+of concurrent connections for a single IP source address. 
 <br><br>Example:<br>
 <table border="0" cellspacing="5" cellpadding="10" width="100%">
 <tr><td bgcolor="#E2EDE2">
@@ -2533,7 +2550,7 @@
 If you have to limit the number of requests to an URL, mod_qos can help 
 with that, too. You may limit the number of requests per second to 
 an URL. mod_qos will then calculate the necessary delay time to be added 
-to each requests accessing this resource in order to achive the defined 
+to each requests accessing this resource in order to achieve the defined 
 limitation. 
 <br><br>Example:<br>
 <table border="0" cellspacing="5" cellpadding="10" width="100%">
@@ -2550,11 +2567,11 @@
 </p>
 <a name="Many_Requests_to_a_Single_URL_SLOW"></a>
 <p>
-Alernatively, if you need to reduce the number of processed requests 
-per time to a very low value, you might add a constant delay to 
-each request and process only one of them at the same time. However, 
-this will delay ever request to the defined URI, even the server 
-is idle.
+Alternatively, if you need to reduce the number of processed requests 
+per time to a very low value, you might add a (predefined or 
+dynamically calculated) delay to each request and process only 
+one of them at the same time. However, this will delay every 
+request to the defined URI, even the server is idle.
 <br><br>Example:<br>
 <table border="0" cellspacing="5" cellpadding="10" width="100%">
 <tr><td bgcolor="#E2EDE2">
@@ -2635,7 +2652,7 @@
 <table border="0" cellspacing="5" cellpadding="10" width="100%">
 <tr><td bgcolor="#E2EDE2">
 <pre>
-# allows a single IP addess to access the URI /wp-login.php not more
+# allows a single IP address to access the URI /wp-login.php not more
 # than 10 times within an hour:
 SetEnvIf                 Request_URI ^/wp-login.php LimitLogin
 <a href="#QS_ClientEventLimitCount">QS_ClientEventLimitCount</a> 10 3600 LimitLogin
@@ -2729,6 +2746,6 @@
 </table>
 <br>
 <hr>
-<small><small>&copy; 2007-2019, Pascal Buchbinder - mod_qos version 11.63</small></small>
+<small><small>&copy; 2007-2023, Pascal Buchbinder - mod_qos version 11.74</small></small>
 </body>
 </html>
diff -Nru libapache2-mod-qos-11.63/doc/MESSAGES.txt libapache2-mod-qos-11.74/doc/MESSAGES.txt
--- libapache2-mod-qos-11.63/doc/MESSAGES.txt	2019-05-25 09:08:59.000000000 -0400
+++ libapache2-mod-qos-11.74/doc/MESSAGES.txt	2023-05-18 08:34:25.000000000 -0400
@@ -1,4 +1,4 @@
-mod_qos version 11.63
+mod_qos version 11.74
 mod_qos(001): QS_ClientEventLimitCount directives can't be added/removed by graceful restart. A server restart is required to apply the new configuration!
 mod_qos(002): failed to create shared memory (ACT)(%s): %s (%lu bytes)
 mod_qos(002): failed to create shared memory (client control)(%s): %s (%d bytes)
@@ -7,15 +7,16 @@
 mod_qos(004): failed to create mutex (client control)(%s): %s
 mod_qos(006): could not compile request header filter rules: %s
 mod_qos(006): could not compile response header filter rules: %s
-mod_qos(007): calculated MaxClients/MaxRequestWorkers (max connections): %d, applied limit: %d
+mod_qos(007): calculated MaxClients/MaxRequestWorkers (max connections): %d, applied limit: %d (QS_MaxClients)
 mod_qos(008): could not create supervisor thread (%s), disable request rate enforcement
+mod_qos(009): could not retrieve mod_ssl functions
 mod_qos(009): failed to initialize the qslog facility '%s'
 mod_qos(009): found default error document '%s'. Use the QS_ErrorPage directive to override this default page.
-mod_qos(009): loaded MPM is '%s' but mod_qos should be used with MPM 'Worker' only.
+mod_qos(009): loaded MPM is '%s' but mod_qos should be used with MPM 'Worker' or 'Event' only.
 mod_qos(009): mod_parp not available (required by some directives)
 mod_qos(009): mod_unique_id not available (mod_qos generates simple request id if required)
 mod_qos(009): running in 'log only' mode - rules are NOT enforced!
-mod_qos(009): server version is %d.%d but mod_qos should be used with Apache 2.2 or 2.4 only.
+mod_qos(009): server version is %d.%d but mod_qos should be used with Apache 2.4 only.
 mod_qos(010): access denied%s, QS_LocRequestLimit* rule: %s(%d), concurrent requests=%d, c=%s, id=%s
 mod_qos(011): access denied, QS_CondLocRequestLimitMatch rule: %s(%d), concurrent requests=%d, c=%s, id=%s
 mod_qos(012): access denied%s, QS_EventRequestLimit rule: %s(%d), concurrent requests=%d, c=%s, id=%s
@@ -29,8 +30,8 @@
 mod_qos(031): access denied%s, QS_SrvMaxConnPerIP rule: max=%d, concurrent connections=%d, message repeated %d times, c=%s
 mod_qos(034): %s, QS_SrvMinDataRate rule (enforce keep-alive), c=%s
 mod_qos(034): %s, QS_SrvMinDataRate rule (%s%s): min=%d, this connection=%d, c=%s
-mod_qos(035): QS_SrvMaxConn: no free IP slot available! Check log for unclean child exit and consider to do a graceful server restart if this condition persists.
-mod_qos(036): QS_SrvMinDataRate: unexpected connection status! connections=%d, cal. request rate=%d, max. limit=%d. Check log for unclean child exit and consider to do a graceful server restart if this condition persists.
+mod_qos(035): QS_SrvMaxConn: no free IP slot available! Check log for unclean child exit and consider to do a graceful server restart if this condition persists. You might also increase the number of supported connections using the 'QS_MaxClients' directive.
+mod_qos(036): QS_SrvMinDataRate: unexpected connection status! connections=%d, cal. request rate=%d, max. limit=%d. Check log for unclean child exit and consider to do a graceful server restart if this condition persists. You might also increase the number of supported connections using the 'QS_MaxClients' directive.
 mod_qos(037): loaded MPM is 'event' and the QS_KeepAliveTimeout/QS_MaxKeepAliveRequests directives can't be used.
 mod_qos(038): DSCP, failed to set socket options, QS_Set_DSCP=%s, socket=%s, rc=%d, id=%s
 mod_qos(040): access denied, %s rule id: %s (%s), action=%s, c=%s, id=%s
@@ -46,15 +47,15 @@
 mod_qos(049): redirect to %s, var=%s, action=%s, c=%s, id=%s
 mod_qos(050): request rate limit, rule: %s(%ld), req/sec=%ld, delay=%dms%s
 mod_qos(051): request rate limit, rule: %s(%ld), req/sec=%ld, delay=%dms
-mod_qos(060): access denied (previously), QS_ClientEventBlockCount rule: max=%d, current=%d, message repeated %d times, c=%s
-mod_qos(060): access denied, QS_ClientEventBlockCount rule: max=%d, current=%d, age=%ld, c=%s
-mod_qos(060): access denied, QS_ClientEventBlockCount rule: max=%d, current=%d, message repeated %d times, c=%s
-mod_qos(060): access denied%s, QS_ClientEventBlockCount rule: max=%d, current=%d, age=%ld, c=%s
+mod_qos(060): access denied (previously), QS_ClientEventBlockCount rule: max=%d, current=%hu, message repeated %d times, c=%s
+mod_qos(060): access denied, QS_ClientEventBlockCount rule: max=%d, current=%hu, age=%ld, c=%s
+mod_qos(060): access denied, QS_ClientEventBlockCount rule: max=%d, current=%hu, message repeated %d times, c=%s
+mod_qos(060): access denied%s, QS_ClientEventBlockCount rule: max=%d, current=%hu, age=%ld, c=%s
 mod_qos(061): request rate limit, rule: QS_Event(%d), req/sec=%ld, delay=%dms%s
 mod_qos(062): request rate limit, rule: QS_Event(%d), req/sec=%ld, delay=%dms
 mod_qos(065): access denied%s, QS_ClientEventRequestLimit rule: max=%d, current=%d, c=%s, id=%s
 mod_qos(066): access denied%s, QS_ClientPrefer rule (penalty=%d 0x%02x): max=%d, concurrent connections=%d, c=%s
-mod_qos(067): access denied%s, QS_%sClientEventLimitCount rule: event=%s, max=%d, current=%d, age=%ld, c=%s
+mod_qos(067): access denied%s, QS_%sClientEventLimitCount rule: event=%s, max=%hu, current=%hu, age=%ld, c=%s
 mod_qos(068): QS_ClientSerialize exceeds limit of 5 minutes, c=%s, id=%s
 mod_qos(068): QS_SrvSerialize exceeds limit of %d seconds, id=%s
 mod_qos(069): no valid IP header found (@%s): header '%s' not available, fallback to connection's IP %s, id=%s
@@ -74,4 +75,5 @@
 mod_qos(147): access denied, reached milestone '%d' (%s), earlier than expected (right after %ld instead of %d seconds), action=%s, c=%s, id=%s
 mod_qos(166): unexpected connection dispatching, skipping connection counter update for QS_ClientPrefer rule, c=%s
 mod_qos(167): closing connection at process connection hook, c=%s
-mod_qos(200): { "scoreboard": { "open": %d, "waiting": %d, "read": %d, "write": %d, "keepalive": %d, "start": %d, "log": %d, "dns": %d, "closing": %d, "finishing": %d, "idle": %d }, "maxclients": { "max": %d, "busy": %d }%s }
+mod_qos(200): { "scoreboard": { "open": %d, "waiting": %d, "read": %d, "write": %d, "keepalive": %d, "start": %d, "log": %d, "dns": %d, "closing": %d, "finishing": %d, "idle": %d }, "maxclients": { "max": %d, "busy": %d%s }%s }
+mod_qos(210): ENV %s %s %s
diff -Nru libapache2-mod-qos-11.63/doc/qsdt.1.html libapache2-mod-qos-11.74/doc/qsdt.1.html
--- libapache2-mod-qos-11.63/doc/qsdt.1.html	2019-05-25 09:08:59.000000000 -0400
+++ libapache2-mod-qos-11.74/doc/qsdt.1.html	2023-05-18 08:34:25.000000000 -0400
@@ -5,7 +5,7 @@
 <META name='author' content='Pascal Buchbinder' />
 </HEAD><BODY>
 <H1>QSDT</H1>
-Section: qsdt man page (1)<BR>Updated: May 2019<BR><A HREF="#index">Index</A>
+Section: qsdt man page (1)<BR>Updated: May 2023<BR><A HREF="#index">Index</A>
 <A HREF="index.html#utilities">Return to Main Contents</A><HR>
 
 <P>
diff -Nru libapache2-mod-qos-11.63/doc/qsexec.1.html libapache2-mod-qos-11.74/doc/qsexec.1.html
--- libapache2-mod-qos-11.63/doc/qsexec.1.html	2019-05-25 09:08:59.000000000 -0400
+++ libapache2-mod-qos-11.74/doc/qsexec.1.html	2023-05-18 08:34:25.000000000 -0400
@@ -5,7 +5,7 @@
 <META name='author' content='Pascal Buchbinder' />
 </HEAD><BODY>
 <H1>QSEXEC</H1>
-Section: qsexec man page (1)<BR>Updated: May 2019<BR><A HREF="#index">Index</A>
+Section: qsexec man page (1)<BR>Updated: May 2023<BR><A HREF="#index">Index</A>
 <A HREF="index.html#utilities">Return to Main Contents</A><HR>
 
 <P>
@@ -27,7 +27,7 @@
 
 <DL COMPACT>
 <DT>-e &lt;pattern&gt; <DD>
-Specifes the search pattern causing an event which shall trigger the command. 
+Specifies the search pattern causing an event which shall trigger the command. 
 <DT>-t &lt;number&gt;:&lt;sec&gt; <DD>
 Defines the number of pattern match within the the defined number of seconds in order to trigger the command execution. By default, every pattern match causes a command execution. 
 <DT>-c &lt;pattern&gt; [&lt;command string&gt;] <DD>
diff -Nru libapache2-mod-qos-11.63/doc/qsfilter2.1.html libapache2-mod-qos-11.74/doc/qsfilter2.1.html
--- libapache2-mod-qos-11.63/doc/qsfilter2.1.html	2019-05-25 09:08:59.000000000 -0400
+++ libapache2-mod-qos-11.74/doc/qsfilter2.1.html	2023-05-18 08:34:25.000000000 -0400
@@ -5,7 +5,7 @@
 <META name='author' content='Pascal Buchbinder' />
 </HEAD><BODY>
 <H1>QSFILTER2</H1>
-Section: qsfilter2 man page (1)<BR>Updated: May 2019<BR><A HREF="#index">Index</A>
+Section: qsfilter2 man page (1)<BR>Updated: May 2023<BR><A HREF="#index">Index</A>
 <A HREF="index.html#utilities">Return to Main Contents</A><HR>
 
 <P>
@@ -20,7 +20,7 @@
 <A NAME="lbAD">&nbsp;</A>
 <H2>DESCRIPTION</H2><p><img src="qsfilter2_process.gif" alt="overview"></p>
 
-mod_qos implements a request filter which validates each request line. The module supports both, negative and positive security model. The QS_Deny* directives are used to specify request line patterns which are not allowed to access the server (negative security model / blacklist). These rules are used to restrict access to certain resources which should not be available to users or to protect the server from malicious patterns. The QS_Permit* rules implement a positive security model (whitelist). These directives are used to define allowed request line patterns. Request which do not match any of thses patterns are not allowed to access the server. 
+mod_qos implements a request filter which validates each request line. The module supports both, negative and positive security model. The QS_Deny* directives are used to specify request line patterns which are not allowed to access the server (negative security model / deny list). These rules are used to restrict access to certain resources which should not be available to users or to protect the server from malicious patterns. The QS_Permit* rules implement a positive security model (allow list). These directives are used to define allowed request line patterns. Request which do not match any of these patterns are not allowed to access the server. 
 <P>
 qsfilter2 is an audit log analyzer used to generate filter rules (perl compatible regular expressions) which may be used by mod_qos to deny access for suspect requests (QS_PermitUri rules). It parses existing audit log files in order to generate request patterns covering all allowed requests. 
 <A NAME="lbAE">&nbsp;</A>
@@ -28,7 +28,7 @@
 
 <DL COMPACT>
 <DT>-i &lt;path&gt; <DD>
-Input file containing request URIs. The URIs for this file have to be extracted from the servers access logs. Each line of the input file contains a request URI consiting of a path and and query. 
+Input file containing request URIs. The URIs for this file have to be extracted from the servers access logs. Each line of the input file contains a request URI consisting of a path and and query. 
 <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Example:
 <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/aaa/index.do
 <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/aaa/edit?image=1.jpg
@@ -38,9 +38,9 @@
 <P>
 These access log data must include current request URIs but also request lines from previous rule generation steps. It must also include request lines which cover manually generated rules. You may use the 'qos-path' and 'qos-query' variables to create an audit log containing all request data (path and query/body data). Example: 'CustomLog audit_log %{qos-path}n%{qos-query}n'. See also <A HREF="http://mod-qos.sourceforge.net#qsfiltersample";>http://mod-qos.sourceforge.net#qsfiltersample</A> about the module settings. 
 <DT>-c &lt;path&gt; <DD>
-mod_qos configuration file defining QS_DenyRequestLine and QS_PermitUri directives. qsfilter2 generates rules from access log data automatically. Manually generated rules (QS_PermitUri) may be provided from this file. Note: each manual rule must be represented by a request URI in the input data (-i) in order to make sure not to be deleted by the rule optimisation algorithm. QS_Deny* rules from this file are used to filter request lines which should not be used for whitelist rule generation. 
+mod_qos configuration file defining QS_DenyRequestLine and QS_PermitUri directives. qsfilter2 generates rules from access log data automatically. Manually generated rules (QS_PermitUri) may be provided from this file. Note: each manual rule must be represented by a request URI in the input data (-i) in order to make sure not to be deleted by the rule optimisation algorithm. QS_Deny* rules from this file are used to filter request lines which should not be used for allow list rule generation. 
 <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Example:
-<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#&nbsp;manually&nbsp;defined&nbsp;whitelist&nbsp;rule:
+<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#&nbsp;manually&nbsp;defined&nbsp;allow&nbsp;list&nbsp;rule:
 <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;QS_PermitUri&nbsp;+view&nbsp;deny&nbsp;&quot;^[/a-zA-Z0-9]+/view\?(page=[0-9]+)?$&quot;
 <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#&nbsp;filter&nbsp;unwanted&nbsp;request&nbsp;line&nbsp;patterns:
 <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;QS_DenyRequestLine&nbsp;+printable&nbsp;deny&nbsp;&quot;.*[\x00-\x19].*&quot;
@@ -53,11 +53,11 @@
 <DT>-b &lt;num&gt; <DD>
 Replaces url pattern by the regular expression when detecting a base64/hex encoded string. Detecting sensibility is defined by a numeric value. You should use values higher than 5 (default) or 0 to disable this function. 
 <DT>-p <DD>
-Repesents query by pcre only (no literal strings). 
+Represents query by pcre only (no literal strings). 
 <DT>-s <DD>
 Uses one single pcre for the whole query string. 
 <DT>-m <DD>
-Uses one pcre for multipe query values (recommended mode). 
+Uses one pcre for multiple query values (recommended mode). 
 <DT>-o <DD>
 Does not care the order of query parameters. 
 <DT>-l &lt;len&gt; <DD>
diff -Nru libapache2-mod-qos-11.63/doc/qsgeo.1.html libapache2-mod-qos-11.74/doc/qsgeo.1.html
--- libapache2-mod-qos-11.63/doc/qsgeo.1.html	2019-05-25 09:08:59.000000000 -0400
+++ libapache2-mod-qos-11.74/doc/qsgeo.1.html	2023-05-18 08:34:25.000000000 -0400
@@ -5,7 +5,7 @@
 <META name='author' content='Pascal Buchbinder' />
 </HEAD><BODY>
 <H1>QSGEO</H1>
-Section: qsgeo man page (1)<BR>Updated: May 2019<BR><A HREF="#index">Index</A>
+Section: qsgeo man page (1)<BR>Updated: May 2023<BR><A HREF="#index">Index</A>
 <A HREF="index.html#utilities">Return to Main Contents</A><HR>
 
 <P>
diff -Nru libapache2-mod-qos-11.63/doc/qsgrep.1.html libapache2-mod-qos-11.74/doc/qsgrep.1.html
--- libapache2-mod-qos-11.63/doc/qsgrep.1.html	2019-05-25 09:08:59.000000000 -0400
+++ libapache2-mod-qos-11.74/doc/qsgrep.1.html	2023-05-18 08:34:25.000000000 -0400
@@ -5,7 +5,7 @@
 <META name='author' content='Pascal Buchbinder' />
 </HEAD><BODY>
 <H1>QSGREP</H1>
-Section: qsgrep man page (1)<BR>Updated: May 2019<BR><A HREF="#index">Index</A>
+Section: qsgrep man page (1)<BR>Updated: May 2023<BR><A HREF="#index">Index</A>
 <A HREF="index.html#utilities">Return to Main Contents</A><HR>
 
 <P>
@@ -26,7 +26,7 @@
 
 <DL COMPACT>
 <DT>-e &lt;pattern&gt; <DD>
-Specifes the search pattern. 
+Specifies the search pattern. 
 <DT>-o &lt;string&gt; <DD>
 Defines the output string where $0-$9 are substituted by the submatches of the regular expression. 
 <DT>&lt;path&gt; <DD>
diff -Nru libapache2-mod-qos-11.63/doc/qshead.1.html libapache2-mod-qos-11.74/doc/qshead.1.html
--- libapache2-mod-qos-11.63/doc/qshead.1.html	2019-05-25 09:08:59.000000000 -0400
+++ libapache2-mod-qos-11.74/doc/qshead.1.html	2023-05-18 08:34:25.000000000 -0400
@@ -5,7 +5,7 @@
 <META name='author' content='Pascal Buchbinder' />
 </HEAD><BODY>
 <H1>QSHEAD</H1>
-Section: qshead man page (1)<BR>Updated: May 2019<BR><A HREF="#index">Index</A>
+Section: qshead man page (1)<BR>Updated: May 2023<BR><A HREF="#index">Index</A>
 <A HREF="index.html#utilities">Return to Main Contents</A><HR>
 
 <P>
@@ -20,7 +20,7 @@
 <A NAME="lbAD">&nbsp;</A>
 <H2>DESCRIPTION</H2>
 
-qshead reads lines from stdin and prints them to stdout unitl a line contains the specified pattern (literal string). 
+qshead reads lines from stdin and prints them to stdout until a line contains the specified pattern (literal string). 
 <A NAME="lbAE">&nbsp;</A>
 <H2>OPTIONS</H2>
 
diff -Nru libapache2-mod-qos-11.63/doc/qslog.1.html libapache2-mod-qos-11.74/doc/qslog.1.html
--- libapache2-mod-qos-11.63/doc/qslog.1.html	2019-05-25 09:08:59.000000000 -0400
+++ libapache2-mod-qos-11.74/doc/qslog.1.html	2023-05-18 08:34:25.000000000 -0400
@@ -5,7 +5,7 @@
 <META name='author' content='Pascal Buchbinder' />
 </HEAD><BODY>
 <H1>QSLOG</H1>
-Section: qslog man page (1)<BR>Updated: May 2019<BR><A HREF="#index">Index</A>
+Section: qslog man page (1)<BR>Updated: May 2023<BR><A HREF="#index">Index</A>
 <A HREF="index.html#utilities">Return to Main Contents</A><HR>
 
 <P>
@@ -25,7 +25,7 @@
 <BR>&nbsp;&nbsp;-&nbsp;number&nbsp;of&nbsp;requests&nbsp;within&nbsp;measured&nbsp;time&nbsp;(req)
 <BR>&nbsp;&nbsp;-&nbsp;bytes&nbsp;sent&nbsp;to&nbsp;the&nbsp;client&nbsp;per&nbsp;second&nbsp;(b/s)
 <BR>&nbsp;&nbsp;-&nbsp;bytes&nbsp;received&nbsp;from&nbsp;the&nbsp;client&nbsp;per&nbsp;second&nbsp;(ib/s)
-<BR>&nbsp;&nbsp;-&nbsp;repsonse&nbsp;status&nbsp;codes&nbsp;within&nbsp;the&nbsp;last&nbsp;minute&nbsp;(1xx,2xx,3xx,4xx,5xx)
+<BR>&nbsp;&nbsp;-&nbsp;response&nbsp;status&nbsp;codes&nbsp;within&nbsp;the&nbsp;last&nbsp;minute&nbsp;(1xx,2xx,3xx,4xx,5xx)
 <BR>&nbsp;&nbsp;-&nbsp;average&nbsp;response&nbsp;duration&nbsp;(av)
 <BR>&nbsp;&nbsp;-&nbsp;average&nbsp;response&nbsp;duration&nbsp;in&nbsp;milliseconds&nbsp;(avms)
 <BR>&nbsp;&nbsp;-&nbsp;distribution&nbsp;of&nbsp;response&nbsp;durations&nbsp;in&nbsp;seconds&nbsp;within&nbsp;the&nbsp;last&nbsp;minute
@@ -45,7 +45,7 @@
 
 <DL COMPACT>
 <DT>-f &lt;format_string&gt; <DD>
-Defines the log data format and the positions of data elements processed by this utility. See to the 'LogFormat' directive of the httpd.conf file to see the format defintions of the servers access log data. 
+Defines the log data format and the positions of data elements processed by this utility. See to the 'LogFormat' directive of the httpd.conf file to see the format definitions of the servers access log data. 
 <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;qslog&nbsp;knows&nbsp;the&nbsp;following&nbsp;elements:
 <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;I&nbsp;defines&nbsp;the&nbsp;client&nbsp;ip&nbsp;address&nbsp;(%h)
 <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;R&nbsp;defines&nbsp;the&nbsp;request&nbsp;line&nbsp;(%r)
@@ -81,7 +81,7 @@
 <DT>-m <DD>
 Calculates free system memory every minute. 
 <DT>-c &lt;path&gt; <DD>
-Enables the collection of log statitics for different request types. 'path' specifies the necessary rule file. Each rule consists of a rule identifier and a regular expression to identify a request seprarated by a colon, e.g., 01:^(/a)|(/c). The regular expressions are matched against the log data element which has been identified by the 'C' format character. 
+Enables the collection of log statistics for different request types. 'path' specifies the necessary rule file. Each rule consists of a rule identifier and a regular expression to identify a request seprarated by a colon, e.g., 01:^(/a)|(/c). The regular expressions are matched against the log data element which has been identified by the 'C' format character. 
 </DL>
 <A NAME="lbAF">&nbsp;</A>
 <H2>VARIABLES</H2>
diff -Nru libapache2-mod-qos-11.63/doc/qslogger.1.html libapache2-mod-qos-11.74/doc/qslogger.1.html
--- libapache2-mod-qos-11.63/doc/qslogger.1.html	2019-05-25 09:08:59.000000000 -0400
+++ libapache2-mod-qos-11.74/doc/qslogger.1.html	2023-05-18 08:34:25.000000000 -0400
@@ -5,7 +5,7 @@
 <META name='author' content='Pascal Buchbinder' />
 </HEAD><BODY>
 <H1>QSLOGGER</H1>
-Section: qslogger man page (1)<BR>Updated: May 2019<BR><A HREF="#index">Index</A>
+Section: qslogger man page (1)<BR>Updated: May 2023<BR><A HREF="#index">Index</A>
 <A HREF="index.html#utilities">Return to Main Contents</A><HR>
 
 <P>
@@ -33,13 +33,13 @@
 <DT>-u &lt;name&gt; <DD>
 Becomes another user, e.g. www-data. 
 <DT>-l &lt;level&gt; <DD>
-Defines the minimal severity a message must have in order to be forwarded. Default is 'DEBUG' (fowarding everything). 
+Defines the minimal severity a message must have in order to be forwarded. Default is 'DEBUG' (forwarding everything). 
 <DT>-x &lt;prefix&gt; <DD>
 Allows you to add a prefix (literal string) to every message. 
 <DT>-r &lt;expression&gt; <DD>
 Specifies a regular expression which shall be used to determine the severity (syslog level) for each log line. The default pattern '^\[[0-9a-zA-Z :]+\] \[([a-z]+)\] ' can be used for Apache error log messages but you may configure your own pattern matching other log formats. Use brackets to define the pattern enclosing the severity string. Default level (if severity can't be determined) is defined by the option '-d' (see below). 
 <DT>-d &lt;level&gt; <DD>
-The default severity if the specified pattern (-r) does not match and the message's serverity can't be determined. Default is 'NOTICE'. 
+The default severity if the specified pattern (-r) does not match and the message's severity can't be determined. Default is 'NOTICE'. 
 <DT>-p <DD>
 Writes data also to stdout (for piped logging). 
 </DL>
diff -Nru libapache2-mod-qos-11.63/doc/qspng.1.html libapache2-mod-qos-11.74/doc/qspng.1.html
--- libapache2-mod-qos-11.63/doc/qspng.1.html	2019-05-25 09:08:59.000000000 -0400
+++ libapache2-mod-qos-11.74/doc/qspng.1.html	2023-05-18 08:34:25.000000000 -0400
@@ -5,7 +5,7 @@
 <META name='author' content='Pascal Buchbinder' />
 </HEAD><BODY>
 <H1>QSPNG</H1>
-Section: qspng man page (1)<BR>Updated: May 2019<BR><A HREF="#index">Index</A>
+Section: qspng man page (1)<BR>Updated: May 2023<BR><A HREF="#index">Index</A>
 <A HREF="index.html#utilities">Return to Main Contents</A><HR>
 
 <P>
diff -Nru libapache2-mod-qos-11.63/doc/qsre.1.html libapache2-mod-qos-11.74/doc/qsre.1.html
--- libapache2-mod-qos-11.63/doc/qsre.1.html	2019-05-25 09:08:59.000000000 -0400
+++ libapache2-mod-qos-11.74/doc/qsre.1.html	2023-05-18 08:34:25.000000000 -0400
@@ -5,7 +5,7 @@
 <META name='author' content='Pascal Buchbinder' />
 </HEAD><BODY>
 <H1>QSRE</H1>
-Section: qsre man page (1)<BR>Updated: May 2019<BR><A HREF="#index">Index</A>
+Section: qsre man page (1)<BR>Updated: May 2023<BR><A HREF="#index">Index</A>
 <A HREF="index.html#utilities">Return to Main Contents</A><HR>
 
 <P>
@@ -26,7 +26,7 @@
 
 <DL COMPACT>
 <DT>&lt;string&gt;|&lt;path&gt; <DD>
-The first argument either defines a sinlge test string of a path to a file containing either multiple test strings or a test pattern with newline characters (text). 
+The first argument either defines a single test string of a path to a file containing either multiple test strings or a test pattern with newline characters (text). 
 <DT>&lt;pcre&gt;|&lt;path&gt; <DD>
 The second argument either defines a regular expression or a path to a file containing the expression. 
 </DL>
diff -Nru libapache2-mod-qos-11.63/doc/qsrespeed.1.html libapache2-mod-qos-11.74/doc/qsrespeed.1.html
--- libapache2-mod-qos-11.63/doc/qsrespeed.1.html	2019-05-25 09:08:59.000000000 -0400
+++ libapache2-mod-qos-11.74/doc/qsrespeed.1.html	2023-05-18 08:34:25.000000000 -0400
@@ -5,7 +5,7 @@
 <META name='author' content='Pascal Buchbinder' />
 </HEAD><BODY>
 <H1>QSRESPEED</H1>
-Section: qsrespeed man page (1)<BR>Updated: May 2019<BR><A HREF="#index">Index</A>
+Section: qsrespeed man page (1)<BR>Updated: May 2023<BR><A HREF="#index">Index</A>
 <A HREF="index.html#utilities">Return to Main Contents</A><HR>
 
 <P>
@@ -20,7 +20,7 @@
 <A NAME="lbAD">&nbsp;</A>
 <H2>DESCRIPTION</H2>
 
-qsrespeed loads regular expressions from the provided file and matches them against a build-in set of strings measuring the time needed to process them. It's a benchmark too to judge the expressions you have defined regarding the potential CPU consumption. 
+qsrespeed loads regular expressions from the provided file and matches them against a built-in set of strings measuring the time needed to process them. It's a benchmark too to judge the expressions you have defined regarding the potential CPU consumption. 
 <A NAME="lbAE">&nbsp;</A>
 <H2>OPTIONS</H2>
 
diff -Nru libapache2-mod-qos-11.63/doc/qsrotate.1.html libapache2-mod-qos-11.74/doc/qsrotate.1.html
--- libapache2-mod-qos-11.63/doc/qsrotate.1.html	2019-05-25 09:08:59.000000000 -0400
+++ libapache2-mod-qos-11.74/doc/qsrotate.1.html	2023-05-18 08:34:25.000000000 -0400
@@ -5,7 +5,7 @@
 <META name='author' content='Pascal Buchbinder' />
 </HEAD><BODY>
 <H1>QSROTATE</H1>
-Section: qsrotate man page (1)<BR>Updated: May 2019<BR><A HREF="#index">Index</A>
+Section: qsrotate man page (1)<BR>Updated: May 2023<BR><A HREF="#index">Index</A>
 <A HREF="index.html#utilities">Return to Main Contents</A><HR>
 
 <P>
diff -Nru libapache2-mod-qos-11.63/doc/qssign.1.html libapache2-mod-qos-11.74/doc/qssign.1.html
--- libapache2-mod-qos-11.63/doc/qssign.1.html	2019-05-25 09:08:59.000000000 -0400
+++ libapache2-mod-qos-11.74/doc/qssign.1.html	2023-05-18 08:34:25.000000000 -0400
@@ -5,7 +5,7 @@
 <META name='author' content='Pascal Buchbinder' />
 </HEAD><BODY>
 <H1>QSSIGN</H1>
-Section: qssign man page (1)<BR>Updated: May 2019<BR><A HREF="#index">Index</A>
+Section: qssign man page (1)<BR>Updated: May 2023<BR><A HREF="#index">Index</A>
 <A HREF="index.html#utilities">Return to Main Contents</A><HR>
 
 <P>
@@ -20,7 +20,7 @@
 <A NAME="lbAD">&nbsp;</A>
 <H2>DESCRIPTION</H2>
 
-qssign is a log data integrity check tool. It reads log data from stdin (pipe) and writes the data to stdout adding a sequence number and signatur to ever log line. 
+qssign is a log data integrity check tool. It reads log data from stdin (pipe) and writes the data to stdout adding a sequence number and signature to ever log line. 
 <A NAME="lbAE">&nbsp;</A>
 <H2>OPTIONS</H2>
 
@@ -38,7 +38,7 @@
 <DT>-f &lt;regex&gt; <DD>
 Filter pattern (case sensitive regular expression) for messages which do not need to be signed. 
 <DT>-a 'sha1'|'sha256' <DD>
-Specifes the algorithm to use. Default is sha1. 
+Specifies the algorithm to use. Default is sha1. 
 </DL>
 <A NAME="lbAF">&nbsp;</A>
 <H2>EXAMPLE</H2>
diff -Nru libapache2-mod-qos-11.63/doc/qstail.1.html libapache2-mod-qos-11.74/doc/qstail.1.html
--- libapache2-mod-qos-11.63/doc/qstail.1.html	2019-05-25 09:08:59.000000000 -0400
+++ libapache2-mod-qos-11.74/doc/qstail.1.html	2023-05-18 08:34:25.000000000 -0400
@@ -5,7 +5,7 @@
 <META name='author' content='Pascal Buchbinder' />
 </HEAD><BODY>
 <H1>QSTAIL</H1>
-Section: qstail man page (1)<BR>Updated: May 2019<BR><A HREF="#index">Index</A>
+Section: qstail man page (1)<BR>Updated: May 2023<BR><A HREF="#index">Index</A>
 <A HREF="index.html#utilities">Return to Main Contents</A><HR>
 
 <P>
diff -Nru libapache2-mod-qos-11.63/README.TXT libapache2-mod-qos-11.74/README.TXT
--- libapache2-mod-qos-11.63/README.TXT	2019-05-25 09:08:59.000000000 -0400
+++ libapache2-mod-qos-11.74/README.TXT	2023-05-18 08:34:25.000000000 -0400
@@ -2,7 +2,7 @@
  Quality of service module for Apache Web Server.
  http://mod-qos.sourceforge.net/
 
- Copyright (C) 2019 Pascal Buchbinder
+ Copyright (C) 2023 Pascal Buchbinder
 
  Licensed to the Apache Software Foundation (ASF) under one or more
  contributor license agreements.  See the NOTICE file distributed with
diff -Nru libapache2-mod-qos-11.63/tools/configure libapache2-mod-qos-11.74/tools/configure
--- libapache2-mod-qos-11.63/tools/configure	2019-05-25 09:08:59.000000000 -0400
+++ libapache2-mod-qos-11.74/tools/configure	2023-05-18 08:34:25.000000000 -0400
@@ -722,7 +722,7 @@
 enable_ssl
 with_apr
 with_apr_util
-with_pcre
+with_pcre2
 with_png
 with_ssl
 '
@@ -1375,7 +1375,7 @@
   --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
   --with-apr=PATH         path to apr-1-config script
   --with-apr-util=PATH    path to apu-1-config script
-  --with-pcre=PATH        path to pcre-config script
+  --with-pcre2=PATH       path to pcre2-config script
   --with-png=PATH         path to libpng-config script
   --with-ssl=PATH         path to openssl source
 
@@ -4665,11 +4665,11 @@
 fi
 
 
-# Check whether --with-pcre was given.
-if test "${with_pcre+set}" = set; then :
-  withval=$with_pcre; if test ! -x $withval/pcre-config; then as_fn_error $? "$withval/pcre-config do not exist or is not executable" "$LINENO" 5; else PCRE_CONFIG="$withval/pcre-config"; fi
+# Check whether --with-pcre2 was given.
+if test "${with_pcre2+set}" = set; then :
+  withval=$with_pcre2; if test ! -x $withval/pcre2-config; then as_fn_error $? "$withval/pcre2-config do not exist or is not executable" "$LINENO" 5; else PCRE2_CONFIG="$withval/pcre2-config"; fi
 else
-  PCRE_CONFIG="pcre-config"
+  PCRE2_CONFIG="pcre2-config"
 fi
 
 
@@ -4699,9 +4699,9 @@
   echo "libaprutil is missing, use --with-apr-util=PATH"
   exit -1
 fi
-PCRE_VERSION=`$PCRE_CONFIG --version`
+PCRE2_VERSION=`$PCRE2_CONFIG --version`
 if test ! "$?" = "0"; then
-  echo "libpcre is missing, use --with-pcre=PATH to specify the location of your pcre library"
+  echo "libpcre2 is missing, use --with-pcre2=PATH to specify the location of your pcre2 library"
   exit -1
 fi
 PNG_VERSION=`$PNG_CONFIG --version`
@@ -4712,9 +4712,9 @@
 
 # Store settings for includes, libs and flags
 INCLUDES="`$APR_CONFIG --includes` `$APU_CONFIG --includes` $OPENSSL_INCLUDES"
-CFLAGS="`$APR_CONFIG --cflags` `$PCRE_CONFIG --cflags` `$PNG_CONFIG --cflags` $CFLAGS $INCLUDES"
+CFLAGS="`$APR_CONFIG --cflags` `$PCRE2_CONFIG --cflags` `$PNG_CONFIG --cflags` $CFLAGS $INCLUDES"
 CPPFLAGS="`$APR_CONFIG --cppflags` $CPPFLAGS"
-LIBS="$OPENSSL_LIB_PATH -lssl -lcrypto `$APR_CONFIG --link-ld`  `$APU_CONFIG --link-ld` `$APR_CONFIG --libs` `$APU_CONFIG --libs` `$PCRE_CONFIG --libs` `$PNG_CONFIG --libs` -lz"
+LIBS="$OPENSSL_LIB_PATH -lssl -lcrypto `$APR_CONFIG --link-ld`  `$APU_CONFIG --link-ld` `$APR_CONFIG --libs` `$APU_CONFIG --libs` `$PCRE2_CONFIG --libs8` `$PNG_CONFIG --libs` -lz"
 
 # if link static
 if test "$enable_full_static" = "yes"; then
diff -Nru libapache2-mod-qos-11.63/tools/configure.ac libapache2-mod-qos-11.74/tools/configure.ac
--- libapache2-mod-qos-11.63/tools/configure.ac	2019-05-25 09:08:59.000000000 -0400
+++ libapache2-mod-qos-11.74/tools/configure.ac	2023-05-18 08:34:25.000000000 -0400
@@ -35,9 +35,9 @@
 AC_ARG_WITH(apr-util,AS_HELP_STRING(--with-apr-util=PATH,path to apu-1-config script),
 	[if test ! -x $withval/apu-1-config; then AC_MSG_ERROR($withval/apu-1-config do not exist or is not executable); else APU_CONFIG="$withval/apu-1-config"; fi],
 	[APU_CONFIG="apu-1-config"])
-AC_ARG_WITH(pcre,AS_HELP_STRING(--with-pcre=PATH,path to pcre-config script),
-	[if test ! -x $withval/pcre-config; then AC_MSG_ERROR($withval/pcre-config do not exist or is not executable); else PCRE_CONFIG="$withval/pcre-config"; fi],
-	[PCRE_CONFIG="pcre-config"])
+AC_ARG_WITH(pcre2,AS_HELP_STRING(--with-pcre2=PATH,path to pcre2-config script),
+	[if test ! -x $withval/pcre2-config; then AC_MSG_ERROR($withval/pcre2-config do not exist or is not executable); else PCRE2_CONFIG="$withval/pcre2-config"; fi],
+	[PCRE2_CONFIG="pcre2-config"])
 AC_ARG_WITH(png,AS_HELP_STRING(--with-png=PATH,path to libpng-config script),
 	[if test ! -x $withval/libpng-config; then AC_MSG_ERROR($withval/libpng-config do not exist or is not executable); else PNG_CONFIG="$withval/libpng-config"; fi],
 	[PNG_CONFIG="libpng-config"])
@@ -55,9 +55,9 @@
   echo "libaprutil is missing, use --with-apr-util=PATH"
   exit -1
 fi
-PCRE_VERSION=`$PCRE_CONFIG --version`
+PCRE2_VERSION=`$PCRE2_CONFIG --version`
 if test ! "$?" = "0"; then
-  echo "libpcre is missing, use --with-pcre=PATH to specify the location of your pcre library"
+  echo "libpcre2 is missing, use --with-pcre2=PATH to specify the location of your pcre2 library"
   exit -1
 fi
 PNG_VERSION=`$PNG_CONFIG --version`
@@ -68,9 +68,9 @@
 
 # Store settings for includes, libs and flags
 INCLUDES="`$APR_CONFIG --includes` `$APU_CONFIG --includes` $OPENSSL_INCLUDES"
-CFLAGS="`$APR_CONFIG --cflags` `$PCRE_CONFIG --cflags` `$PNG_CONFIG --cflags` $CFLAGS $INCLUDES"
+CFLAGS="`$APR_CONFIG --cflags` `$PCRE2_CONFIG --cflags` `$PNG_CONFIG --cflags` $CFLAGS $INCLUDES"
 CPPFLAGS="`$APR_CONFIG --cppflags` $CPPFLAGS"
-LIBS="$OPENSSL_LIB_PATH -lssl -lcrypto `$APR_CONFIG --link-ld`  `$APU_CONFIG --link-ld` `$APR_CONFIG --libs` `$APU_CONFIG --libs` `$PCRE_CONFIG --libs` `$PNG_CONFIG --libs` -lz"
+LIBS="$OPENSSL_LIB_PATH -lssl -lcrypto `$APR_CONFIG --link-ld`  `$APU_CONFIG --link-ld` `$APR_CONFIG --libs` `$APU_CONFIG --libs` `$PCRE2_CONFIG --libs8` `$PNG_CONFIG --libs` -lz"
 
 # if link static
 if test "$enable_full_static" = "yes"; then
diff -Nru libapache2-mod-qos-11.63/tools/man1/mod_qos.1 libapache2-mod-qos-11.74/tools/man1/mod_qos.1
--- libapache2-mod-qos-11.63/tools/man1/mod_qos.1	2019-05-25 09:08:59.000000000 -0400
+++ libapache2-mod-qos-11.74/tools/man1/mod_qos.1	2023-05-18 08:34:25.000000000 -0400
@@ -1,4 +1,4 @@
-.TH MOD_QOS 1 "May 2019" "mod_qos Apache Module" "mod_qos"
+.TH MOD_QOS 1 "May 2023" "mod_qos Apache Module" "mod_qos"
 .SH NAME
 mod_qos \- quality of service module for the Apache Web server
 .SH DESCRIPTION
@@ -37,7 +37,7 @@
 .TP
 QS_SrvMaxConnPerIP <number> [<connections>], defines the maximum number of connections per source IP address for this server (virtual host). 'connections' defines the number of busy connections of the server (all virtual hosts) to enable this limitation, default is 0.
 .TP
-QS_SrvMaxConnExcludeIP <addr>, excludes an IP address or address range from beeing limited.
+QS_SrvMaxConnExcludeIP <addr>, excludes an IP address or address range from being limited.
 .TP
 QS_SrvMinDataRateIgnoreVIP tells the QS_SrvMaxConnPerIP directive to ignore (if set to "on") the VIP status of clients. Default is "off", which means that QS_SrvMaxConnPerIP is disabled for VIPs.
 .TP
@@ -45,9 +45,9 @@
 .TP
 QS_SrvDataRateOff, disables the QS_SrvRequestRate and QS_SrvMinDataRate enforcement for a virtual host (only port/address based but not for name based virtual hosts).
 .TP
-QS_SrvRequestRate <bytes per seconds> [<max bytes per second>], defines the minumum upload throughput a client must generate. See also QS_SrvMinDataRate.
+QS_SrvRequestRate <bytes per seconds> [<max bytes per second>], defines the minimum upload throughput a client must generate. See also QS_SrvMinDataRate.
 .TP
-QS_SrvMinDataRate <bytes per seconds> [<max bytes per second> [<connections>]], defines the minumum upload/download throughput a client must generate (the bytes send/received by the client per seconds). This bandwidth is measured while transmitting the data (request line, header fields, request body, or response data). The client connection get closed if the client does not fulfill the required data rate and the IP address of the causing client get marked in order to be handled with low priority (see the QS_ClientPrefer directive). The "max bytes per second" activates dynamic minimum throughput control: The required minimal throughput is increased in parallel to the number of concurrent clients sending/receiving data. The "max bytes per second" setting is reached when the number of sending/receiving clients is equal to the MaxClients setting. The "connections" argument is used to specify the number of busy TCP connections a server must have to enable this feature (0 by default). No limitation is set by default.
+QS_SrvMinDataRate <bytes per seconds> [<max bytes per second> [<connections>]], defines the minimum upload/download throughput a client must generate (the bytes send/received by the client per seconds). This bandwidth is measured while transmitting the data (request line, header fields, request body, or response data). The client connection get closed if the client does not fulfill the required data rate and the IP address of the causing client get marked in order to be handled with low priority (see the QS_ClientPrefer directive). The "max bytes per second" activates dynamic minimum throughput control: The required minimal throughput is increased in parallel to the number of concurrent clients sending/receiving data. The "max bytes per second" setting is reached when the number of sending/receiving clients is equal to the MaxClients setting. The "connections" argument is used to specify the number of busy TCP connections a server must have to enable this feature (0 by default). No limitation is set by default.
 .TP
 QS_SrvMinDataRateOffEvent  '+'|'\-'<env\-variable>, disables the minimal data rate enfocement (QS_SrvMinDataRate) for a certain connection if the defined environment variable has been set. The '+' prefix is used to add a variable to the configuration while the '\-' prefix is used to remove a variable.
 .TP
@@ -55,7 +55,7 @@
 .TP
 QS_SrvSampleRate <seconds>, defines the sampling rate used by the QS_SrvMinDataRate directive to measure the throughput of a connection.
 .TP
-QS_DenyRequestLine '+'|'\-'<id> 'log'|'deny' <pcre>, generic request line (method, path, query and protocol) filter used to deny access for requests matching the defined expression (pcre). '+' adds a new rule while '\-' removes a rule for a location. The action is either 'log' (access is granted but rule match is logged) or 'deny' (access is denied).
+QS_DenyRequestLine '+'|'\-'<id> 'log'|'deny' <regular expression>, generic request line (method, path, query and protocol) filter used to deny access for requests matching the defined regular expression. '+' adds a new rule while '\-' removes a rule for a location. The action is either 'log' (access is granted but rule match is logged) or 'deny' (access is denied).
 .TP
 QS_DenyPath, same as QS_DenyRequestLine but applied to the path only.
 .TP
@@ -63,7 +63,7 @@
 .TP
 QS_DenyEvent '+'|'\-'<id> 'log'|'deny' [!]<variable>, matches requests having the defined process environment variable set (or NOT set if prefixed by a '!'). The action taken for matching rules is either 'log' (access is granted but the rule match is logged) or 'deny' (access is denied).
 .TP
-QS_PermitUri, '+'|'\-'<id> 'log'|'deny' <pcre>, generic request filter applied to the request uri (path and query). Only requests matching at least one QS_PermitUri pattern are allowed. If a QS_PermitUri pattern has been defined an the request does not match any rule, the request is denied albeit of any server resource availability (white list). All rules must define the same action. pcre is case sensitve.
+QS_PermitUri, '+'|'\-'<id> 'log'|'deny' <regular expression>, generic request filter applied to the request uri (path and query). Only requests matching at least one QS_PermitUri pattern are allowed. If a QS_PermitUri pattern has been defined an the request does not match any rule, the request is denied albeit of any server resource availability (allow list). All rules must define the same action. Regular expression is case sensitive.
 .TP
 QS_DenyBody 'on'|'off', enabled body data filter (obsolete).
 .TP
@@ -81,11 +81,11 @@
 .TP
 QS_RequestHeaderFilter 'on'|'off'|'size', filters request headers by allowing only these headers which match the request header rules defined by mod_qos. Request headers which do not conform these definitions are either dropped or the whole request is denied. Custom request headers may be added by the QS_RequestHeaderFilterRule directive. Using the 'size' option, the header field max. size is verified only (similar to LimitRequestFieldsize but using individual values for each header type) while the pattern is ignored.
 .TP
-QS_ResponseHeaderFilter 'on'|'off', filters response headers by allowing only these headers which match the request header rules defined by mod_qos. Request headers which do not conform these definitions are dropped.
+QS_ResponseHeaderFilter 'on'|'off', filters response headers by allowing only these headers which match the response header rules defined by mod_qos. Response headers which do not conform these definitions are dropped.
 .TP
-QS_RequestHeaderFilterRule <header name> 'drop'|'deny' <pcre>  <size>, used to add custom request header filter rules which override the internal filter rules of mod_qos. Directive is allowed in global server context only.
+QS_RequestHeaderFilterRule <header name> 'drop'|'deny' <regular expression>  <size>, used to add custom request header filter rules which override the internal filter rules of mod_qos. Directive is allowed in global server context only.
 .TP
-QS_ResponseHeaderFilterRule <header name> <pcre> <size>, used to add custom response header filter rules which override the internal filter rules of mod_qos. Directive is allowed in global server context only.
+QS_ResponseHeaderFilterRule <header name> <regular expression> <size>, used to add custom response header filter rules which override the internal filter rules of mod_qos. Directive is allowed in global server context only.
 .TP
 QS_MileStone 'log'|'deny' <pattern> [<thinktime>], defines request line patterns a client must access in the defined order as they are defined in the configuration file.
 .TP
@@ -109,9 +109,9 @@
 .TP
 QS_UserTrackingCookieName <name> [<path>] [<domain>] ['session'] ['jsredirect'], enables the user tracking cookie by defining a cookie name. The "path" parameter is an option cookie check page which is used to ensure the client accepts cookies. The "domain" option defines the Domain attriibute for the Set\-Cookie header. The option "session" indicates that the cookie shall be a session cookie expiring when the user closes it's browser. User tracking requires mod_unique_id. This feature is disabled by default. Ignores QS_LogOnly.
 .TP
-QS_SetEnvIf [!]<variable1>[=<regex>] [[!]<variable2>] [!]<variable=value>, sets (or unsets) the 'variable=value' (literal string) if variable1 (literal string) AND variable2 (literal string) are set in the request environment variable list (not case sensitive). This is used to combine multiple variables to a new event type. Alternatively, a regular expression can be specifed for variable1's value and variable2 must be omitted in order to simply set a new variable if the regular expression matches.
+QS_SetEnvIf [!]<variable1>[=<regex>] [[!]<variable2>] [!]<variable=value>, sets (or unsets) the 'variable=value' (literal string) if variable1 (literal string) AND variable2 (literal string) are set in the request environment variable list (not case sensitive). This is used to combine multiple variables to a new event type. Alternatively, a regular expression can be specified for variable1's value and variable2 must be omitted in order to simply set a new variable if the regular expression matches.
 .TP
-QS_SetEnvIfCmpP <env\-variable1> eq|ne|gt|lt <env\-variable2> [!]<env\-variable>[=<value>], sets the specifed environment variable if the specifed env\-variables are alphabetically or numerical equal (eq), not equal (ne), greater (gt), less (lt).
+QS_SetEnvIfCmpP <env\-variable1> eq|ne|gt|lt <env\-variable2> [!]<env\-variable>[=<value>], sets the specified environment variable if the specified env\-variables are alphabetically or numerical equal (eq), not equal (ne), greater (gt), less (lt).
 .TP
 QS_SetEnvIfQuery <regex> [!]<variable>[=value], directive works quite similar to the SetEnvIf directive of the Apache module mod_setenvif, but the specified regex is applied against the query string portion of the request line. The directive recognizes the occurrences of $1..$9 within value and replaces them by the sub\-expressions of the defined regex pattern.
 .TP
@@ -135,11 +135,11 @@
 .TP
 QS_UnsetResHeader <header name>, Removes the specified header from the response.
 .TP
-QS_SetEnvResHeader <header name> [drop], sets the defined HTTP response header to the request environment variables. Deletes the header if the action 'drop' has been specified.
+QS_SetEnvResHeader <header name> [drop], sets the defined HTTP response header (name and value) to the request environment variables Deletes the header if the action 'drop' has been specified.
 .TP
-QS_SetEnvResHeaderMatch <header name> <regex>, sets the defined HTTP response header to the request environment variables if the specified regular expression (pcre) matches the header value.
+QS_SetEnvResHeaderMatch <header name> <regex>, sets the defined HTTP response header (name and value) to the request environment variables if the specified regular expression matches the header value.
 .TP
-QS_SetEnvRes <variable> <regex> <variable2>[=<value>], sets the environmet variable2 if the regular expression matches against the value of the environment variable. Occurrences of $1..$9 within the value and replace them by parenthesized subexpressions of the regular expression.
+QS_SetEnvRes <variable> <regex> <variable2>[=<value>], sets the environment variable2 if the regular expression matches against the value of the environment variable. Occurrences of $1..$9 within the value and replace them by parenthesized subexpressions of the regular expression.
 .TP
 QS_RedirectIf <variable> <regex> [<code>:]<url>, redirects the client to the configured url if the regular expression matches the value of the the environment variable.
 .TP
@@ -149,11 +149,11 @@
 .TP
 QS_ClientTolerance <percent>, defines the allowed tolerance (variation) from a "normal" client (average) in percent. Default is 20%. Directive is allowed in global server context only.
 .TP
-QS_ClientContentTypes <html> <css/js> <images> <other> <304>, defines the distribution of HTTP response content types a client normaly receives when accessing the server. mod_qos normally learns the average behavior automatically by default but you may specify a static configuration in order to avoid influences by a high number of abnormal clients.
+QS_ClientContentTypes <html> <css/js> <images> <other> <304>, defines the distribution of HTTP response content types a client normally receives when accessing the server. mod_qos normally learns the average behavior automatically by default but you may specify a static configuration in order to avoid influences by a high number of abnormal clients.
 .TP
 QS_ClientEventBlockCount <number> [<seconds>], defines the maximum number of QS_Block allowed within the defined time (default are 10 minutes). Directive is allowed in global server context only.
 .TP
-QS_ClientEventBlockExcludeIP <addr>, excludes an IP address or address range from beeing limited by QS_ClientEventBlockCount.
+QS_ClientEventBlockExcludeIP <addr>, excludes an IP address or address range from being limited by QS_ClientEventBlockCount.
 .TP
 QS_ClientEventLimitCount <number> [<seconds> [<variable>]], defines the maximum number of the specified environment variable (QS_Limit by default) allowed within the defined time (default are 10 minutes). Directive is allowed in global server context only.
 .TP
@@ -161,32 +161,34 @@
 .TP
 QS_ClientEventPerSecLimit <number>, defines the number events pro seconds on a per client (source IP) basis. Events are identified by requests having the QS_Event variable set. Directive is allowed in global server context only.
 .TP
-QS_ClientEventRequestLimit <number>, defines the allowed number of concurrent requests comming from the same client source IP address having the QS_EventRequest variable set. Directive is allowed in global server context only.
+QS_ClientEventRequestLimit <number>, defines the allowed number of concurrent requests coming from the same client source IP address having the QS_EventRequest variable set. Directive is allowed in global server context only.
 .TP
-QS_ClientSerialize, serializes requests having the QS_Serialize variable set if they are comming from the same IP address.
+QS_ClientSerialize, serializes requests having the QS_Serialize variable set if they are coming from the same IP address.
 .TP
 QS_ClientIpFromHeader <header>, defines a HTTP request header to read the client's source IP address from (instead of taking the IP address of the client opening the TCP connection). This may be used for the QS_ClientEventLimitCount directive and QS_Country variable.
 .TP
 QS_ClientGeoCountryDB <path>, path to the geograpical database file.
 .TP
-QS_ClientGeoCountryPriv <list> <connections>, defines a comma separated list of country codes for origin client IP address which are allowed to access the server if the number of busy TCP connections reaches the defined number of connections.
+QS_ClientGeoCountryPriv <list> <connections> ['excludeUnknown'], defines a comma separated list of country codes for origin client IP address which are allowed to access the server if the number of busy TCP connections reaches the defined number of connections while others are denied access. Clients whose IP can't be mapped to a country code can be excluded from the limitation by configuring the 'excludeUnknown' argument.
 .TP
 QS_ErrorPage <url>, defines a custom error page.
 .TP
 QS_ErrorResponseCode <code>, defines the HTTP response code which is used when a request is denied, default is 500.
 .TP
+QS_ForcedClose 'on'|'off', defines if mod_qos connection handler shall exit with an error code (on) or not. Default is on (except for Apache 2.4.49).
+.TP
 QS_LogOnly 'on'|'off', enables the log only mode of the module where no limitations are enforced. Default is off. Directive is allowed in global server context only.
 .TP
+QS_LogEnv 'on'|'off', enables logging of environment variables.
+.TP
 QS_SupportIPv6 'on'|'off', enables IPv6 address support. Default is on.
 .TP
-QS_SemMemFile <path>, optional path to a directory or file which shall be used for file based samaphores/shared memory usage. Default is /var/tmp/.
+QS_SemMemFile <path>, optional path to a directory or file which shall be used for file based semaphores/shared memory usage, e.g. /var/tmp.
 .TP
 QS_MaxClients <number>, optional override for mod_qos's MaxClients/MaxRequestWorkers calculation which defines the maximum number of TCP connections the server can handle.
 .TP
 QS_DisableHandler 'on'|'off', disables the qos\-viewer and qos\-console for a virtual host
 .TP
-QS_Chroot <path>, change root directory.
-.TP
 QS_Status 'on'|'off', writes a log message containing server statistics once every minute. Default is off.
 .TP
 QS_EventCount 'on'|'off', enables error event counting (counters are shown in the machine\-readable version of the status viewer). Default is off.
diff -Nru libapache2-mod-qos-11.63/tools/man1/qsdt.1 libapache2-mod-qos-11.74/tools/man1/qsdt.1
--- libapache2-mod-qos-11.63/tools/man1/qsdt.1	2019-05-25 09:08:59.000000000 -0400
+++ libapache2-mod-qos-11.74/tools/man1/qsdt.1	2023-05-18 08:34:25.000000000 -0400
@@ -1,4 +1,4 @@
-.TH QSDT 1 "May 2019" "mod_qos utilities 11.63" "qsdt man page"
+.TH QSDT 1 "May 2023" "mod_qos utilities 11.74" "qsdt man page"
 
 .SH NAME
 qsdt calculates the elapsed time between two related log messages. 
diff -Nru libapache2-mod-qos-11.63/tools/man1/qsexec.1 libapache2-mod-qos-11.74/tools/man1/qsexec.1
--- libapache2-mod-qos-11.63/tools/man1/qsexec.1	2019-05-25 09:08:59.000000000 -0400
+++ libapache2-mod-qos-11.74/tools/man1/qsexec.1	2023-05-18 08:34:25.000000000 -0400
@@ -1,4 +1,4 @@
-.TH QSEXEC 1 "May 2019" "mod_qos utilities 11.63" "qsexec man page
+.TH QSEXEC 1 "May 2023" "mod_qos utilities 11.74" "qsexec man page
 
 .SH NAME
 qsexec \- parses the data received via stdin and executes the defined command on a pattern match.
@@ -10,7 +10,7 @@
 .SH OPTIONS
 .TP
 \-e <pattern> 
-Specifes the search pattern causing an event which shall trigger the command. 
+Specifies the search pattern causing an event which shall trigger the command. 
 .TP
 \-t <number>:<sec> 
 Defines the number of pattern match within the the defined number of seconds in order to trigger the command execution. By default, every pattern match causes a command execution. 
diff -Nru libapache2-mod-qos-11.63/tools/man1/qsfilter2.1 libapache2-mod-qos-11.74/tools/man1/qsfilter2.1
--- libapache2-mod-qos-11.63/tools/man1/qsfilter2.1	2019-05-25 09:08:59.000000000 -0400
+++ libapache2-mod-qos-11.74/tools/man1/qsfilter2.1	2023-05-18 08:34:25.000000000 -0400
@@ -1,17 +1,17 @@
-.TH QSFILTER2 1 "May 2019" "mod_qos utilities 11.63" "qsfilter2 man page"
+.TH QSFILTER2 1 "May 2023" "mod_qos utilities 11.74" "qsfilter2 man page"
 
 .SH NAME
 qsfilter2 \- an utility to generate mod_qos request line rules out from existing access/audit log data. 
 .SH SYNOPSIS
 qsfilter2 \-i <path> [\-c <path>] [\-d <num>] [\-h] [\-b <num>] [\-p|\-s|\-m|\-o] [\-l <len>] [\-n] [\-e] [\-u 'uni'] [\-k <prefix>] [\-t] [\-f <path>] [\-v 0|1|2] 
 .SH DESCRIPTION
-mod_qos implements a request filter which validates each request line. The module supports both, negative and positive security model. The QS_Deny* directives are used to specify request line patterns which are not allowed to access the server (negative security model / blacklist). These rules are used to restrict access to certain resources which should not be available to users or to protect the server from malicious patterns. The QS_Permit* rules implement a positive security model (whitelist). These directives are used to define allowed request line patterns. Request which do not match any of thses patterns are not allowed to access the server. 
+mod_qos implements a request filter which validates each request line. The module supports both, negative and positive security model. The QS_Deny* directives are used to specify request line patterns which are not allowed to access the server (negative security model / deny list). These rules are used to restrict access to certain resources which should not be available to users or to protect the server from malicious patterns. The QS_Permit* rules implement a positive security model (allow list). These directives are used to define allowed request line patterns. Request which do not match any of these patterns are not allowed to access the server. 
 
 qsfilter2 is an audit log analyzer used to generate filter rules (perl compatible regular expressions) which may be used by mod_qos to deny access for suspect requests (QS_PermitUri rules). It parses existing audit log files in order to generate request patterns covering all allowed requests. 
 .SH OPTIONS
 .TP
 \-i <path> 
-Input file containing request URIs. The URIs for this file have to be extracted from the servers access logs. Each line of the input file contains a request URI consiting of a path and and query. 
+Input file containing request URIs. The URIs for this file have to be extracted from the servers access logs. Each line of the input file contains a request URI consisting of a path and and query. 
      Example:
        /aaa/index.do
        /aaa/edit?image=1.jpg
@@ -22,9 +22,9 @@
 These access log data must include current request URIs but also request lines from previous rule generation steps. It must also include request lines which cover manually generated rules. You may use the 'qos\-path' and 'qos\-query' variables to create an audit log containing all request data (path and query/body data). Example: 'CustomLog audit_log %{qos\-path}n%{qos\-query}n'. See also http://mod\-qos.sourceforge.net#qsfiltersample about the module settings. 
 .TP
 \-c <path> 
-mod_qos configuration file defining QS_DenyRequestLine and QS_PermitUri directives. qsfilter2 generates rules from access log data automatically. Manually generated rules (QS_PermitUri) may be provided from this file. Note: each manual rule must be represented by a request URI in the input data (\-i) in order to make sure not to be deleted by the rule optimisation algorithm. QS_Deny* rules from this file are used to filter request lines which should not be used for whitelist rule generation. 
+mod_qos configuration file defining QS_DenyRequestLine and QS_PermitUri directives. qsfilter2 generates rules from access log data automatically. Manually generated rules (QS_PermitUri) may be provided from this file. Note: each manual rule must be represented by a request URI in the input data (\-i) in order to make sure not to be deleted by the rule optimisation algorithm. QS_Deny* rules from this file are used to filter request lines which should not be used for allow list rule generation. 
      Example:
-       # manually defined whitelist rule:
+       # manually defined allow list rule:
        QS_PermitUri +view deny "^[/a\-zA\-Z0\-9]+/view\\?(page=[0\-9]+)?$"
        # filter unwanted request line patterns:
        QS_DenyRequestLine +printable deny ".*[\\x00\-\\x19].*"
@@ -41,13 +41,13 @@
 Replaces url pattern by the regular expression when detecting a base64/hex encoded string. Detecting sensibility is defined by a numeric value. You should use values higher than 5 (default) or 0 to disable this function. 
 .TP
 \-p 
-Repesents query by pcre only (no literal strings). 
+Represents query by pcre only (no literal strings). 
 .TP
 \-s 
 Uses one single pcre for the whole query string. 
 .TP
 \-m 
-Uses one pcre for multipe query values (recommended mode). 
+Uses one pcre for multiple query values (recommended mode). 
 .TP
 \-o 
 Does not care the order of query parameters. 
diff -Nru libapache2-mod-qos-11.63/tools/man1/qsgeo.1 libapache2-mod-qos-11.74/tools/man1/qsgeo.1
--- libapache2-mod-qos-11.63/tools/man1/qsgeo.1	2019-05-25 09:08:59.000000000 -0400
+++ libapache2-mod-qos-11.74/tools/man1/qsgeo.1	2023-05-18 08:34:25.000000000 -0400
@@ -1,4 +1,4 @@
-.TH QSGEO 1 "May 2019" "mod_qos utilities 11.63" "qsgeo man page"
+.TH QSGEO 1 "May 2023" "mod_qos utilities 11.74" "qsgeo man page"
 
 .SH NAME
 qsgeo \- an utility to lookup a client's country code. 
diff -Nru libapache2-mod-qos-11.63/tools/man1/qsgrep.1 libapache2-mod-qos-11.74/tools/man1/qsgrep.1
--- libapache2-mod-qos-11.63/tools/man1/qsgrep.1	2019-05-25 09:08:59.000000000 -0400
+++ libapache2-mod-qos-11.74/tools/man1/qsgrep.1	2023-05-18 08:34:25.000000000 -0400
@@ -1,4 +1,4 @@
-.TH QSGREP 1 "May 2019" "mod_qos utilities 11.63" "qsgrep man page"
+.TH QSGREP 1 "May 2023" "mod_qos utilities 11.74" "qsgrep man page"
 
 .SH NAME
 qsgrep \- prints matching patterns within a file. 
@@ -9,7 +9,7 @@
 .SH OPTIONS
 .TP
 \-e <pattern> 
-Specifes the search pattern. 
+Specifies the search pattern. 
 .TP
 \-o <string> 
 Defines the output string where $0\-$9 are substituted by the submatches of the regular expression. 
diff -Nru libapache2-mod-qos-11.63/tools/man1/qshead.1 libapache2-mod-qos-11.74/tools/man1/qshead.1
--- libapache2-mod-qos-11.63/tools/man1/qshead.1	2019-05-25 09:08:59.000000000 -0400
+++ libapache2-mod-qos-11.74/tools/man1/qshead.1	2023-05-18 08:34:25.000000000 -0400
@@ -1,11 +1,11 @@
-.TH QSHEAD 1 "May 2019" "mod_qos utilities 11.63" "qshead man page"
+.TH QSHEAD 1 "May 2023" "mod_qos utilities 11.74" "qshead man page"
 
 .SH NAME
 qshead \- an utility reading from stdin and printing all lines to stdout until reaching the defined pattern. 
 .SH SYNOPSIS
 qshead \-p <pattern> 
 .SH DESCRIPTION
-qshead reads lines from stdin and prints them to stdout unitl a line contains the specified pattern (literal string). 
+qshead reads lines from stdin and prints them to stdout until a line contains the specified pattern (literal string). 
 .SH OPTIONS
 .TP
 \-p <pattern> 
diff -Nru libapache2-mod-qos-11.63/tools/man1/qslog.1 libapache2-mod-qos-11.74/tools/man1/qslog.1
--- libapache2-mod-qos-11.63/tools/man1/qslog.1	2019-05-25 09:08:59.000000000 -0400
+++ libapache2-mod-qos-11.74/tools/man1/qslog.1	2023-05-18 08:34:25.000000000 -0400
@@ -1,4 +1,4 @@
-.TH QSLOG 1 "May 2019" "mod_qos utilities 11.63" "qslog man page"
+.TH QSLOG 1 "May 2023" "mod_qos utilities 11.74" "qslog man page"
 
 .SH NAME
 qslog \- collects request statistics from access log data. 
@@ -10,7 +10,7 @@
   \- number of requests within measured time (req)
   \- bytes sent to the client per second (b/s)
   \- bytes received from the client per second (ib/s)
-  \- repsonse status codes within the last minute (1xx,2xx,3xx,4xx,5xx)
+  \- response status codes within the last minute (1xx,2xx,3xx,4xx,5xx)
   \- average response duration (av)
   \- average response duration in milliseconds (avms)
   \- distribution of response durations in seconds within the last minute
@@ -28,7 +28,7 @@
 .SH OPTIONS
 .TP
 \-f <format_string> 
-Defines the log data format and the positions of data elements processed by this utility. See to the 'LogFormat' directive of the httpd.conf file to see the format defintions of the servers access log data. 
+Defines the log data format and the positions of data elements processed by this utility. See to the 'LogFormat' directive of the httpd.conf file to see the format definitions of the servers access log data. 
      qslog knows the following elements:
      I defines the client ip address (%h)
      R defines the request line (%r)
@@ -71,7 +71,7 @@
 Calculates free system memory every minute. 
 .TP
 \-c <path> 
-Enables the collection of log statitics for different request types. 'path' specifies the necessary rule file. Each rule consists of a rule identifier and a regular expression to identify a request seprarated by a colon, e.g., 01:^(/a)|(/c). The regular expressions are matched against the log data element which has been identified by the 'C' format character. 
+Enables the collection of log statistics for different request types. 'path' specifies the necessary rule file. Each rule consists of a rule identifier and a regular expression to identify a request seprarated by a colon, e.g., 01:^(/a)|(/c). The regular expressions are matched against the log data element which has been identified by the 'C' format character. 
 .SH VARIABLES
 The following environment variables are known to qslog: 
 .TP
diff -Nru libapache2-mod-qos-11.63/tools/man1/qslogger.1 libapache2-mod-qos-11.74/tools/man1/qslogger.1
--- libapache2-mod-qos-11.63/tools/man1/qslogger.1	2019-05-25 09:08:59.000000000 -0400
+++ libapache2-mod-qos-11.74/tools/man1/qslogger.1	2023-05-18 08:34:25.000000000 -0400
@@ -1,4 +1,4 @@
-.TH QSLOGGER 1 "May 2019" "mod_qos utilities 11.63" "qslogger man page"
+.TH QSLOGGER 1 "May 2023" "mod_qos utilities 11.74" "qslogger man page"
 
 .SH NAME
 qslogger \- another shell command interface to the system log module (syslog). 
@@ -19,7 +19,7 @@
 Becomes another user, e.g. www\-data. 
 .TP
 \-l <level> 
-Defines the minimal severity a message must have in order to be forwarded. Default is 'DEBUG' (fowarding everything). 
+Defines the minimal severity a message must have in order to be forwarded. Default is 'DEBUG' (forwarding everything). 
 .TP
 \-x <prefix> 
 Allows you to add a prefix (literal string) to every message. 
@@ -28,7 +28,7 @@
 Specifies a regular expression which shall be used to determine the severity (syslog level) for each log line. The default pattern '^\\[[0\-9a\-zA\-Z :]+\\] \\[([a\-z]+)\\] ' can be used for Apache error log messages but you may configure your own pattern matching other log formats. Use brackets to define the pattern enclosing the severity string. Default level (if severity can't be determined) is defined by the option '\-d' (see below). 
 .TP
 \-d <level> 
-The default severity if the specified pattern (\-r) does not match and the message's serverity can't be determined. Default is 'NOTICE'. 
+The default severity if the specified pattern (\-r) does not match and the message's severity can't be determined. Default is 'NOTICE'. 
 .TP
 \-p 
 Writes data also to stdout (for piped logging). 
diff -Nru libapache2-mod-qos-11.63/tools/man1/qspng.1 libapache2-mod-qos-11.74/tools/man1/qspng.1
--- libapache2-mod-qos-11.63/tools/man1/qspng.1	2019-05-25 09:08:59.000000000 -0400
+++ libapache2-mod-qos-11.74/tools/man1/qspng.1	2023-05-18 08:34:25.000000000 -0400
@@ -1,4 +1,4 @@
-.TH QSPNG 1 "May 2019" "mod_qos utilities 11.63" "qspng man page"
+.TH QSPNG 1 "May 2023" "mod_qos utilities 11.74" "qspng man page"
 
 .SH NAME
 qspng \- an utility to draw a png graph from qslog(1) output data. 
diff -Nru libapache2-mod-qos-11.63/tools/man1/qsre.1 libapache2-mod-qos-11.74/tools/man1/qsre.1
--- libapache2-mod-qos-11.63/tools/man1/qsre.1	2019-05-25 09:08:59.000000000 -0400
+++ libapache2-mod-qos-11.74/tools/man1/qsre.1	2023-05-18 08:34:25.000000000 -0400
@@ -1,4 +1,4 @@
-.TH QSRE 1 "May 2019" "mod_qos utilities 11.63" "qsre man page"
+.TH QSRE 1 "May 2023" "mod_qos utilities 11.74" "qsre man page"
 
 .SH NAME
 qsre matches a regular expression against test strings. 
@@ -9,7 +9,7 @@
 .SH OPTIONS
 .TP
 <string>|<path> 
-The first argument either defines a sinlge test string of a path to a file containing either multiple test strings or a test pattern with newline characters (text). 
+The first argument either defines a single test string of a path to a file containing either multiple test strings or a test pattern with newline characters (text). 
 .TP
 <pcre>|<path> 
 The second argument either defines a regular expression or a path to a file containing the expression. 
diff -Nru libapache2-mod-qos-11.63/tools/man1/qsrespeed.1 libapache2-mod-qos-11.74/tools/man1/qsrespeed.1
--- libapache2-mod-qos-11.63/tools/man1/qsrespeed.1	2019-05-25 09:08:59.000000000 -0400
+++ libapache2-mod-qos-11.74/tools/man1/qsrespeed.1	2023-05-18 08:34:25.000000000 -0400
@@ -1,11 +1,11 @@
-.TH QSRESPEED 1 "May 2019" "mod_qos utilities 11.63" "qsrespeed man page"
+.TH QSRESPEED 1 "May 2023" "mod_qos utilities 11.74" "qsrespeed man page"
 
 .SH NAME
 Tool to compare / estimate the processing time for (Perl\-compatible) regular expressions (PCRE). 
 .SH SYNOPSIS
 qsrespeed <path> 
 .SH DESCRIPTION
-qsrespeed loads regular expressions from the provided file and matches them against a build\-in set of strings measuring the time needed to process them. It's a benchmark too to judge the expressions you have defined regarding the potential CPU consumption. 
+qsrespeed loads regular expressions from the provided file and matches them against a built\-in set of strings measuring the time needed to process them. It's a benchmark too to judge the expressions you have defined regarding the potential CPU consumption. 
 .SH OPTIONS
 .TP
 <path> 
diff -Nru libapache2-mod-qos-11.63/tools/man1/qsrotate.1 libapache2-mod-qos-11.74/tools/man1/qsrotate.1
--- libapache2-mod-qos-11.63/tools/man1/qsrotate.1	2019-05-25 09:08:59.000000000 -0400
+++ libapache2-mod-qos-11.74/tools/man1/qsrotate.1	2023-05-18 08:34:25.000000000 -0400
@@ -1,4 +1,4 @@
-.TH QSROTATE 1 "May 2019" "mod_qos utilities 11.63" "qsrotate man page"
+.TH QSROTATE 1 "May 2023" "mod_qos utilities 11.74" "qsrotate man page"
 
 .SH NAME
 qsrotate \- a log rotation tool (similar to Apache's rotatelogs). 
diff -Nru libapache2-mod-qos-11.63/tools/man1/qssign.1 libapache2-mod-qos-11.74/tools/man1/qssign.1
--- libapache2-mod-qos-11.63/tools/man1/qssign.1	2019-05-25 09:08:59.000000000 -0400
+++ libapache2-mod-qos-11.74/tools/man1/qssign.1	2023-05-18 08:34:25.000000000 -0400
@@ -1,11 +1,11 @@
-.TH QSSIGN 1 "May 2019" "mod_qos utilities 11.63" "qssign man page"
+.TH QSSIGN 1 "May 2023" "mod_qos utilities 11.74" "qssign man page"
 
 .SH NAME
 qssign \- an utility to sign and verify the integrity of log data. 
 .SH SYNOPSIS
 qssign \-s|S <secret> [\-e] [\-v] [\-u <name>] [\-f <regex>] [\-a 'sha1'|'sha256'] 
 .SH DESCRIPTION
-qssign is a log data integrity check tool. It reads log data from stdin (pipe) and writes the data to stdout adding a sequence number and signatur to ever log line. 
+qssign is a log data integrity check tool. It reads log data from stdin (pipe) and writes the data to stdout adding a sequence number and signature to ever log line. 
 .SH OPTIONS
 .TP
 \-s <secret> 
@@ -27,7 +27,7 @@
 Filter pattern (case sensitive regular expression) for messages which do not need to be signed. 
 .TP
 \-a 'sha1'|'sha256' 
-Specifes the algorithm to use. Default is sha1. 
+Specifies the algorithm to use. Default is sha1. 
 .SH EXAMPLE
 Sign:
 
diff -Nru libapache2-mod-qos-11.63/tools/man1/qstail.1 libapache2-mod-qos-11.74/tools/man1/qstail.1
--- libapache2-mod-qos-11.63/tools/man1/qstail.1	2019-05-25 09:08:59.000000000 -0400
+++ libapache2-mod-qos-11.74/tools/man1/qstail.1	2023-05-18 08:34:25.000000000 -0400
@@ -1,4 +1,4 @@
-.TH QSTAIL 1 "May 2019" "mod_qos utilities 11.63" "qstail man page"
+.TH QSTAIL 1 "May 2023" "mod_qos utilities 11.74" "qstail man page"
 
 .SH NAME
 qstail \- an utility printing the end of a log file starting at the specified pattern. 
diff -Nru libapache2-mod-qos-11.63/tools/src/char.h libapache2-mod-qos-11.74/tools/src/char.h
--- libapache2-mod-qos-11.63/tools/src/char.h	2019-05-25 09:08:59.000000000 -0400
+++ libapache2-mod-qos-11.74/tools/src/char.h	2023-05-18 08:34:25.000000000 -0400
@@ -4,7 +4,7 @@
  * See http://mod-qos.sourceforge.net/ for further
  * details.
  *
- * Copyright (C) 2019 Pascal Buchbinder
+ * Copyright (C) 2023 Pascal Buchbinder
  *
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
diff -Nru libapache2-mod-qos-11.63/tools/src/Makefile.am libapache2-mod-qos-11.74/tools/src/Makefile.am
--- libapache2-mod-qos-11.63/tools/src/Makefile.am	2019-05-25 09:08:59.000000000 -0400
+++ libapache2-mod-qos-11.74/tools/src/Makefile.am	2023-05-18 08:34:25.000000000 -0400
@@ -1,6 +1,6 @@
 # $Id: Makefile.am 2486 2018-09-03 20:22:17Z pbuchbinder $
 
-bin_PROGRAMS=qsfilter2 qslog qspng qsrotate qssign qstail qsgrep qsexec qscheck qsgeo qslogger qshead qsdt qsrespeed qsre
+bin_PROGRAMS=qsfilter2 qslog qspng qsrotate qssign qstail qshead qsgrep qsexec qscheck qsgeo qslogger qsdt qsrespeed qsre
 
 qsfilter2_SOURCES= \
 	qsfilter2.c qs_util.c
diff -Nru libapache2-mod-qos-11.63/tools/src/Makefile.in libapache2-mod-qos-11.74/tools/src/Makefile.in
--- libapache2-mod-qos-11.63/tools/src/Makefile.in	2019-05-25 09:08:59.000000000 -0400
+++ libapache2-mod-qos-11.74/tools/src/Makefile.in	2023-05-18 08:34:25.000000000 -0400
@@ -90,9 +90,9 @@
 POST_UNINSTALL = :
 bin_PROGRAMS = qsfilter2$(EXEEXT) qslog$(EXEEXT) qspng$(EXEEXT) \
 	qsrotate$(EXEEXT) qssign$(EXEEXT) qstail$(EXEEXT) \
-	qsgrep$(EXEEXT) qsexec$(EXEEXT) qscheck$(EXEEXT) \
-	qsgeo$(EXEEXT) qslogger$(EXEEXT) qshead$(EXEEXT) qsdt$(EXEEXT) \
-	qsrespeed$(EXEEXT) qsre$(EXEEXT)
+	qshead$(EXEEXT) qsgrep$(EXEEXT) qsexec$(EXEEXT) \
+	qscheck$(EXEEXT) qsgeo$(EXEEXT) qslogger$(EXEEXT) \
+	qsdt$(EXEEXT) qsrespeed$(EXEEXT) qsre$(EXEEXT)
 subdir = src
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/configure.ac
diff -Nru libapache2-mod-qos-11.63/tools/src/qs_apo.c libapache2-mod-qos-11.74/tools/src/qs_apo.c
--- libapache2-mod-qos-11.63/tools/src/qs_apo.c	2019-05-25 09:08:59.000000000 -0400
+++ libapache2-mod-qos-11.74/tools/src/qs_apo.c	2023-05-18 08:34:25.000000000 -0400
@@ -4,7 +4,7 @@
  * See http://mod-qos.sourceforge.net/ for further
  * details.
  *
- * Copyright (C) 2019 Pascal Buchbinder
+ * Copyright (C) 2023 Pascal Buchbinder
  *
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -23,7 +23,7 @@
  *
  */
 
-static const char revision[] = "$Id: qs_apo.c 2542 2019-02-22 06:37:10Z pbuchbinder $";
+static const char revision[] = "$Id: qs_apo.c 2654 2022-05-13 09:12:42Z pbuchbinder $";
 
 #include <stdio.h>
 #include <pthread.h>
diff -Nru libapache2-mod-qos-11.63/tools/src/qs_apo.h libapache2-mod-qos-11.74/tools/src/qs_apo.h
--- libapache2-mod-qos-11.63/tools/src/qs_apo.h	2019-05-25 09:08:59.000000000 -0400
+++ libapache2-mod-qos-11.74/tools/src/qs_apo.h	2023-05-18 08:34:25.000000000 -0400
@@ -4,7 +4,7 @@
  * See http://mod-qos.sourceforge.net/ for further
  * details.
  *
- * Copyright (C) 2019 Pascal Buchbinder
+ * Copyright (C) 2023 Pascal Buchbinder
  *
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
diff -Nru libapache2-mod-qos-11.63/tools/src/qscheck.c libapache2-mod-qos-11.74/tools/src/qscheck.c
--- libapache2-mod-qos-11.63/tools/src/qscheck.c	2019-05-25 09:08:59.000000000 -0400
+++ libapache2-mod-qos-11.74/tools/src/qscheck.c	2023-05-18 08:34:25.000000000 -0400
@@ -6,7 +6,7 @@
  * See http://mod-qos.sourceforge.net/ for further
  * details.
  *
- * Copyright (C) 2019 Pascal Buchbinder
+ * Copyright (C) 2023 Pascal Buchbinder
  *
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -25,7 +25,7 @@
  *
  */
 
-static const char revision[] = "$Id: qscheck.c 2542 2019-02-22 06:37:10Z pbuchbinder $";
+static const char revision[] = "$Id: qscheck.c 2654 2022-05-13 09:12:42Z pbuchbinder $";
 
 #include <stdio.h>
 #include <stdlib.h>
@@ -65,7 +65,7 @@
  */
 static void usage(char *cmd) {
   printf("\n");
-  printf("Monitor programm testing the TCP connectivity to servers.\n");
+  printf("Monitor program testing the TCP connectivity to servers.\n");
   printf("\n");
   printf("Usage: %s -c <httpd.conf> [-v]\n", cmd);
   printf("\n");
diff -Nru libapache2-mod-qos-11.63/tools/src/qsdt.c libapache2-mod-qos-11.74/tools/src/qsdt.c
--- libapache2-mod-qos-11.63/tools/src/qsdt.c	2019-05-25 09:08:59.000000000 -0400
+++ libapache2-mod-qos-11.74/tools/src/qsdt.c	2023-05-18 08:34:25.000000000 -0400
@@ -7,7 +7,7 @@
  * See http://mod-qos.sourceforge.net/ for further
  * details.
  *
- * Copyright (C) 2019 Pascal Buchbinder
+ * Copyright (C) 2023 Pascal Buchbinder
  *
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
diff -Nru libapache2-mod-qos-11.63/tools/src/qsexec.c libapache2-mod-qos-11.74/tools/src/qsexec.c
--- libapache2-mod-qos-11.63/tools/src/qsexec.c	2019-05-25 09:08:59.000000000 -0400
+++ libapache2-mod-qos-11.74/tools/src/qsexec.c	2023-05-18 08:34:25.000000000 -0400
@@ -5,7 +5,7 @@
  *
  * See http://mod-qos.sourceforge.net/ for further details.
  *
- * Copyright (C) 2019 Pascal Buchbinder
+ * Copyright (C) 2023 Pascal Buchbinder
  *
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -24,7 +24,7 @@
  *
  */
 
-static const char revision[] = "$Id: qsexec.c 2542 2019-02-22 06:37:10Z pbuchbinder $";
+static const char revision[] = "$Id: qsexec.c 2654 2022-05-13 09:12:42Z pbuchbinder $";
 
 /* system */
 #include <stdio.h>
@@ -35,7 +35,6 @@
 #include <time.h>
 
 /* apr */
-#include <pcre.h>
 #include <apr.h>
 #include <apr_strings.h>
 #include <apr_file_io.h>
@@ -46,12 +45,14 @@
 #include <apr_portable.h>
 #include <apr_support.h>
 
+#define PCRE2_CODE_UNIT_WIDTH 8
+#include <pcre2.h>
+
 #include "qs_util.h"
 
 #ifndef POSIX_MALLOC_THRESHOLD
 #define POSIX_MALLOC_THRESHOLD (10)
 #endif
-#define MAX_REG_MATCH 10
 
 /* same as APR_SIZE_MAX which doesn't appear until APR 1.3 */
 #define QSUTIL_SIZE_MAX (~((apr_size_t)0))
@@ -95,7 +96,7 @@
   if(man) printf(".TP\n");
   qs_man_print(man, "  -e <pattern>\n");
   if(man) printf("\n");
-  qs_man_print(man, "     Specifes the search pattern causing an event which shall trigger the\n");
+  qs_man_print(man, "     Specifies the search pattern causing an event which shall trigger the\n");
   qs_man_print(man, "     command.\n");
   if(man) printf("\n.TP\n");
   qs_man_print(man, "  -t <number>:<sec>\n");
@@ -154,7 +155,7 @@
  */
 char *qs_pregsub(apr_pool_t *pool, const char *input,
 		 const char *source, size_t nmatch,
-		 regmatch_t pmatch[]) {
+		 qs_regmatch_t pmatch[]) {
   const char *src = input;
   char *dest, *dst;
   char c;
@@ -216,41 +217,6 @@
   return dest;
 }
 
-int qs_regexec(pcre *preg, const char *string,
-	       apr_size_t nmatch, regmatch_t pmatch[]) {
-  int rc;
-  int options = 0;
-  int *ovector = NULL;
-  int small_ovector[POSIX_MALLOC_THRESHOLD * 3];
-  int allocated_ovector = 0;
-  if (nmatch > 0) {
-    if (nmatch <= POSIX_MALLOC_THRESHOLD) {
-      ovector = &(small_ovector[0]);
-    } else {
-      ovector = (int *)malloc(sizeof(int) * nmatch * 3);
-      if (ovector == NULL) {
-	return 1;
-      }
-      allocated_ovector = 1;
-    }
-  }
-  rc = pcre_exec(preg, NULL, string, (int)strlen(string), 0, options, ovector, nmatch * 3);
-  if (rc == 0) rc = nmatch;    /* All captured slots were filled in */
-  if (rc >= 0) {
-    apr_size_t i;
-    for (i = 0; i < (apr_size_t)rc; i++) {
-      pmatch[i].rm_so = ovector[i*2];
-      pmatch[i].rm_eo = ovector[i*2+1];
-    }
-    if (allocated_ovector) free(ovector);
-    for (; i < nmatch; i++) pmatch[i].rm_so = pmatch[i].rm_eo = -1;
-    return 0;
-  } else {
-    if (allocated_ovector) free(ovector);
-    return rc;
-  }
-}
-
 int main(int argc, const char * const argv[]) {
   const char *username = NULL;
   int nr = 0;
@@ -262,11 +228,9 @@
   const char *clearcommand = NULL;
   const char *clearpattern = NULL;
   int executed = 0;
-  pcre *preg;
-  pcre *clearpreg;
-  const char *errptr = NULL;
-  int erroffset;
-  regmatch_t regm[MAX_REG_MATCH];
+  qs_regex_t *preg;
+  qs_regex_t *clearpreg;
+  qs_regmatch_t regm[QS_MAX_REG_MATCH];
   time_t sec = 0;
   int threshold = 0;
   int counter = 0;
@@ -342,32 +306,36 @@
 
   qs_setuid(username, cmd);
 
-  preg = pcre_compile(pattern, PCRE_DOTALL, &errptr, &erroffset, NULL);
-  if(!preg) {
-    fprintf(stderr, "ERROR, could not compile '%s' at position %d, reason: %s\n",
-	    pattern, erroffset, errptr);
+  preg = apr_palloc(pool, sizeof(qs_regex_t));
+  if(qs_regcomp(preg, pattern, PCRE2_DOTALL) != 0) {
+    fprintf(stderr, "ERROR, could not compile '%s'\n", pattern);
     exit(1);
   }
+  apr_pool_pre_cleanup_register(pool, preg, qs_pregfree);
   if(clearpattern) {
-    clearpreg = pcre_compile(clearpattern, PCRE_DOTALL, &errptr, &erroffset, NULL);
-    if(!clearpreg) {
-      fprintf(stderr, "ERROR, could not compile '%s' at position %d, reason: %s\n",
-	      clearpattern, erroffset, errptr);
+    clearpreg = apr_palloc(pool, sizeof(qs_regex_t));
+    if(qs_regcomp(clearpreg, clearpattern, PCRE2_DOTALL) != 0) {
+      fprintf(stderr, "ERROR, could not compile '%s'\n", clearpattern);
       exit(1);
     }
+    apr_pool_pre_cleanup_register(pool, clearpattern, qs_pregfree);
   }
 
   while(fgets(line, MAX_LINE_BUFFER, stdin) != NULL) {
+    size_t len;
     nr++;
     if(pass) {
       printf("%s", line);
       fflush(stdout);
     }
-    if(clearpattern && (qs_regexec(clearpreg, line, MAX_REG_MATCH, regm) == 0)) {
+    len = strlen(line);
+    if(clearpattern && (qs_regexec_len(clearpreg, line, len, QS_MAX_REG_MATCH, regm, 0) >= 0)) {
+      apr_pool_t *subpool;
+      apr_pool_create(&subpool, pool);
       counter = 0;
       countertime = 0;
       if(clearcommand && executed) {
-	char *replaced = qs_pregsub(pool, clearcommand, line, MAX_REG_MATCH, regm);
+	char *replaced = qs_pregsub(subpool, clearcommand, line, QS_MAX_REG_MATCH, regm);
 	if(!replaced) {
 	  fprintf(stderr, "[%s]: ERROR, failed to substitute"
                   " submatches '%s' in (%s)\n", cmd, clearcommand, line);
@@ -376,8 +344,12 @@
 	}
 	executed = 0;
       }
-    } else if(qs_regexec(preg, line, MAX_REG_MATCH, regm) == 0) {
-      char *replaced = qs_pregsub(pool, command, line, MAX_REG_MATCH, regm);
+      apr_pool_destroy(subpool);
+    } else if(qs_regexec_len(preg, line, len, QS_MAX_REG_MATCH, regm, 0) >= 0) {
+      apr_pool_t *subpool;
+      char *replaced;
+      apr_pool_create(&subpool, pool);
+      replaced = qs_pregsub(subpool, command, line, QS_MAX_REG_MATCH, regm);
       if(!replaced) {
 	fprintf(stderr, "[%s]: ERROR, failed to substitute"
                 " submatches '%s' in (%s)\n", cmd, command, line);
@@ -395,7 +367,7 @@
 	  counter = 0;
 	}
       }
-      apr_pool_clear(pool);
+      apr_pool_destroy(subpool);
     }
   }
   
diff -Nru libapache2-mod-qos-11.63/tools/src/qsfilter2.c libapache2-mod-qos-11.74/tools/src/qsfilter2.c
--- libapache2-mod-qos-11.63/tools/src/qsfilter2.c	2019-05-25 09:08:59.000000000 -0400
+++ libapache2-mod-qos-11.74/tools/src/qsfilter2.c	2023-05-18 08:34:25.000000000 -0400
@@ -2,12 +2,12 @@
  */
 /**
  * Filter utilities for the quality of service module mod_qos
- * used to create white list rules for request line filters.
+ * used to create allow list rules for request line filters.
  *
  * See http://mod-qos.sourceforge.net/ for further
  * details.
  *
- * Copyright (C) 2019 Pascal Buchbinder
+ * Copyright (C) 2023 Pascal Buchbinder
  *
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -26,7 +26,7 @@
  *
  */
 
-static const char revision[] = "$Id: qsfilter2.c 2542 2019-02-22 06:37:10Z pbuchbinder $";
+static const char revision[] = "$Id: qsfilter2.c 2654 2022-05-13 09:12:42Z pbuchbinder $";
 
 /* system */
 #include <stdio.h>
@@ -37,8 +37,6 @@
 #include <unistd.h>
 #include <time.h>
 
-#include <pcre.h>
-
 /* apr */
 #include <apr.h>
 #include <apr_uri.h>
@@ -60,6 +58,9 @@
 /* OpenSSL  */
 #include <openssl/safestack.h>
 
+#define PCRE2_CODE_UNIT_WIDTH 8
+#include <pcre2.h>
+
 #include "qs_util.h"
 
 #define MAX_LINE 32768
@@ -89,11 +90,11 @@
 #define QS_OVECCOUNT 3
 
 /* request line detection */
-#define QOSC_REQ          "(OPTIONS|GET|HEAD|POST|PUT|DELETE|TRACE|CONNECT|PROPFIND|PROPPATCH|MKCOL|COPY|MOVE|LOCK|UNLOCK|VERSION-CONTROL|REPORT|CHECKOUT|CHECKIN|UNCHECKOUT|MKWORKSPACE|UPDATE|LABEL|MERGE|BASELINE-CONTROL|MKACTIVITY|ORDERPATCH|ACL|PATCH|SEARCH|BCOPY|BDELETE|BMOVE|BPROPFIND|BPROPPATCH|NOTIFY|POLL|SUBSCRIBE|UNSUBSCRIBE|X-MS-ENUMATTS|RPC_IN_DATA|RPC_OUT_DATA) /[\x20-\x21\x23-\xFF]* HTTP/"
+#define QOSC_REQ          "(OPTIONS|GET|HEAD|POST|PUT|DELETE|TRACE|CONNECT|PROPFIND|PROPPATCH|MKCOL|COPY|MOVE|LOCK|UNLOCK|VERSION-CONTROL|REPORT|CHECKOUT|CHECKIN|UNCHECKOUT|MKWORKSPACE|UPDATE|LABEL|MERGE|BASELINE-CONTROL|MKACTIVITY|ORDERPATCH|ACL|PATCH|SEARCH|BCOPY|BDELETE|BMOVE|BPROPFIND|BPROPPATCH|NOTIFY|POLL|SUBSCRIBE|UNSUBSCRIBE|X-MS-ENUMATTS|RPC_IN_DATA|RPC_OUT_DATA) (/[\x20-\x21\x23-\xFF]*) HTTP/"
 
-pcre *pcre_b64;
-pcre *pcre_hx;
-pcre *pcre_simple_path;
+qs_regex_t *pcre_b64;
+qs_regex_t *pcre_hx;
+qs_regex_t *pcre_simple_path;
 
 #define QOS_DEC_MODE_FLAGS_URL        0x00
 #define QOS_DEC_MODE_FLAGS_HTML       0x01
@@ -113,14 +114,13 @@
 static int m_query_len_pcre = 10;
 static int m_exit_on_error = 0;
 static int m_handler = 0;
-static pcre *m_req_regex = NULL;
+static qs_regex_t *m_req_regex = NULL;
 static int m_log_req_regex = 0;
 static const char *m_pfx = NULL;
 static const char *m_filter = NULL;
 
 typedef struct {
-  pcre *pcre;
-  pcre_extra *extra;
+  qs_regex_t *pcre;
   char *rule;
   char *path;
   char *query_m_string;
@@ -137,32 +137,30 @@
 }
 
 /* compiles a pcre (exit on error) */
-static pcre *qos_pcre_compile(char *pattern, int option) {
-  const char *errptr = NULL;
-  int erroffset;
-  pcre *pcre = pcre_compile(pattern, PCRE_DOTALL|option, &errptr, &erroffset, NULL);
-  if(pcre == NULL) {
-    fprintf(stderr, "ERROR, rule <%s> could not compile pcre at position %d,"
-            " reason: %s\n", pattern, erroffset, errptr);
+static qs_regex_t *qos_pcre_compile(apr_pool_t *pool, char *pattern, int option) {
+  qs_regex_t *preg = apr_palloc(pool, sizeof(qs_regex_t));
+  if(qs_regcomp(preg, pattern, PCRE2_DOTALL|option) != 0) {
+    fprintf(stderr, "ERROR, rule <%s> could not compile pcre\n", pattern);
     exit(1);
   }
-  return pcre;
+  apr_pool_pre_cleanup_register(pool, preg, qs_pregfree);
+  return preg;
 }
 
 /* tries to detect base64/hex patterns (mix of upper and lower case characters) */
 static char *qos_detect_b64(char *line, int silent) {
-  int ovector[QS_OVECCOUNT];
-  int rc_c = pcre_exec(pcre_b64, NULL, line, strlen(line), 0, 0, ovector, QS_OVECCOUNT);
+  qs_regmatch_t regm[QS_MAX_REG_MATCH];
+  int rc_c = qs_regexec_len(pcre_b64, line, strlen(line), QS_MAX_REG_MATCH, regm, 0);
   if(rc_c >= 0) {
     if((m_verbose > 1) && !silent) printf("  B64: %.*s\n",
-                                          ovector[1] - ovector[0], &line[ovector[0]]);
-    return &line[ovector[0]];
+                                          regm[0].rm_eo - regm[0].rm_so, &line[regm[0].rm_so]);
+    return &line[regm[0].rm_so];
   }
-  rc_c = pcre_exec(pcre_hx, NULL, line, strlen(line), 0, 0, ovector, QS_OVECCOUNT);
+  rc_c = qs_regexec_len(pcre_hx, line, strlen(line), QS_MAX_REG_MATCH, regm, 0);
   if(rc_c >= 0) {
     if((m_verbose > 1) && !silent) printf("  HX: %.*s\n",
-                                          ovector[1] - ovector[0], &line[ovector[0]]);
-    return &line[ovector[0]];
+                                          regm[0].rm_eo - regm[0].rm_so, &line[regm[0].rm_so]);
+    return &line[regm[0].rm_so];
   }
   return NULL;
 }
@@ -325,14 +323,14 @@
 }
 
 /* init global pcre */
-static void qos_init_pcre() {
+static void qos_init_pcre(apr_pool_t *pool) {
   char buf[1024];
   sprintf(buf, "%s{%d,}", QS_B64, m_base64);
-  pcre_b64 = qos_pcre_compile(buf, 0);
+  pcre_b64 = qos_pcre_compile(pool, buf, 0);
   sprintf(buf, "%s{%d,}", QS_HX, m_base64);
-  pcre_hx = qos_pcre_compile(buf, 0);
-  pcre_simple_path = qos_pcre_compile("^"QS_SIMPLE_PATH_PCRE"$", 0);
-  m_req_regex = qos_pcre_compile(QOSC_REQ, 0);
+  pcre_hx = qos_pcre_compile(pool, buf, 0);
+  pcre_simple_path = qos_pcre_compile(pool, "^"QS_SIMPLE_PATH_PCRE"$", 0);
+  m_req_regex = qos_pcre_compile(pool, QOSC_REQ, 0);
 }
 
 static void usage(char *cmd, int man) {
@@ -368,12 +366,12 @@
   qs_man_print(man, " line. The module supports both, negative and positive security\n");
   qs_man_print(man, " model. The QS_Deny* directives are used to specify request line\n");
   qs_man_print(man, " patterns which are not allowed to access the server (negative\n");
-  qs_man_print(man, " security model / blacklist). These rules are used to restrict\n");
+  qs_man_print(man, " security model / deny list). These rules are used to restrict\n");
   qs_man_print(man, " access to certain resources which should not be available to\n");
   qs_man_print(man, " users or to protect the server from malicious patterns. The\n");
-  qs_man_print(man, " QS_Permit* rules implement a positive security model (whitelist).\n");
+  qs_man_print(man, " QS_Permit* rules implement a positive security model (allow list).\n");
   qs_man_print(man, " These directives are used to define allowed request line patterns.\n");
-  qs_man_print(man, " Request which do not match any of thses patterns are not allowed\n");
+  qs_man_print(man, " Request which do not match any of these patterns are not allowed\n");
   qs_man_print(man, " to access the server.\n");
   if(man) printf("\n\n");
   qs_man_print(man, " %s is an audit log analyzer used to generate filter\n", cmd);
@@ -393,7 +391,7 @@
   qs_man_print(man, "     Input file containing request URIs.\n");
   qs_man_print(man, "     The URIs for this file have to be extracted from the servers\n");
   qs_man_print(man, "     access logs. Each line of the input file contains a request\n");
-  qs_man_print(man, "     URI consiting of a path and and query.\n");
+  qs_man_print(man, "     URI consisting of a path and and query.\n");
   printf("\n");
   printf("     Example:\n");
   qs_man_println(man, "       /aaa/index.do\n");
@@ -422,10 +420,10 @@
   qs_man_print(man, "     request URI in the input data (-i) in order to make sure not\n");
   qs_man_print(man, "     to be deleted by the rule optimisation algorithm.\n");
   qs_man_print(man, "     QS_Deny* rules from this file are used to filter request lines\n");
-  qs_man_print(man, "     which should not be used for whitelist rule generation.\n");
+  qs_man_print(man, "     which should not be used for allow list rule generation.\n");
   printf("\n");
   printf("     Example:\n");
-  qs_man_println(man, "       # manually defined whitelist rule:\n");
+  qs_man_println(man, "       # manually defined allow list rule:\n");
   qs_man_println(man, "       QS_PermitUri +view deny \"^[/a-zA-Z0-9]+/view\\?(page=[0-9]+)?$\"\n");
   qs_man_println(man, "       # filter unwanted request line patterns:\n");
   qs_man_println(man, "       QS_DenyRequestLine +printable deny \".*[\\x00-\\x19].*\"\n");
@@ -450,7 +448,7 @@
   if(man) printf("\n.TP\n");
   qs_man_print(man, "  -p\n");
   if(man) printf("\n");
-  qs_man_print(man, "     Repesents query by pcre only (no literal strings).\n");
+  qs_man_print(man, "     Represents query by pcre only (no literal strings).\n");
   if(man) printf("\n.TP\n");
   qs_man_print(man, "  -s\n");
   if(man) printf("\n");
@@ -458,7 +456,7 @@
   if(man) printf("\n.TP\n");
   qs_man_print(man, "  -m\n");
   if(man) printf("\n");
-  qs_man_print(man, "     Uses one pcre for multipe query values (recommended mode).\n");
+  qs_man_print(man, "     Uses one pcre for multiple query values (recommended mode).\n");
   if(man) printf("\n.TP\n");
   qs_man_print(man, "  -o\n");
   if(man) printf("\n");
@@ -588,7 +586,7 @@
       for(i = 0; i < apr_table_elts(rules)->nelts; i++) {
         if(i != j) {
           qs_rule_t *rs = (qs_rule_t *)entry[i].val;
-          if(pcre_exec(rs->pcre, rs->extra, line, strlen(line), 0, 0, NULL, 0) >= 0) {
+          if(qs_regexec_len(rs->pcre, line, strlen(line), 0, NULL, 0) >= 0) {
             match = 1;
             break;
           }
@@ -814,8 +812,7 @@
                                qos_qqs(pool, query_m_string, query_m_pcre, 0, 0, 0), NULL);
           }
           rule = apr_pstrcat(pool, rule, "$", NULL);
-          rs->pcre = qos_pcre_compile(rule, 0);
-          rs->extra = pcre_study(rs->pcre, 0, &errptr);
+          rs->pcre = qos_pcre_compile(pool, rule, 0);
           rs->path = r->path;
           apr_table_setn(new, rule, (char *)rs);
           if(m_verbose) {
@@ -898,7 +895,7 @@
   if((line == 0) || (strlen(line) == 0)) return 0;
   for(i = 0; i < apr_table_elts(rules)->nelts; i++) {
     qs_rule_t *rs = (qs_rule_t *)entry[i].val;
-    if(pcre_exec(rs->pcre, rs->extra, line, strlen(line), 0, 0, NULL, 0) >= 0) {
+    if(qs_regexec_len(rs->pcre, line, strlen(line), 0, NULL, 0) >= 0) {
       if(first && (apr_table_get(source_rules, entry[i].key) == NULL)) {
         apr_table_add(source_rules, entry[i].key, "");
         apr_table_add(rules_url, line, "");
@@ -918,7 +915,7 @@
   entry = (apr_table_entry_t *)apr_table_elts(special_rules)->elts;
   for(i = 0; i < apr_table_elts(special_rules)->nelts; i++) {
     qs_rule_t *rs = (qs_rule_t *)entry[i].val;
-    if(pcre_exec(rs->pcre, rs->extra, line, strlen(line), 0, 0, NULL, 0) >= 0) {
+    if(qs_regexec_len(rs->pcre, line, strlen(line), 0, NULL, 0) >= 0) {
       if(m_verbose) {
         printf("# ADD line %d: %s\n", line_nr, plain);
         printf("# -(S) %s\n", entry[i].key);
@@ -930,15 +927,15 @@
   return 0;
 }
 
-/* filter lines we don't want to add to the whitelist */
-static int qos_enforce_blacklist(apr_table_t *rules, const char *line) {
+/* filter lines we don't want to add to the allow list */
+static int qos_enforce_denylist(apr_table_t *rules, const char *line) {
   int i;
   apr_table_entry_t *entry = (apr_table_entry_t *)apr_table_elts(rules)->elts;
   if((line == 0) || (strlen(line) == 0)) return 0;
   for(i = 0; i < apr_table_elts(rules)->nelts; i++) {
     qs_rule_t *rs = (qs_rule_t *)entry[i].val;
-    if(pcre_exec(rs->pcre, rs->extra, line, strlen(line), 0, 0, NULL, 0) == 0) {
-      if(m_verbose > 1) printf(" blacklist match, rule %s\n", entry[i].key);
+    if(qs_regexec_len(rs->pcre, line, strlen(line), 0, NULL, 0) == 0) {
+      if(m_verbose > 1) printf(" deny list match, rule %s\n", entry[i].key);
       return 1;
     }
   }
@@ -977,8 +974,7 @@
             {
               const char *errptr = NULL;
               char *pattern;
-              pcre *pcre_test;
-              pcre_extra *extra;
+              qs_regex_t *pcre_test;
               qs_rule_t *rs;
               if(p[0] == '"') {
                 int fl = strlen(p)-2;
@@ -987,11 +983,9 @@
                 int fl = strlen(p);
                 pattern = apr_psprintf(pool, "%.*s", fl, p);
               }
-              pcre_test = qos_pcre_compile(pattern, option);
-              extra = pcre_study(pcre_test, 0, &errptr);
+              pcre_test = qos_pcre_compile(pool, pattern, option);
               rs = apr_pcalloc(pool, sizeof(qs_rule_t));
               rs->pcre = pcre_test;
-              rs->extra = extra;
               apr_table_setn(ruletable, pattern, (char *)rs);
             }
           }
@@ -1002,10 +996,10 @@
   fclose(f);
 }
 
-static void qos_load_blacklist(apr_pool_t *pool, apr_table_t *blacklist, const char *httpdconf) {
-  qos_load_rules(pool, blacklist, httpdconf, "QS_DenyRequestLine", PCRE_CASELESS);
+static void qos_load_denylist(apr_pool_t *pool, apr_table_t *denylist, const char *httpdconf) {
+  qos_load_rules(pool, denylist, httpdconf, "QS_DenyRequestLine", PCRE2_CASELESS);
 }
-static void qos_load_whitelist(apr_pool_t *pool, apr_table_t *rules, const char *httpdconf) {
+static void qos_load_allowlist(apr_pool_t *pool, apr_table_t *rules, const char *httpdconf) {
   qos_load_rules(pool, rules, httpdconf, "QS_PermitUri", 0);
 }
 
@@ -1114,7 +1108,7 @@
     return ret;
   } else {
     return ret;
-    /* it woud be nice to use (see -o):
+    /* it would be nice to use (see -o):
      *  ((a=b)?(c=d)?)* 
      * instead of:
      *  (a=b)?(c=d)? and (c=d)?(a=b)?
@@ -1281,8 +1275,7 @@
                 char *matchx = apr_psprintf(lpool, "[%s]{%d}", qos_2pcre(lpool, match), e-s);
                 char *new = apr_psprintf(pool, "%.*s%s%s", s, entry[i].key, matchx, &entry[i].key[e]);
                 qs_rule_t *rsn = apr_pcalloc(pool, sizeof(qs_rule_t));
-                rsn->pcre = qos_pcre_compile(new, 0);
-                rsn->extra = pcre_study(rsn->pcre, 0, &errptr);
+                rsn->pcre = qos_pcre_compile(pool, new, 0);
                 rsn->path = rs->path;
                 rsn->query_m_string = rs->query_m_string;
                 rsn->query_m_pcre = rs->query_m_pcre;
@@ -1341,18 +1334,13 @@
   char *line = *raw;
   int rc_c = -1;
   if(m_req_regex) {
-    int ovector[QS_OVECCOUNT];
+    qs_regmatch_t regm[QS_MAX_REG_MATCH];
     /* no request line, maybe raw Apache access log? */
-    rc_c = pcre_exec(m_req_regex, NULL, line, strlen(line), 0, 0, ovector, QS_OVECCOUNT);
+    rc_c = qs_regexec_len(m_req_regex, line, strlen(line), QS_MAX_REG_MATCH, regm, 0);
     if(rc_c >= 0) {
-      char *sr;
-      line = &line[ovector[0]];
-      line[ovector[1] - ovector[0]] = '\0';
-      sr = strchr(line, ' ');
-      while(sr[0] == ' ')sr++;
+      char *sr = &line[regm[2].rm_so];
+      sr[regm[2].rm_eo - regm[2].rm_so] = '\0';
       *raw = sr;
-      sr = strrchr(line, ' ');
-      sr[0] = '\0';
     }
   }
   if(rc_c < 0) {
@@ -1374,7 +1362,7 @@
 }
 
 /* process the input file line by line */
-static void qos_process_log(apr_pool_t *pool, apr_table_t *blacklist, apr_table_t *rules,
+static void qos_process_log(apr_pool_t *pool, apr_table_t *denylist, apr_table_t *rules,
                             apr_table_t *rules_url, apr_table_t *special_rules,
                             FILE *f, int *ln, int *dc, int first) {
   char *readline = apr_pcalloc(pool, MAX_BODY_BUFFER);
@@ -1403,7 +1391,7 @@
       qos_auto_detect(&line);
     }
     if(apr_uri_parse(lpool, line, &parsed_uri) != APR_SUCCESS) {
-      fprintf(stderr, "ERROR, could parse uri %s\n", line);
+      fprintf(stderr, "ERROR, could not parse uri %s\n", line);
       if(m_exit_on_error) exit(1);
     }
     if(parsed_uri.path == NULL || (parsed_uri.path[0] != '/')) {
@@ -1418,8 +1406,8 @@
       char *fragment = NULL;
       char *copy = apr_pstrdup(lpool, line);
       qos_unescaping(copy);
-      if(qos_enforce_blacklist(blacklist, copy)) {
-        fprintf(stderr, "WARNING: blacklist filter match at line %d for %s\n",
+      if(qos_enforce_denylist(denylist, copy)) {
+        fprintf(stderr, "WARNING: deny list filter match at line %d for %s\n",
                 line_nr, line);
         deny_count++;
       } else {
@@ -1454,8 +1442,9 @@
               if(m_handler) {
                 path = qos_path_pcre_string(lpool, parsed_uri.path);
               } else {
-                if(pcre_exec(pcre_simple_path, NULL, parsed_uri.path,
-                             strlen(parsed_uri.path), 0, 0, NULL, 0) >= 0) {
+                if(qs_regexec_len(pcre_simple_path,
+                                  parsed_uri.path, strlen(parsed_uri.path),
+                                  0, NULL, 0) >= 0) {
                   path = apr_pstrdup(lpool, QS_SIMPLE_PATH_PCRE);
                 } else {
                   path = qos_path_pcre(lpool, parsed_uri.path);
@@ -1503,8 +1492,7 @@
               rs->fragment = 0;
             }
             rule = apr_pstrcat(pool, rule, "$", NULL);
-            rs->pcre = qos_pcre_compile(rule, 0);
-            rs->extra = pcre_study(rs->pcre, 0, &errptr);
+            rs->pcre = qos_pcre_compile(pool, rule, 0);
             rs->path = apr_pstrdup(pool, path);
             if(m_query_multi_pcre && !fragment) {
               rs->query_m_string = apr_pstrdup(pool, query_m_string);
@@ -1519,7 +1507,7 @@
               printf("# %.3d %s\n", apr_table_elts(rules)->nelts+1, rule);
               fflush(stdout);
             }
-            if(pcre_exec(rs->pcre, rs->extra, copy, strlen(copy), 0, 0, NULL, 0) < 0) {
+            if(qs_regexec_len(rs->pcre, copy, strlen(copy), 0, NULL, 0) < 0) {
               fprintf(stderr, "ERROR, rule check failed (did not match)!\n");
               fprintf(stderr, " line %d: %s\n", line_nr, line);
               fprintf(stderr, " string: %s\n", copy);
@@ -1562,7 +1550,7 @@
   *ln = line_nr;
 }
 
-static void qos_measurement(apr_pool_t *pool, apr_table_t *blacklist, apr_table_t *rules, FILE *f, int *ln) {
+static void qos_measurement(apr_pool_t *pool, apr_table_t *denylist, apr_table_t *rules, FILE *f, int *ln) {
   char *readline = apr_pcalloc(pool, MAX_BODY_BUFFER);
   int line_nr = 0;
   while(!qos_fgetline(readline, MAX_BODY_BUFFER, f)) {
@@ -1590,7 +1578,7 @@
       qos_unescaping(copy);
       for(i = 0; i < apr_table_elts(rules)->nelts; i++) {
         qs_rule_t *rs = (qs_rule_t *)entry[i].val;
-        pcre_exec(rs->pcre, NULL, copy, strlen(copy), 0, 0, NULL, 0);
+        qs_regexec_len(rs->pcre, copy, strlen(copy), 0, NULL, 0);
       }
     }
     apr_pool_destroy(lpool);
@@ -1612,17 +1600,17 @@
   apr_pool_t *pool;
   apr_table_t *rules;
   apr_table_t *special_rules;
-  apr_table_t *blacklist;
+  apr_table_t *denylist;
   apr_table_t *rules_url;
-  int blacklist_size = 0;
-  int whitelist_size = 0;
+  int denylist_size = 0;
+  int allowlist_size = 0;
   char *cmd = strrchr(argv[0], '/');
   const char *httpdconf = NULL;
   apr_app_initialize(&argc, &argv, NULL);
   apr_pool_create(&pool, NULL);
   rules = apr_table_make(pool, 10);
   special_rules = apr_table_make(pool, 10);
-  blacklist = apr_table_make(pool, 10);
+  denylist = apr_table_make(pool, 10);
   rules_url = apr_table_make(pool, 10);
   rc = nice(10);
   if(rc == -1) {
@@ -1710,7 +1698,7 @@
     argc--;
     argv++;
   }
-  qos_init_pcre();
+  qos_init_pcre(pool);
 
   if((m_query_pcre && m_query_multi_pcre) ||
      (m_query_pcre && m_query_single_pcre) ||
@@ -1723,10 +1711,10 @@
   }
 
   if(httpdconf) {
-    qos_load_blacklist(pool, blacklist, httpdconf);
-    blacklist_size = apr_table_elts(blacklist)->nelts;
-    qos_load_whitelist(pool, rules, httpdconf);
-    whitelist_size = apr_table_elts(rules)->nelts;
+    qos_load_denylist(pool, denylist, httpdconf);
+    denylist_size = apr_table_elts(denylist)->nelts;
+    qos_load_allowlist(pool, rules, httpdconf);
+    allowlist_size = apr_table_elts(rules)->nelts;
   }
 
   if(access_log == NULL) usage(cmd, 0);
@@ -1735,7 +1723,7 @@
     fprintf(stderr, "ERROR, could not open input file %s\n", access_log);
     exit(1);
   }
-  qos_process_log(pool, blacklist, rules, rules_url, special_rules, f, &line_nr, &deny_count, 1);
+  qos_process_log(pool, denylist, rules, rules_url, special_rules, f, &line_nr, &deny_count, 1);
   fclose(f);
 
   if(m_redundant) {
@@ -1749,10 +1737,10 @@
       fflush(stdout);
     }
     //    if(httpdconf) {
-    //      qos_load_whitelist(pool, rules, httpdconf);
+    //      qos_load_allowlist(pool, rules, httpdconf);
     //    }
     f = fopen(access_log, "r");
-    qos_process_log(pool, blacklist, rules, rules_url, special_rules, f, &xl, &y, 0);
+    qos_process_log(pool, denylist, rules, rules_url, special_rules, f, &xl, &y, 0);
     fclose(f);
   }
 
@@ -1761,7 +1749,7 @@
     apr_time_t tv;
     f = fopen(access_log, "r");
     tv = apr_time_now();
-    qos_measurement(pool, blacklist, rules, f, &lx);
+    qos_measurement(pool, denylist, rules, f, &lx);
     tv = apr_time_now() - tv;
     performance = apr_time_msec(tv) + (apr_time_sec(tv) * 1000);
     performance = performance / lx;
@@ -1804,9 +1792,9 @@
   printf("#  exit on error (-e): %s\n", m_exit_on_error == 1 ? "yes" : "no");
   printf("#  rule file (-c): %s\n", httpdconf == NULL ? "-" : httpdconf);
   if(httpdconf) {
-    printf("#    whitelist (loaded existing rules): %d\n", whitelist_size);
-    printf("#    blacklist (loaded deny rules): %d\n", blacklist_size);
-    printf("#    blacklist matches: %d\n", deny_count);
+    printf("#    allow list (loaded existing rules): %d\n", allowlist_size);
+    printf("#    deny list (loaded deny rules): %d\n", denylist_size);
+    printf("#    deny list matches: %d\n", deny_count);
   }
   printf("#  duration: %ld minutes\n", (end - start) / 60);
   printf("# --------------------------------------------------------\n");
diff -Nru libapache2-mod-qos-11.63/tools/src/qsgeo.c libapache2-mod-qos-11.74/tools/src/qsgeo.c
--- libapache2-mod-qos-11.63/tools/src/qsgeo.c	2019-05-25 09:08:59.000000000 -0400
+++ libapache2-mod-qos-11.74/tools/src/qsgeo.c	2023-05-18 08:34:25.000000000 -0400
@@ -8,7 +8,7 @@
  * See http://mod-qos.sourceforge.net/ for further
  * details.
  *
- * Copyright (C) 2019 Pascal Buchbinder
+ * Copyright (C) 2023 Pascal Buchbinder
  *
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -27,7 +27,7 @@
  *
  */
 
-static const char revision[] = "$Id: qsgeo.c 2542 2019-02-22 06:37:10Z pbuchbinder $";
+static const char revision[] = "$Id: qsgeo.c 2654 2022-05-13 09:12:42Z pbuchbinder $";
 
 #include <stdio.h>
 #include <stdlib.h>
@@ -39,7 +39,6 @@
 #include <regex.h>
 
 /* apr */
-#include <pcre.h>
 #include <apr.h>
 #include <apr_strings.h>
 #include <apr_file_io.h>
@@ -58,7 +57,7 @@
 // "3758096128","3758096383","AU","Australia"
 #define QS_GEO_PATTERN_D "\"([0-9]+)\",\"([0-9]+)\",\"([A-Z0-9]{2})\",\"(.*)\""
 // "192.83.198.0","192.83.198.255","3226715648","3226715903","AU","Australia"
-#define QS_GEO_PATTERN_EXT  "\"[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+\",\"[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+\",\"([0-9]+)\",\"([0-9]+)\",\"([A-Z0-9]{2})\",\"(.*)\""
+#define QS_GEO_PATTERN_EXT  "\"[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+\",\"[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+\",\"([0-9]+)\",\"([0-9]+)\",\"([A-Z0-9]{2})\""
 // 182.12.34.23
 #define IPPATTERN "([0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3})[\"'\x0d\x0a, ]+"
 #define IPPATTERN2 "([0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3})[\"'\x0d\x0a,; ]+"
diff -Nru libapache2-mod-qos-11.63/tools/src/qsgrep.c libapache2-mod-qos-11.74/tools/src/qsgrep.c
--- libapache2-mod-qos-11.63/tools/src/qsgrep.c	2019-05-25 09:08:59.000000000 -0400
+++ libapache2-mod-qos-11.74/tools/src/qsgrep.c	2023-05-18 08:34:25.000000000 -0400
@@ -7,7 +7,7 @@
  *
  * See http://mod-qos.sourceforge.net/ for further details.
  *
- * Copyright (C) 2019 Pascal Buchbinder
+ * Copyright (C) 2023 Pascal Buchbinder
  *
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -26,7 +26,7 @@
  *
  */
 
-static const char revision[] = "$Id: qsgrep.c 2542 2019-02-22 06:37:10Z pbuchbinder $";
+static const char revision[] = "$Id: qsgrep.c 2654 2022-05-13 09:12:42Z pbuchbinder $";
 
 /* system */
 #include <stdio.h>
@@ -38,7 +38,6 @@
 #include <time.h>
 
 /* apr */
-#include <pcre.h>
 #include <apr.h>
 #include <apr_strings.h>
 #include <apr_file_io.h>
@@ -49,12 +48,15 @@
 #include <apr_portable.h>
 #include <apr_support.h>
 
+#define PCRE2_CODE_UNIT_WIDTH 8
+#include <pcre2.h>
+
 #include "qs_util.h"
 
 #ifndef POSIX_MALLOC_THRESHOLD
 #define POSIX_MALLOC_THRESHOLD (10)
 #endif
-#define MAX_REG_MATCH 10
+
 /* same as APR_SIZE_MAX which doesn't appear until APR 1.3 */
 #define QSUTIL_SIZE_MAX (~((apr_size_t)0))
 
@@ -97,7 +99,7 @@
   if(man) printf(".TP\n");
   qs_man_print(man, "  -e <pattern>\n");
   if(man) printf("\n");
-  qs_man_print(man, "     Specifes the search pattern.\n");
+  qs_man_print(man, "     Specifies the search pattern.\n");
   if(man) printf("\n.TP\n");
   qs_man_print(man, "  -o <string>\n");
   if(man) printf("\n");
@@ -140,7 +142,7 @@
  */
 char *qs_pregsub(apr_pool_t *pool, const char *input,
 		 const char *source, size_t nmatch,
-		 regmatch_t pmatch[]) {
+		 qs_regmatch_t pmatch[]) {
   const char *src = input;
   char *dest, *dst;
   char c;
@@ -202,41 +204,6 @@
   return dest;
 }
 
-int qs_regexec(pcre *preg, const char *string,
-	       apr_size_t nmatch, regmatch_t pmatch[]) {
-  int rc;
-  int options = 0;
-  int *ovector = NULL;
-  int small_ovector[POSIX_MALLOC_THRESHOLD * 3];
-  int allocated_ovector = 0;
-  if (nmatch > 0) {
-    if (nmatch <= POSIX_MALLOC_THRESHOLD) {
-      ovector = &(small_ovector[0]);
-    } else {
-      ovector = (int *)malloc(sizeof(int) * nmatch * 3);
-      if (ovector == NULL) {
-	return 1;
-      }
-      allocated_ovector = 1;
-    }
-  }
-  rc = pcre_exec(preg, NULL, string, (int)strlen(string), 0, options, ovector, nmatch * 3);
-  if (rc == 0) rc = nmatch;    /* All captured slots were filled in */
-  if (rc >= 0) {
-    apr_size_t i;
-    for (i = 0; i < (apr_size_t)rc; i++) {
-      pmatch[i].rm_so = ovector[i*2];
-      pmatch[i].rm_eo = ovector[i*2+1];
-    }
-    if (allocated_ovector) free(ovector);
-    for (; i < nmatch; i++) pmatch[i].rm_so = pmatch[i].rm_eo = -1;
-    return 0;
-  } else {
-    if (allocated_ovector) free(ovector);
-    return rc;
-  }
-}
-
 int main(int argc, const char * const argv[]) {
   unsigned long nr = 0;
   char line[32768];
@@ -246,10 +213,8 @@
   const char *out = NULL;
   const char *pattern = NULL;
   const char *filename = NULL;
-  pcre *preg;
-  const char *errptr = NULL;
-  int erroffset;
-  regmatch_t regm[MAX_REG_MATCH];
+  qs_regex_t *preg;
+  qs_regmatch_t regm[QS_MAX_REG_MATCH];
   apr_app_initialize(&argc, &argv, NULL);
   apr_pool_create(&pool, NULL);
 
@@ -293,12 +258,12 @@
     fprintf(stderr, "ERROR, failed to change nice value: %s\n", strerror(errno));
   }
 
-  preg = pcre_compile(pattern, PCRE_DOTALL, &errptr, &erroffset, NULL);
-  if(!preg) {
-    fprintf(stderr, "ERROR, could not compile '%s' at position %d, reason: %s\n",
-	    pattern, erroffset, errptr);
+  preg = apr_palloc(pool, sizeof(qs_regex_t));
+  if(qs_regcomp(preg, pattern, PCRE2_DOTALL) != 0) {
+    fprintf(stderr, "ERROR, could not compile '%s\n", pattern);
     exit(1);
   }
+  apr_pool_pre_cleanup_register(pool, preg, qs_pregfree);
 
   if(filename) {
     file = fopen(filename, "r");
@@ -311,16 +276,20 @@
   }
     
   while(fgets(line, sizeof(line), file) != NULL) {
+    size_t len = strlen(line);
     nr++;
-    if(qs_regexec(preg, line, MAX_REG_MATCH, regm) == 0) {
-      char *replaced = qs_pregsub(pool, out, line, MAX_REG_MATCH, regm);
+    if(qs_regexec_len(preg, line, len, QS_MAX_REG_MATCH, regm, 0) >= 0) {
+      apr_pool_t *subpool;
+      char *replaced;
+      apr_pool_create(&subpool, pool);
+      replaced = qs_pregsub(subpool, out, line, QS_MAX_REG_MATCH, regm);
       if(!replaced) {
 	fprintf(stderr, "ERROR, failed to substitute submatches (line=%lu)\n", nr);
       } else {
 	printf("%s\n", replaced);
         fflush(stdout);
       }
-      apr_pool_clear(pool);
+      apr_pool_destroy(subpool);
     }
   }
 
diff -Nru libapache2-mod-qos-11.63/tools/src/qshead.c libapache2-mod-qos-11.74/tools/src/qshead.c
--- libapache2-mod-qos-11.63/tools/src/qshead.c	2019-05-25 09:08:59.000000000 -0400
+++ libapache2-mod-qos-11.74/tools/src/qshead.c	2023-05-18 08:34:25.000000000 -0400
@@ -8,7 +8,7 @@
  * See http://mod-qos.sourceforge.net/ for further
  * details.
  *
- * Copyright (C) 2019 Pascal Buchbinder
+ * Copyright (C) 2023 Pascal Buchbinder
  *
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -27,13 +27,12 @@
  *
  */
 
-static const char revision[] = "$Id: qshead.c 2542 2019-02-22 06:37:10Z pbuchbinder $";
+static const char revision[] = "$Id: qshead.c 2654 2022-05-13 09:12:42Z pbuchbinder $";
 
 #include <stdio.h>
 #include <unistd.h>
 #include <string.h>
 #include <stdlib.h>
-#include <regex.h>
 #include <signal.h>
 
 #include "qs_util.h"
@@ -62,7 +61,7 @@
   } else {
     printf("Summary\n");
   }
-  qs_man_print(man, " %s reads lines from stdin and prints them to stdout unitl a line contains\n", cmd);
+  qs_man_print(man, " %s reads lines from stdin and prints them to stdout until a line contains\n", cmd);
   qs_man_print(man, " the specified pattern (literal string).\n");
   printf("\n");
   if(man) {
diff -Nru libapache2-mod-qos-11.63/tools/src/qslog.c libapache2-mod-qos-11.74/tools/src/qslog.c
--- libapache2-mod-qos-11.63/tools/src/qslog.c	2019-05-25 09:08:59.000000000 -0400
+++ libapache2-mod-qos-11.74/tools/src/qslog.c	2023-05-18 08:34:25.000000000 -0400
@@ -9,7 +9,7 @@
  * See http://mod-qos.sourceforge.net/ for further
  * details.
  *
- * Copyright (C) 2019 Pascal Buchbinder
+ * Copyright (C) 2023 Pascal Buchbinder
  *
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -28,7 +28,7 @@
  *
  */
 
-static const char revision[] = "$Id: qslog.c 2542 2019-02-22 06:37:10Z pbuchbinder $";
+static const char revision[] = "$Id: qslog.c 2654 2022-05-13 09:12:42Z pbuchbinder $";
 
 #include <stdio.h>
 #include <string.h>
@@ -45,14 +45,15 @@
 #include <regex.h>
 #include <time.h>
 
-#include <pcre.h>
-
 /* apr */
 #include <apr.h>
 #include <apr_portable.h>
 #include <apr_support.h>
 #include <apr_strings.h>
 
+#define PCRE2_CODE_UNIT_WIDTH 8
+#include <pcre2.h>
+
 #include "qs_util.h"
 
 /* ----------------------------------
@@ -68,7 +69,7 @@
 #define NUM_EVENT_TABLES   8
 #define QS_GENERATIONS 14
 #define EVENT_DELIM ','
-#define QSEVENTPATH "QSEVENTPATH" /* varibale name to find event definitions */
+#define QSEVENTPATH "QSEVENTPATH" /* variable name to find event definitions */
 #define QSCOUNTERPATH "QSCOUNTERPATH" /* counter rule definitions */
 #define COUNTER_PATTERN "([a-zA-Z0-9_]+):([a-zA-Z0-9_]+)[-]([0-9]+)[*]([a-zA-Z0-9_]+)[/]([0-9]+)=([0-9]+)"
 
@@ -312,10 +313,10 @@
 }
 
 /**
- * Inserts an event entry and delets expired.
+ * Inserts an event entry and deletes expired.
  *
  * @param l_qs_event Pointer to the event list.
- * @param id Identifer, e.g. IP address or user tracking cookie
+ * @param id Identifier, e.g. IP address or user tracking cookie
  * @param type which counter is used (either 'I' or 'U')
  * @return event counter (number of updates) for the provided id
  */
@@ -439,7 +440,7 @@
 
 /**
  * Helper to print an error message when terminating
- * the programm due to an unexpected error.
+ * the program due to an unexpected error.
  */
 static void qerror(const char *fmt,...) {
   char buf[MAX_LINE];
@@ -977,7 +978,7 @@
     }
     E = sep;
     if(restore) {
-      // suports multiple parsing of the event string
+      // supports multiple parsing of the event string
       restore[0] = EVENT_DELIM;
     }
   }
@@ -990,31 +991,28 @@
 static void qsInitCounter(apr_pool_t *pool, apr_table_t *counters) {
   const char *envFile = getenv(QSCOUNTERPATH);
   if(envFile != NULL) {
-    const char *errptr = NULL;
-    int erroffset;
-    int ovector[100];
-    pcre *pcrestat = pcre_compile(COUNTER_PATTERN, PCRE_CASELESS, &errptr, &erroffset, NULL);
+    qs_regmatch_t regm[QS_MAX_REG_MATCH];
+    qs_regex_t *pcrestat = apr_palloc(pool, sizeof(qs_regex_t));
     FILE *file = fopen(envFile, "r"); 
+    if(qs_regcomp(pcrestat, COUNTER_PATTERN, PCRE2_CASELESS) != 0) {
+      fprintf(stderr, "ERROR, could not compile '%s'\n", COUNTER_PATTERN);
+      exit(1);
+    }
+    apr_pool_pre_cleanup_register(pool, pcrestat, qs_pregfree);
     if(file != NULL) {
       char line[MAX_LINE];
       while(!qs_getLinef(line, sizeof(line), file)) {
-        if(pcre_exec(pcrestat, NULL, line, strlen(line), 0, 0, ovector, 100) >= 0) {
+        if(qs_regexec_len(pcrestat, line, strlen(line), QS_MAX_REG_MATCH, regm, 0) >= 0) {
           counter_rec_t *c = apr_pcalloc(pool, sizeof(counter_rec_t));
-          line[ovector[2] + ovector[3] - ovector[2]] = '\0';
-          line[ovector[4] + ovector[5] - ovector[4]] = '\0';
-          line[ovector[6] + ovector[7] - ovector[6]] = '\0';
-          line[ovector[8] + ovector[9] - ovector[8]] = '\0';
-          line[ovector[10] + ovector[11] - ovector[10]] = '\0';
- 
-          c->name = apr_pstrdup(pool, &line[ovector[2]]);
+          c->name = apr_pstrndup(pool, &line[regm[1].rm_so], regm[1].rm_eo - regm[1].rm_so);
           c->count = 0;
           c->total = 0;
           c->start = 0;
-          c->inc = apr_pstrdup(pool, &line[ovector[4]]);
-          c->decVal = atoi(&line[ovector[6]]);
-          c->dec = apr_pstrdup(pool, &line[ovector[8]]);
-          c->duration = atoi(&line[ovector[10]]);
-          c->limit = atoi(&line[ovector[12]]);
+          c->inc = apr_pstrndup(pool, &line[regm[2].rm_so], regm[2].rm_eo - regm[2].rm_so);
+          c->decVal = atoi(apr_pstrndup(pool, &line[regm[3].rm_so], regm[3].rm_eo - regm[3].rm_so));
+          c->dec = apr_pstrndup(pool, &line[regm[4].rm_so], regm[4].rm_eo - regm[4].rm_so);
+          c->duration = atoi(apr_pstrndup(pool, &line[regm[5].rm_so], regm[5].rm_eo - regm[5].rm_so));
+          c->limit = atoi(apr_pstrndup(pool, &line[regm[6].rm_so], regm[6].rm_eo - regm[6].rm_so));
           if(m_verbose) {
             fprintf(stderr, "%s : %s - (%d * %s) / %d = %d\n",
                     c->name, c->inc, c->decVal, c->dec, c->duration, c->limit);
@@ -1599,7 +1597,7 @@
   char *k = NULL; /* connections (keep alive requests = 0) */
   char *C = NULL; /* custom patter matching the config file */
   char *s = NULL; /* sum */
-  char *a = NULL; /* avarage 1 */
+  char *a = NULL; /* average 1 */
   char *A = NULL; /* average 2 */
   char *M = NULL; /* max */
   char *E = NULL; /* events */
@@ -2086,7 +2084,7 @@
   qs_man_println(man, "  - number of requests within measured time (req)\n");
   qs_man_println(man, "  - bytes sent to the client per second ("NBS")\n");
   qs_man_println(man, "  - bytes received from the client per second ("NBIS")\n");
-  qs_man_println(man, "  - repsonse status codes within the last minute (1xx,2xx,3xx,4xx,5xx)\n");
+  qs_man_println(man, "  - response status codes within the last minute (1xx,2xx,3xx,4xx,5xx)\n");
   qs_man_println(man, "  - average response duration ("NAV")\n");
   qs_man_println(man, "  - average response duration in milliseconds ("NAVMS")\n");
   qs_man_println(man, "  - distribution of response durations in seconds within the last minute\n");
@@ -2118,7 +2116,7 @@
   qs_man_print(man, "     Defines the log data format and the positions of data\n");
   qs_man_print(man, "     elements processed by this utility.\n");
   qs_man_print(man, "     See to the 'LogFormat' directive of the httpd.conf file\n");
-  qs_man_print(man, "     to see the format defintions of the servers access log data.\n");
+  qs_man_print(man, "     to see the format definitions of the servers access log data.\n");
   if(man) printf("\n");
   qs_man_println(man, "     %s knows the following elements:\n", cmd);
   qs_man_println(man, "     I defines the client ip address (%%h)\n");
@@ -2179,7 +2177,7 @@
   if(man) printf("\n.TP\n");
   qs_man_print(man, "  -c <path>\n");
   if(man) printf("\n");
-  qs_man_print(man, "     Enables the collection of log statitics for different request types.\n");
+  qs_man_print(man, "     Enables the collection of log statistics for different request types.\n");
   qs_man_print(man, "     'path' specifies the necessary rule file. Each rule consists of a rule\n");
   qs_man_print(man, "     identifier and a regular expression to identify a request seprarated\n");
   qs_man_print(man, "     by a colon, e.g., 01:^(/a)|(/c). The regular expressions are matched against\n");
diff -Nru libapache2-mod-qos-11.63/tools/src/qslogger.c libapache2-mod-qos-11.74/tools/src/qslogger.c
--- libapache2-mod-qos-11.63/tools/src/qslogger.c	2019-05-25 09:08:59.000000000 -0400
+++ libapache2-mod-qos-11.74/tools/src/qslogger.c	2023-05-18 08:34:25.000000000 -0400
@@ -8,7 +8,7 @@
  * See http://mod-qos.sourceforge.net/ for further
  * details.
  *
- * Copyright (C) 2019 Pascal Buchbinder
+ * Copyright (C) 2023 Pascal Buchbinder
  *
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -27,7 +27,7 @@
  *
  */
 
-static const char revision[] = "$Id: qslogger.c 2542 2019-02-22 06:37:10Z pbuchbinder $";
+static const char revision[] = "$Id: qslogger.c 2654 2022-05-13 09:12:42Z pbuchbinder $";
 
 #include <stdio.h>
 #include <stdlib.h>
@@ -52,7 +52,7 @@
 static int m_default_severity = LOG_NOTICE;
 
 /**
- * Similar to standard strstr() but case insensitive and lenght limitation
+ * Similar to standard strstr() but case insensitive and length limitation
  * (string which is not 0 terminated).
  *
  * @param s1 String to search in
@@ -135,7 +135,7 @@
  * regular expression and determinest the priofity using
  * qsgetprio().
  *
- * @param preg Regular expression to extract the serverity
+ * @param preg Regular expression to extract the severity
  * @param line Log fline to extract the severity from
  * @return Level or LOG_NOTICE (see m_default_severity) if level could not be determined.
  */
@@ -264,7 +264,7 @@
   qs_man_print(man, "  -l <level>\n");
   if(man) printf("\n");
   qs_man_print(man, "     Defines the minimal severity a message must have in order to\n");
-  qs_man_print(man, "     be forwarded. Default is 'DEBUG' (fowarding everything).\n");
+  qs_man_print(man, "     be forwarded. Default is 'DEBUG' (forwarding everything).\n");
   if(man) printf("\n.TP\n");
   qs_man_print(man, "  -x <prefix>\n");
   if(man) printf("\n");
@@ -284,7 +284,7 @@
   qs_man_print(man, "  -d <level>\n");
   if(man) printf("\n");
   qs_man_print(man, "     The default severity if the specified pattern (-r) does not\n");
-  qs_man_print(man, "     match and the message's serverity can't be determined. Default\n");
+  qs_man_print(man, "     match and the message's severity can't be determined. Default\n");
   qs_man_print(man, "     is 'NOTICE'.\n");
   if(man) printf("\n.TP\n");
   qs_man_print(man, "  -p\n");
diff -Nru libapache2-mod-qos-11.63/tools/src/qspng.c libapache2-mod-qos-11.74/tools/src/qspng.c
--- libapache2-mod-qos-11.63/tools/src/qspng.c	2019-05-25 09:08:59.000000000 -0400
+++ libapache2-mod-qos-11.74/tools/src/qspng.c	2023-05-18 08:34:25.000000000 -0400
@@ -6,7 +6,7 @@
  * See http://mod-qos.sourceforge.net/ for further
  * details.
  *
- * Copyright (C) 2019 Pascal Buchbinder
+ * Copyright (C) 2023 Pascal Buchbinder
  *
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -25,7 +25,7 @@
  *
  */
 
-static const char revision[] = "$Id: qspng.c 2542 2019-02-22 06:37:10Z pbuchbinder $";
+static const char revision[] = "$Id: qspng.c 2654 2022-05-13 09:12:42Z pbuchbinder $";
 
 #include <stdio.h>
 #include <string.h>
@@ -76,17 +76,17 @@
   { "4s", "requests with 4 seconds response time", 25, 95, 180 },
   { "5s", "requests with 5 seconds response time", 15, 90, 180 },
   { ">5s","requests slower than 5 seconds", 35, 90, 185 },
-  { "1xx","requets with HTTP status 1xx",   50, 70, 150 },
-  { "2xx","requets with HTTP status 2xx",   50, 70, 150 },
-  { "3xx","requets with HTTP status 3xx",   50, 70, 150 },
-  { "4xx","requets with HTTP status 4xx",   50, 70, 150 },
-  { "5xx","requets with HTTP status 5xx",   50, 70, 150 },
+  { "1xx","requests with HTTP status 1xx",   50, 70, 150 },
+  { "2xx","requests with HTTP status 2xx",   50, 70, 150 },
+  { "3xx","requests with HTTP status 3xx",   50, 70, 150 },
+  { "4xx","requests with HTTP status 4xx",   50, 70, 150 },
+  { "5xx","requests with HTTP status 5xx",   50, 70, 150 },
   { "ip", "IP addresses",          55, 60, 150 },
   { "usr","active users",          55, 66, 150 },
   { "qV", "created VIP sessions",  55, 50, 155 },
   { "qS", "session pass",          55, 75, 160 },
   { "qD", "access denied",         55, 70, 170 },
-  { "qK", "conection closed",      55, 60, 145 },
+  { "qK", "connection closed",      55, 60, 145 },
   { "qT", "dynamic keep-alive",    55, 55, 153 },
   { "qL", "slow down",             55, 65, 140 },
   { "qA", "connection aborts",     55, 50, 175 },
@@ -400,7 +400,7 @@
  * "Main" png function:
  * - reads the data from the file
  * - draws the curve
- * - lables the x axis
+ * - labels the x axis
  *
  * @param width IN size (x axis) of the graph
  * @param height IN size (y axis) of the graph
@@ -426,14 +426,14 @@
   char line[HUGE_STRING_LEN];
 
   long peak = 0;           // max of all values
-  double scale = 1;        // scaling factor (heigth x scale = unit)
+  double scale = 1;        // scaling factor (height x scale = unit)
 
   int hour = -1;           // detect "new" hour
-  char date_str[32] = "";  // sting storing the first day (if fist value is at 00h)
+  char date_str[32] = "";  // string storing the first day (if fist value is at 00h)
 
   long ret;
   for(x=0; x<width; x++) hours[x] = 0;
-  /* reads the file and resample measure points to witdh of the graph */
+  /* reads the file and resample measure points to width of the graph */
   while(!qs_png_getline(line, sizeof(line), stat_log) && i < width) {
     char *p = strstr(line, name);
     req[i] = 0;
@@ -486,7 +486,7 @@
       sample++;
     }
   }
-  /* calculate y axis scaling (1:1 are heigth pixels) */
+  /* calculate y axis scaling (1:1 are height pixels) */
   if(peak < 10) {
     scale = 0.1;
   } else {
diff -Nru libapache2-mod-qos-11.63/tools/src/qsre.c libapache2-mod-qos-11.74/tools/src/qsre.c
--- libapache2-mod-qos-11.63/tools/src/qsre.c	2019-05-25 09:08:59.000000000 -0400
+++ libapache2-mod-qos-11.74/tools/src/qsre.c	2023-05-18 08:34:25.000000000 -0400
@@ -4,7 +4,7 @@
  * See http://mod-qos.sourceforge.net/ for further
  * details.
  *
- * Copyright (C) 2019 Pascal Buchbinder
+ * Copyright (C) 2023 Pascal Buchbinder
  *
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -23,7 +23,7 @@
  *
  */
 
-static const char revision[] = "$Id: qsre.c 2542 2019-02-22 06:37:10Z pbuchbinder $";
+static const char revision[] = "$Id: qsre.c 2654 2022-05-13 09:12:42Z pbuchbinder $";
 
 /* system */
 #include <stdio.h>
@@ -34,7 +34,6 @@
 #include <time.h>
 
 /* apr */
-#include <pcre.h>
 #include <apr.h>
 #include <apr_strings.h>
 #include <apr_time.h>
@@ -43,6 +42,9 @@
 #include <apr_portable.h>
 #include <apr_support.h>
 
+#define PCRE2_CODE_UNIT_WIDTH 8
+#include <pcre2.h>
+
 #include "qs_util.h"
 
 #define QS_OVECCOUNT 100
@@ -87,7 +89,7 @@
   if(man) printf(".TP\n");
   qs_man_print(man, "  <string>|<path>\n");
   if(man) printf("\n");
-  qs_man_print(man, "     The first argument either defines a sinlge test string of a path to\n");
+  qs_man_print(man, "     The first argument either defines a single test string of a path to\n");
   qs_man_print(man, "     a file containing either multiple test strings or a test pattern with\n");
   qs_man_print(man, "     newline characters (text).\n");
   if(man) printf("\n.TP\n");
@@ -112,22 +114,19 @@
   }
 }
 
-static int rmatch(const char *line, pcre *pcre) {
-  int ovector[QS_OVECCOUNT];
+static int rmatch(const char *line, qs_regex_t *preg) {
+  qs_regmatch_t regm[QS_MAX_REG_MATCH];
   int rc_c = -1;
   do {
-    int rc = pcre_exec(pcre, NULL, line, strlen(line), 0, 0, ovector, QS_OVECCOUNT);
+    int rc = qs_regexec_len(preg, line, strlen(line), QS_MAX_REG_MATCH, regm, 0);
     if(rc >= 0) {
       int ix;
       rc_c = 0;
-      printf("[%.*s]", ovector[1] - ovector[0], &line[ovector[0]]);
+      printf("[%.*s]", regm[0].rm_eo - regm[0].rm_so, &line[regm[0].rm_so]);
       for(ix = 1; ix < rc; ix++) {
-	printf(" $%d=%.*s", ix, ovector[ix*2+1] - ovector[ix*2], &line[ovector[ix*2]]);
-      }
-      line = &line[ovector[1]];
-      if(ovector[1] - ovector[0] == 0) {
-	line++;
+	printf(" $%d=%.*s", ix, regm[ix].rm_eo - regm[ix].rm_so, &line[regm[ix].rm_so]);
       }
+      line = &line[regm[0].rm_eo];
     } else {
       line = NULL;
     }
@@ -138,7 +137,7 @@
 int main(int argc, const char *const argv[]) {
   const char *errptr = NULL;
   int erroffset;
-  pcre *pcre;
+  qs_regex_t *preg;
   int rc_c = -1;
   const char *line;
   const char *in;
@@ -152,7 +151,6 @@
 
   apr_app_initialize(&argc, &argv, NULL);
   apr_pool_create(&pool, NULL);
-
   if(cmd == NULL) {
     cmd = (char *)argv[0];
   } else {
@@ -186,12 +184,12 @@
   }
   printf("expression: %s\n", pattern);
 
-  pcre = pcre_compile(pattern, PCRE_DOTALL|PCRE_CASELESS, &errptr, &erroffset, NULL);
-  if(pcre == NULL) {
-    fprintf(stderr, "ERROR, rule <%s> could not compile pcre at position %d,"
-	    " reason: %s\n", pattern, erroffset, errptr);
+  preg = apr_palloc(pool, sizeof(qs_regex_t));
+  if(qs_regcomp(preg, pattern, PCRE2_DOTALL|PCRE2_CASELESS) != 0) {
+    fprintf(stderr, "ERROR, rule <%s> could not compile regular expression\n", pattern);
     exit(1);
   }
+  apr_pool_pre_cleanup_register(pool, preg, qs_pregfree);
 
   file = fopen(in, "r");
   if(file) {
@@ -207,17 +205,17 @@
       }
       if(readline[0] >= 32 && strlen(readline) > 0) {
 	line = readline;
-	rc_c = rmatch(line, pcre);
+	rc_c = rmatch(line, preg);
       }
       printf("\n");
     }
     fclose(file);
     printf("entire content match:\n");
-    rc_c = rmatch(raw, pcre);
+    rc_c = rmatch(raw, preg);
     printf("\n");
   } else {
     line = in;
-    rc_c = rmatch(line, pcre);
+    rc_c = rmatch(line, preg);
     printf("\n");
   }
   if(rc_c < 0) {
diff -Nru libapache2-mod-qos-11.63/tools/src/qsrespeed.c libapache2-mod-qos-11.74/tools/src/qsrespeed.c
--- libapache2-mod-qos-11.63/tools/src/qsrespeed.c	2019-05-25 09:08:59.000000000 -0400
+++ libapache2-mod-qos-11.74/tools/src/qsrespeed.c	2023-05-18 08:34:25.000000000 -0400
@@ -7,7 +7,7 @@
  * See http://mod-qos.sourceforge.net/ for further
  * details.
  *
- * Copyright (C) 2019 Pascal Buchbinder
+ * Copyright (C) 2023 Pascal Buchbinder
  *
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -26,7 +26,7 @@
  *
  */
 
-static const char revision[] = "$Revision: 2542 $";
+static const char revision[] = "$Revision: 2654 $";
 
 /* system */
 #include <stdio.h>
@@ -37,7 +37,6 @@
 #include <time.h>
 
 /* apr */
-#include <pcre.h>
 #include <apr.h>
 #include <apr_strings.h>
 #include <apr_time.h>
@@ -46,13 +45,15 @@
 #include <apr_portable.h>
 #include <apr_support.h>
 
+#define PCRE2_CODE_UNIT_WIDTH 8
+#include <pcre2.h>
+
 #include "qs_util.h"
 
 #define LOOPS 100
 
 typedef struct {
-  pcre *pc;
-  pcre_extra *extra;
+  qs_regex_t *preg;
 } rule_t;
 
 static void usage(const char *cmd, int man) {
@@ -82,7 +83,7 @@
     printf("Summary\n");
   }
   qs_man_print(man, "%s loads regular expressions from the provided file and matches\n", cmd);
-  qs_man_print(man, "them against a build-in set of strings measuring the time needed to\n");
+  qs_man_print(man, "them against a built-in set of strings measuring the time needed to\n");
   qs_man_print(man, "process them. It's a benchmark too to judge the expressions you have\n");
   qs_man_print(man, "defined regarding the potential CPU consumption.\n");
   printf("\n");
@@ -180,6 +181,7 @@
   long long start;
   long long end;
   struct timeval tv;
+  static char ver[80];
 
   const char *filename = NULL;
 
@@ -234,8 +236,6 @@
   while(fgets(readline, MAX_LINE-1, file) != NULL) {
     char *p;
     int len = strlen(readline);
-    const char *errptr = NULL;
-    int erroffset;
     rule_t *rule = apr_pcalloc(pool, sizeof(rule_t));
 
     while(len > 0 && readline[len] < 32) {
@@ -247,18 +247,13 @@
        (readline[0] != LF)) {
 
       p = readline;
-      
-      rule->pc = pcre_compile(p, PCRE_DOTALL|PCRE_CASELESS, &errptr, &erroffset, NULL);
-      if(rule->pc == NULL) {
-	printf("faild to compile pattern [%s], reason: %s\n", p, errptr);
+
+      rule->preg = apr_palloc(pool, sizeof(qs_regex_t));
+      if(qs_regcomp(rule->preg, p, PCRE2_DOTALL|PCRE2_CASELESS) != 0) {
+	printf("failed to compile pattern [%s]\n", p);
 	exit(1);
       }
-      rule->extra = pcre_study(rule->pc, 0, &errptr);
-      if(rule->extra == NULL) {
-	rule->extra = apr_pcalloc(pool, sizeof(pcre_extra));
-      }
-      rule->extra->match_limit = 1500;
-      rule->extra->flags |= PCRE_EXTRA_MATCH_LIMIT;
+      apr_pool_pre_cleanup_register(pool, rule->preg, qs_pregfree);
       apr_table_addn(rules, apr_pstrdup(pool, p), (char *)rule);
     }
   }
@@ -274,7 +269,7 @@
 	for(i = 0; i < LOOPS; i++) {
 	  qs_r_t *d = data;
 	  while(d->string) {
-	    pcre_exec(rule->pc, rule->extra, d->string, d->len, 0, 0, NULL, 0);
+	    qs_regexec_len(rule->preg, d->string, d->len, 0, NULL, 0);
 	    d++;
 	  }
 	}
@@ -294,19 +289,20 @@
       apr_table_entry_t *entry = (apr_table_entry_t *)apr_table_elts(rules)->elts;
       for(k = 0; k < apr_table_elts(rules)->nelts; k++) {
 	rule_t* rule = (rule_t *)entry[k].val;
-	pcre_exec(rule->pc, rule->extra, d->string, d->len, 0, 0, NULL, 0);
+	qs_regexec_len(rule->preg, d->string, d->len, 0, NULL, 0);
       }
       d++;
     }
   }
   gettimeofday(&tv, NULL);
   end = tv.tv_sec * 1000000 + tv.tv_usec;
+  pcre2_config(PCRE2_CONFIG_VERSION, ver);
   printf("match all rules (%d) against the test variables (%lu strings, %d characters) took: %lld usec (%s/PCRE %s)\n",
 	 apr_table_elts(rules)->nelts,
 	 sizeof(data)/sizeof(qs_r_t)-1,
 	 datalen,
 	 (end - start) / LOOPS,
-	 revision, pcre_version());
+	 revision, ver);
   return 0;
 
 }
diff -Nru libapache2-mod-qos-11.63/tools/src/qsrotate.c libapache2-mod-qos-11.74/tools/src/qsrotate.c
--- libapache2-mod-qos-11.63/tools/src/qsrotate.c	2019-05-25 09:08:59.000000000 -0400
+++ libapache2-mod-qos-11.74/tools/src/qsrotate.c	2023-05-18 08:34:25.000000000 -0400
@@ -6,7 +6,7 @@
  * See http://mod-qos.sourceforge.net/ for further
  * details.
  *
- * Copyright (C) 2019 Pascal Buchbinder
+ * Copyright (C) 2023 Pascal Buchbinder
  *
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -25,7 +25,7 @@
  *
  */
 
-static const char revision[] = "$Id: qsrotate.c 2542 2019-02-22 06:37:10Z pbuchbinder $";
+static const char revision[] = "$Id: qsrotate.c 2654 2022-05-13 09:12:42Z pbuchbinder $";
 
 #include <stdio.h>
 #include <string.h>
@@ -365,7 +365,7 @@
     cmd++;
   }
   m_cmd = calloc(1, strlen(cmd)+1);
-  strcpy(m_cmd, cmd); // copy as we wan't to pass it when forking
+  strcpy(m_cmd, cmd); // copy as we can't pass it when forking
 
   while(argc >= 1) {
     if(strcmp(*argv,"-o") == 0) {
diff -Nru libapache2-mod-qos-11.63/tools/src/qssign.c libapache2-mod-qos-11.74/tools/src/qssign.c
--- libapache2-mod-qos-11.63/tools/src/qssign.c	2019-05-25 09:08:59.000000000 -0400
+++ libapache2-mod-qos-11.74/tools/src/qssign.c	2023-05-18 08:34:25.000000000 -0400
@@ -6,7 +6,7 @@
  * See http://mod-qos.sourceforge.net/ for further
  * details.
  *
- * Copyright (C) 2019 Pascal Buchbinder
+ * Copyright (C) 2023 Pascal Buchbinder
  *
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -24,7 +24,7 @@
  * limitations under the License.
  */
 
-static const char revision[] = "$Id: qssign.c 2542 2019-02-22 06:37:10Z pbuchbinder $";
+static const char revision[] = "$Id: qssign.c 2654 2022-05-13 09:12:42Z pbuchbinder $";
 
 #include <stdio.h>
 #include <unistd.h>
@@ -37,9 +37,6 @@
 #include <openssl/evp.h>
 #include <openssl/hmac.h>
 
-/* PCRE */
-#include <pcre.h>
-
 /* apr/apr-util */
 #define QS_USEAPR 1
 #include <apr.h>
@@ -50,6 +47,9 @@
 #include <apr_file_io.h>
 #include <apr_time.h>
 
+#define PCRE2_CODE_UNIT_WIDTH 8
+#include <pcre2.h>
+
 #include "qs_util.h"
 #include "qs_apo.h"
 
@@ -65,7 +65,7 @@
 static int m_end_pos = 0;
 static const char *m_sec = NULL;
 static const EVP_MD *m_evp;
-static const pcre *m_filter = NULL;
+static qs_regex_t *m_filter = NULL;
 
 typedef struct {
   const char* start_fmt;
@@ -310,7 +310,7 @@
 }
 
 /**
- * Tries to find out a suiteable log line format which is used
+ * Tries to find out a suitable log line format which is used
  * to log sign end messages (so let the verifier known, that the
  * data ends nothing has been cut off).
  *
@@ -433,7 +433,7 @@
       qs_set_format(line);
       m_end(m_sec, 1);
     }
-    if(pcre_exec(m_filter, NULL, line, line_size, 0, 0, NULL, 0) >= 0) {
+    if(m_filter != NULL && qs_regexec_len(m_filter, line, line_len, 0, NULL, 0) >= 0) {
       printf("%s\n", line);
       fflush(stdout);
     } else {
@@ -517,7 +517,7 @@
       if(strcmp(m, sig) != 0) {
 	err++;
 	fprintf(stderr, "ERROR on line %ld: invalid signature\n", lineNumber);
-	/* message may be modified/currupt or inserted: next line may have
+	/* message may be modified/corrupt or inserted: next line may have
 	   the next sequence number (modified) or the same (inserted) */
 	nr_alt = m_nr + 1;
 	nr_alt_lineNumber = lineNumber + 1;
@@ -534,9 +534,9 @@
       } else {
 	if(m_nr != -1) {
 	  if(lineNumber == nr_alt_lineNumber) {
-	    // last line was modfied
+	    // last line was modified
 	    if(m_nr != msgSeqNr) {
-	      // and therefore, we also accept the next seqence number
+	      // and therefore, we also accept the next sequence number
 	      m_nr = nr_alt;
 	    }
 	    nr_alt = -1;
@@ -544,7 +544,7 @@
 	  }
 	  if(valid && isSpecialLine(line, QS_START)) {
 	    // new start line (graceful restart)
-	    // we expect now msg nummber 1
+	    // we expect now msg number 1
 	    // but still acept the old until we get the end marker
 	    nr_usr1_lineNumber = m_nr;
 	    m_nr = 1; 
@@ -566,7 +566,7 @@
 		fprintf(stderr, "ERROR on line %ld: wrong sequence (expect %."SEQDIG"ld)\n", lineNumber, m_nr);
 	      }
 	    } else {
-	      // well done - this is the sequence number we expet
+	      // well done - this is the sequence number we expect
 	    }
 	  }
 	} else if(m_logend) {
@@ -629,7 +629,7 @@
   }
   qs_man_print(man, "%s is a log data integrity check tool. It reads log data\n", cmd);
   qs_man_print(man, "from stdin (pipe) and writes the data to stdout adding a sequence\n");
-  qs_man_print(man, "number and signatur to ever log line.\n");
+  qs_man_print(man, "number and signature to ever log line.\n");
   printf("\n");
   if(man) {
     printf(".SH OPTIONS\n");
@@ -664,7 +664,7 @@
   if(man) printf("\n.TP\n");
   qs_man_print(man, "  -a 'sha1'|'sha256'\n");
   if(man) printf("\n");
-  qs_man_print(man, "     Specifes the algorithm to use. Default is sha1.\n");
+  qs_man_print(man, "     Specifies the algorithm to use. Default is sha1.\n");
   printf("\n");
   if(man) {
     printf(".SH EXAMPLE\n");
@@ -761,14 +761,12 @@
   }
 
   if(filter != NULL) {
-    const char *errptr = NULL;
-    int erroffset;
-    m_filter = pcre_compile(filter, 0, &errptr, &erroffset, NULL);
-    if(m_filter == NULL) {
-      fprintf(stderr, "failed to compile filter pattern <%s> at position %d,"
-            " reason: %s\n", filter, erroffset, errptr);
+    m_filter = apr_palloc(pool, sizeof(qs_regex_t));
+    if(qs_regcomp(m_filter, filter, 0) != 0) {
+      fprintf(stderr, "failed to compile filter pattern <%s>\n", filter);
       exit(1);
     }
+    apr_pool_pre_cleanup_register(pool, m_filter, qs_pregfree);
   }
 
   if(m_evp == NULL) {
diff -Nru libapache2-mod-qos-11.63/tools/src/qstail.c libapache2-mod-qos-11.74/tools/src/qstail.c
--- libapache2-mod-qos-11.63/tools/src/qstail.c	2019-05-25 09:08:59.000000000 -0400
+++ libapache2-mod-qos-11.74/tools/src/qstail.c	2023-05-18 08:34:25.000000000 -0400
@@ -9,7 +9,7 @@
  * See http://mod-qos.sourceforge.net/ for further
  * details.
  *
- * Copyright (C) 2019 Pascal Buchbinder
+ * Copyright (C) 2023 Pascal Buchbinder
  *
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -27,13 +27,12 @@
  * limitations under the License.
  */
 
-static const char revision[] = "$Id: qstail.c 2542 2019-02-22 06:37:10Z pbuchbinder $";
+static const char revision[] = "$Id: qstail.c 2654 2022-05-13 09:12:42Z pbuchbinder $";
 
 #include <stdio.h>
 #include <unistd.h>
 #include <string.h>
 #include <stdlib.h>
-#include <regex.h>
 #include <signal.h>
 
 #include "qs_util.h"
diff -Nru libapache2-mod-qos-11.63/tools/src/qs_util.c libapache2-mod-qos-11.74/tools/src/qs_util.c
--- libapache2-mod-qos-11.63/tools/src/qs_util.c	2019-05-25 09:08:59.000000000 -0400
+++ libapache2-mod-qos-11.74/tools/src/qs_util.c	2023-05-18 08:34:25.000000000 -0400
@@ -4,7 +4,7 @@
  * See http://mod-qos.sourceforge.net/ for further
  * details.
  *
- * Copyright (C) 2019 Pascal Buchbinder
+ * Copyright (C) 2023 Pascal Buchbinder
  *
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -22,7 +22,7 @@
  * limitations under the License.
  */
 
-static const char revision[] = "$Id: qs_util.c 2542 2019-02-22 06:37:10Z pbuchbinder $";
+static const char revision[] = "$Id: qs_util.c 2654 2022-05-13 09:12:42Z pbuchbinder $";
 
 #include <stdio.h>
 #include <pthread.h>
@@ -36,6 +36,11 @@
 #include <errno.h>
 #include <pwd.h>
 
+#define PCRE2_CODE_UNIT_WIDTH 8
+#include <pcre2.h>
+typedef pcre2_match_data* match_data_pt;
+typedef size_t*           match_vector_pt;
+
 #include "qs_util.h"
 
 /* mutex for counter access */
@@ -326,3 +331,79 @@
     }
   }
 }
+/* pcre ------------------------------------------------------- */
+int qs_pregfree(void *p) {
+  qs_regfree((qs_regex_t *)p);
+  return 0;
+}
+
+void qs_regfree(qs_regex_t *preg) {
+  if(preg->state == 1) {
+    pcre2_code_free(preg->re_pcre);
+  }
+}
+
+int qs_regcomp(qs_regex_t *preg, const char *pattern, int cflags) {
+  unsigned int capcount;
+  size_t erroffset;
+  int errcode = 0;
+  int options = cflags;
+  preg->state = 0;
+
+  preg->re_pcre = pcre2_compile((const unsigned char *)pattern,
+				PCRE2_ZERO_TERMINATED, options, &errcode,
+				&erroffset, NULL);
+
+  if (preg->re_pcre == NULL) {
+    return 1;
+  }
+
+  pcre2_pattern_info((const pcre2_code *)preg->re_pcre,
+		     PCRE2_INFO_CAPTURECOUNT, &capcount);
+  preg->re_nsub = capcount;
+
+  preg->state = 1;
+  
+  return 0;
+}
+
+int qs_regexec_len(const qs_regex_t *preg, const char *buff,
+		   unsigned int len, unsigned int nmatch,
+		   qs_regmatch_t *pmatch, int eflags) {
+  int rc;
+  int options = 0;
+  match_vector_pt ovector = NULL;
+  unsigned int ncaps = (unsigned int)preg->re_nsub + 1;
+  match_data_pt data = pcre2_match_data_create(ncaps, NULL);
+
+  if (!data) {
+    return -1;
+  }
+
+  options = eflags;
+
+  rc = pcre2_match((const pcre2_code *)preg->re_pcre,
+		   (const unsigned char *)buff, len,
+		   0, options, data, NULL);
+  ovector = pcre2_get_ovector_pointer(data);
+  
+  if (rc >= 0) {
+    unsigned int n = rc, i;
+    if (n == 0 || n > nmatch)
+      rc = n = nmatch; /* All capture slots were filled in */
+    for (i = 0; i < n; i++) {
+      pmatch[i].rm_so = ovector[i * 2];
+      pmatch[i].rm_eo = ovector[i * 2 + 1];
+    }
+    for (; i < nmatch; i++) {
+      pmatch[i].rm_so = pmatch[i].rm_eo = -1;
+    }
+    pcre2_match_data_free(data);
+    return rc;
+  }
+  else {
+    pcre2_match_data_free(data);
+    
+    return -1;
+  }
+}
diff -Nru libapache2-mod-qos-11.63/tools/src/qs_util.h libapache2-mod-qos-11.74/tools/src/qs_util.h
--- libapache2-mod-qos-11.63/tools/src/qs_util.h	2019-05-25 09:08:59.000000000 -0400
+++ libapache2-mod-qos-11.74/tools/src/qs_util.h	2023-05-18 08:34:25.000000000 -0400
@@ -4,7 +4,7 @@
  * See http://mod-qos.sourceforge.net/ for further
  * details.
  *
- * Copyright (C) 2019 Pascal Buchbinder
+ * Copyright (C) 2023 Pascal Buchbinder
  *
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -29,8 +29,8 @@
 /* ----------------------------------
  * version info
  * ---------------------------------- */
-static const char man_version[] = "11.63";
-static const char man_date[] = "May 2019";
+static const char man_version[] = "11.74";
+static const char man_date[] = "May 2023";
 
 /* ----------------------------------
  * definitions
@@ -71,4 +71,28 @@
 /* user */
 void qs_setuid(const char *username, const char *cmd);
 
+/* pcre */
+#define QS_MAX_REG_MATCH 10
+
+typedef struct {
+  int rm_so;
+  int rm_eo;
+} qs_regmatch_t;
+
+typedef struct {
+  void *re_pcre;
+  int re_nsub;
+  int state; 
+} qs_regex_t;
+
+int qs_pregfree(void *p);
+
+void qs_regfree(qs_regex_t *preg);
+
+int qs_regcomp(qs_regex_t *preg, const char *regex, int cflags);
+
+int qs_regexec_len(const qs_regex_t *preg, const char *buff,
+		   unsigned int len, unsigned int nmatch,
+		   qs_regmatch_t *pmatch, int eflags);
+
 #endif

Reply to: