From 2b70b76c7e702f20212c1618261e3aa653ebd235 Mon Sep 17 00:00:00 2001
From: Vladimir Krivopalov <vladimir.krivopalov@gmail.com>
Date: Wed, 30 Jan 2019 18:34:26 -0800
Subject: [PATCH 01/58] Make detection mode run fully in background and not
 block Nginx requests (#97)

* Use Apache pool instead of Nginx pool for Apache-specific structs allocation.

This allows the allocated structures to outlive the Nginx request.

Signed-off-by: Vladimir Krivopalov <vlkrivop@microsoft.com>

* Remove unused input parameters from apr_bucket_nginx helpers.

Signed-off-by: Vladimir Krivopalov <vlkrivop@microsoft.com>

* Move the log message out from ngx_http_modsecurity_status.

This way ngx_http_modsecurity_status does not depend on the
ngx_http_request_t parameter and can be used in contexts where no Nginx
request exists.

Signed-off-by: Vladimir Krivopalov <vlkrivop@microsoft.com>

* Rename thread functions to reflect they are used in prevention mode.

Detection mode will be handled separately so old routines are renamed to
emphasize they are only being used in prevention mode.

Signed-off-by: Vladimir Krivopalov <vlkrivop@microsoft.com>

* Do not save Nginx request context to APR table in detection mode.

This stored pointer is used to drop connections from inside ModSecurity.
Since detection mode is going to be detached from Nginx request and
connection, this pointer should not be stored otherwise it could be
potentially used after the structure it points to has been released.

Signed-off-by: Vladimir Krivopalov <vlkrivop@microsoft.com>

* Run detection mode as a background task detached from the handled request.

When ModSecurity runs in the detection-only mode, a request does not
have to be blocked awaiting to be processed and can be transmitted
immediately because the result of executing rules on it does not affect
its status.
This allows to minimize the latency overhead.

To achieve this, the processing is offloaded to a thread pool and runs
independently from the main request processing by Nginx.

Signed-off-by: Vladimir Krivopalov <vlkrivop@microsoft.com>
---
 nginx/modsecurity/apr_bucket_nginx.c     |  10 +-
 nginx/modsecurity/apr_bucket_nginx.h     |   9 +-
 nginx/modsecurity/ngx_http_modsecurity.c | 212 +++++++++++++++++++----
 3 files changed, 181 insertions(+), 50 deletions(-)

diff --git a/nginx/modsecurity/apr_bucket_nginx.c b/nginx/modsecurity/apr_bucket_nginx.c
index 17906fe355..9ed7cbbbcb 100644
--- a/nginx/modsecurity/apr_bucket_nginx.c
+++ b/nginx/modsecurity/apr_bucket_nginx.c
@@ -22,7 +22,6 @@ typedef struct apr_bucket_nginx {
 
 /* ngx_buf_t to apr_bucket */
 apr_bucket * apr_bucket_nginx_create(ngx_buf_t *buf,
-                                     apr_pool_t *p,
                                      apr_bucket_alloc_t *list)
 {
 
@@ -31,11 +30,10 @@ apr_bucket * apr_bucket_nginx_create(ngx_buf_t *buf,
     APR_BUCKET_INIT(b); /* link */
     b->free = apr_bucket_free;
     b->list = list;
-    return apr_bucket_nginx_make(b, buf, p);
+    return apr_bucket_nginx_make(b, buf);
 }
 
-apr_bucket * apr_bucket_nginx_make(apr_bucket *b, ngx_buf_t *buf,
-                                   apr_pool_t *pool)
+apr_bucket * apr_bucket_nginx_make(apr_bucket *b, ngx_buf_t *buf)
 {
     apr_bucket_nginx *n;
 
@@ -93,11 +91,11 @@ static void nginx_bucket_destroy(void *data)
 
 
 ngx_int_t
-copy_chain_to_brigade(ngx_chain_t *chain, apr_bucket_brigade *bb, ngx_pool_t *pool, ngx_int_t last_buf) {
+copy_chain_to_brigade(ngx_chain_t *chain, apr_bucket_brigade *bb, ngx_int_t last_buf) {
     apr_bucket         *e;
 
     while (chain) {
-        e = ngx_buf_to_apr_bucket(chain->buf, bb->p, bb->bucket_alloc);
+        e = ngx_buf_to_apr_bucket(chain->buf, bb->bucket_alloc);
         if (e == NULL) {
             return NGX_ERROR;
         }
diff --git a/nginx/modsecurity/apr_bucket_nginx.h b/nginx/modsecurity/apr_bucket_nginx.h
index a4ce631389..b6b5762770 100644
--- a/nginx/modsecurity/apr_bucket_nginx.h
+++ b/nginx/modsecurity/apr_bucket_nginx.h
@@ -2,13 +2,10 @@
 #include <ngx_core.h>
 #include "apr_buckets.h"
 
-apr_bucket * apr_bucket_nginx_create(ngx_buf_t *buf,
-                                     apr_pool_t *p,
-                                     apr_bucket_alloc_t *list);
+apr_bucket * apr_bucket_nginx_create(ngx_buf_t *buf, apr_bucket_alloc_t *list);
 
-apr_bucket * apr_bucket_nginx_make(apr_bucket *e, ngx_buf_t *buf,
-                                   apr_pool_t *pool);
+apr_bucket * apr_bucket_nginx_make(apr_bucket *e, ngx_buf_t *buf);
 
 #define ngx_buf_to_apr_bucket apr_bucket_nginx_create
 
-ngx_int_t copy_chain_to_brigade(ngx_chain_t *chain, apr_bucket_brigade *bb, ngx_pool_t *pool, ngx_int_t last_buf);
+ngx_int_t copy_chain_to_brigade(ngx_chain_t *chain, apr_bucket_brigade *bb, ngx_int_t last_buf);
diff --git a/nginx/modsecurity/ngx_http_modsecurity.c b/nginx/modsecurity/ngx_http_modsecurity.c
index 2b5809fda6..f7a73d88d3 100644
--- a/nginx/modsecurity/ngx_http_modsecurity.c
+++ b/nginx/modsecurity/ngx_http_modsecurity.c
@@ -50,8 +50,14 @@ typedef struct {
 
 typedef struct {
     ngx_http_request_t *r;
-} ngx_http_modsecurity_thread_ctx_t;
+} ngx_http_modsecurity_prevention_thread_ctx_t;
 
+typedef struct {
+    conn_rec            *connection;
+    request_rec         *req;
+
+    apr_bucket_brigade  *brigade;
+} ngx_http_modsecurity_detection_thread_ctx_t;
 
 /*
 ** Module's registred function/handlers.
@@ -167,6 +173,32 @@ ngx_pstrdup0(ngx_pool_t *pool, ngx_str_t *src)
 }
 
 
+static inline char *
+dup_ngx_str_to_apr(apr_pool_t *pool, ngx_str_t *src)
+{
+    return apr_pstrmemdup(pool, (char *)src->data, src->len);
+}
+
+/*
+ * Helper to allocate a thread task using an Apache pool.
+ * This is useful when the background task can outlive the Nginx request
+ * it is initiated for.
+ */
+ngx_thread_task_t *
+apr_thread_task_alloc(apr_pool_t *pool, size_t size)
+{
+    ngx_thread_task_t  *task;
+
+    task = apr_palloc(pool, sizeof(ngx_thread_task_t) + size);
+    if (task == NULL) {
+        return NULL;
+    }
+
+    task->ctx = task + 1;
+
+    return task;
+}
+
 static inline int
 ngx_http_modsecurity_method_number(unsigned int nginx)
 {
@@ -211,6 +243,11 @@ ngx_http_modsecurity_method_number(unsigned int nginx)
     return MultiplyDeBruijnBitPosition[((uint32_t)((nginx & -nginx) * 0x077CB531U)) >> 27];
 }
 
+/*
+ * Use APR pool for all allocations because they should not depend on Nginx request pool.
+ * In case of detection mode, processing will take place entirely in background and may last
+ * longer than the original request lives.
+ */
 static ngx_inline ngx_int_t
 ngx_http_modsecurity_load_request(ngx_http_request_t *r)
 {
@@ -228,7 +265,7 @@ ngx_http_modsecurity_load_request(ngx_http_request_t *r)
     req = ctx->req;
 
     /* request line */
-    req->method = (char *)ngx_pstrdup0(r->pool, &r->method_name);
+    req->method = dup_ngx_str_to_apr(req->pool, &r->method_name);
 
     /* TODO: how to use ap_method_number_of ?
      * req->method_number = ap_method_number_of(req->method);
@@ -241,18 +278,18 @@ ngx_http_modsecurity_load_request(ngx_http_request_t *r)
         return NGX_ERROR;
     }
 
-    req->filename = (char *) path.data;
+    req->filename = dup_ngx_str_to_apr(req->pool, &path);
     req->path_info = req->filename;
 
-    req->args = (char *)ngx_pstrdup0(r->pool, &r->args);
+    req->args = dup_ngx_str_to_apr(req->pool, &r->args);
 
     req->proto_num = r->http_major *1000 + r->http_minor;
-    req->protocol = (char *)ngx_pstrdup0(r->pool, &r->http_protocol);
+    req->protocol = dup_ngx_str_to_apr(req->pool, &r->http_protocol);
     req->request_time = apr_time_make(r->start_sec, r->start_msec);
-    req->the_request = (char *)ngx_pstrdup0(r->pool, &r->request_line);
+    req->the_request = dup_ngx_str_to_apr(req->pool, &r->request_line);
 
-    req->unparsed_uri = (char *)ngx_pstrdup0(r->pool, &r->unparsed_uri);
-    req->uri = (char *)ngx_pstrdup0(r->pool, &r->uri);
+    req->unparsed_uri = dup_ngx_str_to_apr(req->pool, &r->unparsed_uri);
+    req->uri = dup_ngx_str_to_apr(req->pool, &r->uri);
 
     req->parsed_uri.scheme = "http";
 
@@ -262,7 +299,7 @@ ngx_http_modsecurity_load_request(ngx_http_request_t *r)
     }
 #endif
 
-    req->parsed_uri.path = (char *)ngx_pstrdup0(r->pool, &r->uri);
+    req->parsed_uri.path = dup_ngx_str_to_apr(req->pool, &r->uri);
     req->parsed_uri.is_initialized = 1;
 
     switch (r->connection->local_sockaddr->sa_family) {
@@ -287,18 +324,16 @@ ngx_http_modsecurity_load_request(ngx_http_request_t *r)
     }
 
     req->parsed_uri.port = port;
-    req->parsed_uri.port_str = ngx_pnalloc(r->pool, sizeof("65535"));
+    req->parsed_uri.port_str = apr_palloc(req->pool, sizeof("65535"));
     (void) ngx_sprintf((u_char *)req->parsed_uri.port_str, "%ui%c", port, '\0');
 
     req->parsed_uri.query = r->args.len ? req->args : NULL;
     req->parsed_uri.dns_looked_up = 0;
     req->parsed_uri.dns_resolved = 0;
 
-    // req->parsed_uri.password = (char *)ngx_pstrdup0(r->pool, &r->headers_in.passwd);
-    // req->parsed_uri.user = (char *)ngx_pstrdup0(r->pool, &r->headers_in.user);
-    req->parsed_uri.fragment = (char *)ngx_pstrdup0(r->pool, &r->exten);
+    req->parsed_uri.fragment = dup_ngx_str_to_apr(req->pool, &r->exten);
 
-    req->hostname = (char *)ngx_pstrdup0(r->pool, (ngx_str_t *)&ngx_cycle->hostname);
+    req->hostname = dup_ngx_str_to_apr(req->pool, (ngx_str_t *)&ngx_cycle->hostname);
 
     req->header_only = r->header_only ? r->header_only : (r->method == NGX_HTTP_HEAD);
 
@@ -337,7 +372,15 @@ ngx_http_modsecurity_load_headers_in(ngx_http_request_t *r)
             i = 0;
         }
 
-        apr_table_setn(req->headers_in, (char *)h[i].key.data, (char *)h[i].value.data);
+        const char *key = dup_ngx_str_to_apr(req->pool, &h[i].key);
+        if (key == NULL) {
+            return NGX_ERROR;
+        }
+        const char *value = dup_ngx_str_to_apr(req->pool, &h[i].value);
+        if (value == NULL) {
+            return NGX_ERROR;
+        }
+        apr_table_setn(req->headers_in, key, value);
         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                        "ModSecurity: load headers in: \"%V: %V\"",
                        &h[i].key, &h[i].value);
@@ -353,14 +396,14 @@ ngx_http_modsecurity_load_headers_in(ngx_http_request_t *r)
     lang = apr_table_get(ctx->req->headers_in, "Content-Languages");
     if(lang != NULL)
     {
-        ctx->req->content_languages = apr_array_make(ctx->req->pool, 1, sizeof(const char *));
+        ctx->req->content_languages = apr_array_make(req->pool, 1, sizeof(const char *));
 
-        *(const char **)apr_array_push(ctx->req->content_languages) = lang;
+        *(const char **)apr_array_push(req->content_languages) = lang;
     }
 
     req->ap_auth_type = (char *)apr_table_get(req->headers_in, "Authorization");
 
-    req->user = (char *)ngx_pstrdup0(r->pool, &r->headers_in.user);
+    req->user = dup_ngx_str_to_apr(req->pool, &r->headers_in.user);
 
 
 
@@ -496,10 +539,10 @@ ngx_http_modsecurity_load_request_body(ngx_http_request_t *r)
 
     if (r->request_body == NULL || r->request_body->bufs == NULL) {
 
-        return copy_chain_to_brigade(NULL, ctx->brigade, r->pool, 1);
+        return copy_chain_to_brigade(NULL, ctx->brigade, 1);
     }
 
-    if (copy_chain_to_brigade(r->request_body->bufs, ctx->brigade, r->pool, 1) != NGX_OK) {
+    if (copy_chain_to_brigade(r->request_body->bufs, ctx->brigade, 1) != NGX_OK) {
         return NGX_ERROR;
     }
 
@@ -813,10 +856,8 @@ ngx_http_modsecurity_save_headers_out_visitor(void *data, const char *key, const
 
 
 static ngx_inline ngx_int_t
-ngx_http_modsecurity_status(ngx_http_request_t *r, int status)
+ngx_http_modsecurity_status(int status)
 {
-    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "ModSecurity: status %d", status);
-
     if (status == DECLINED || status == APR_SUCCESS) {
         return NGX_DECLINED;
     }
@@ -995,11 +1036,11 @@ ngx_http_modsecurity_init_process(ngx_cycle_t *cycle)
 
 
 static void
-ngx_http_modsecurity_thread_func(void *data, ngx_log_t *log)
+ngx_http_modsecurity_prevention_thread_func(void *data, ngx_log_t *log)
 {
     // Executed in a separate thread
 
-    ngx_http_modsecurity_thread_ctx_t *thread_ctx = data;
+    ngx_http_modsecurity_prevention_thread_ctx_t *thread_ctx = data;
     ngx_http_request_t *r = thread_ctx->r;
 
     ngx_http_modsecurity_ctx_t* mod_ctx = ngx_http_get_module_ctx(r, ngx_http_modsecurity);
@@ -1013,7 +1054,9 @@ ngx_http_modsecurity_thread_func(void *data, ngx_log_t *log)
     }
 
     // Processing request headers
-    ngx_int_t rc = ngx_http_modsecurity_status(r, modsecProcessRequestHeaders(mod_ctx->req));
+    ngx_int_t rc = modsecProcessRequestHeaders(mod_ctx->req);
+    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "ModSecurity process headers: status %d", rc);
+    rc = ngx_http_modsecurity_status(rc);
 
     if (rc != NGX_DECLINED) {
         mod_ctx->status_code = rc;
@@ -1033,13 +1076,14 @@ ngx_http_modsecurity_thread_func(void *data, ngx_log_t *log)
     }
 
     // The name of modsecProcessRequestBody is a bit misleading. This function call is needed even to just process GET args.
-    rc = ngx_http_modsecurity_status(r, modsecProcessRequestBody(mod_ctx->req));
-    mod_ctx->status_code = rc;
+    rc = modsecProcessRequestBody(mod_ctx->req);
+    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "ModSecurity process body: status %d", rc);
+    mod_ctx->status_code = ngx_http_modsecurity_status(rc);
 }
 
 
 static void
-ngx_http_modsecurity_thread_completion(ngx_event_t *ev)
+ngx_http_modsecurity_prevention_thread_completion(ngx_event_t *ev)
 {
     // executed in nginx event loop after thread task is done, in order to pick up and continue processing request
 
@@ -1056,13 +1100,52 @@ ngx_http_modsecurity_thread_completion(ngx_event_t *ev)
 }
 
 
+static void
+ngx_http_modsecurity_detection_thread_func(void *data, ngx_log_t *log)
+{
+    // Executed in a separate thread
+    ngx_http_modsecurity_detection_thread_ctx_t *thread_ctx = data;
+
+    // Processing request headers
+    ngx_int_t rc = ngx_http_modsecurity_status(modsecProcessRequestHeaders(thread_ctx->req));
+    if (rc != NGX_DECLINED) {
+        return;
+    }
+
+    if (modsecContextState(thread_ctx->req) == MODSEC_DISABLED) {
+        return;
+    }
+
+    // The name of modsecProcessRequestBody is a bit misleading. This function call is needed even to just process GET args.
+    modsecProcessRequestBody(thread_ctx->req);
+}
+
+
+static void
+ngx_http_modsecurity_detection_thread_completion(ngx_event_t *ev)
+{
+    // executed in nginx event loop after thread task is done, in order to pick up and continue processing request
+    ngx_http_modsecurity_detection_thread_ctx_t *ctx = ev->data;
+
+    request_rec *req = ctx->req;
+    conn_rec *connection = ctx->connection;
+
+    if (req != NULL) {
+        modsecFinishRequest(req);
+    }
+    if (connection != NULL) {
+        modsecFinishConnection(connection);
+    }
+}
+
+
 static ngx_int_t
-ngx_http_modsecurity_task_offload(ngx_http_request_t *r)
+ngx_http_modsecurity_prevention_task_offload(ngx_http_request_t *r)
 {
-    ngx_http_modsecurity_thread_ctx_t *thread_ctx;
+    ngx_http_modsecurity_prevention_thread_ctx_t *thread_ctx;
     ngx_thread_task_t *task;
 
-    task = ngx_thread_task_alloc(r->pool, sizeof(ngx_http_modsecurity_thread_ctx_t));
+    task = ngx_thread_task_alloc(r->pool, sizeof(ngx_http_modsecurity_prevention_thread_ctx_t));
     if (task == NULL) {
         return NGX_ERROR;
     }
@@ -1070,8 +1153,8 @@ ngx_http_modsecurity_task_offload(ngx_http_request_t *r)
     thread_ctx = task->ctx;
     thread_ctx->r = r;
 
-    task->handler = ngx_http_modsecurity_thread_func;
-    task->event.handler = ngx_http_modsecurity_thread_completion;
+    task->handler = ngx_http_modsecurity_prevention_thread_func;
+    task->event.handler = ngx_http_modsecurity_prevention_thread_completion;
     task->event.data = r;
 
     ngx_thread_pool_t* thread_pool = ngx_thread_pool_get((ngx_cycle_t *)ngx_cycle, &thread_pool_name);
@@ -1085,6 +1168,48 @@ ngx_http_modsecurity_task_offload(ngx_http_request_t *r)
     return NGX_OK;
 }
 
+static ngx_int_t
+ngx_http_modsecurity_detection_task_offload(ngx_http_request_t *r)
+{
+    ngx_http_modsecurity_ctx_t *ctx = ngx_http_get_module_ctx(r, ngx_http_modsecurity);
+    request_rec *req = ctx->req;
+
+    // Load request to request rec
+    if (ngx_http_modsecurity_load_request(r) != NGX_OK ||
+            ngx_http_modsecurity_load_headers_in(r) != NGX_OK) {
+        return NGX_ERROR;
+    }
+
+    if (modsecIsRequestBodyAccessEnabled(req) && (r->headers_in.content_length || r->headers_in.chunked)) {
+        if (ngx_http_modsecurity_load_request_body(r) != NGX_OK) {
+            return NGX_ERROR;
+        }
+    }
+
+    ngx_thread_task_t *task = apr_thread_task_alloc(req->pool, sizeof(ngx_http_modsecurity_detection_thread_ctx_t));
+    if (task == NULL) {
+        return NGX_ERROR;
+    }
+
+    ngx_http_modsecurity_detection_thread_ctx_t *thread_ctx = task->ctx;
+    thread_ctx->connection = ctx->connection;
+    ctx->connection = NULL;
+    thread_ctx->req = ctx->req;
+    ctx->req = NULL;
+    thread_ctx->brigade = ctx->brigade;
+    ctx->brigade = NULL;
+
+    task->handler = ngx_http_modsecurity_detection_thread_func;
+    task->event.handler = ngx_http_modsecurity_detection_thread_completion;
+    task->event.data = thread_ctx;
+
+    ngx_thread_pool_t* thread_pool = ngx_thread_pool_get((ngx_cycle_t *)ngx_cycle, &thread_pool_name);
+    if (ngx_thread_task_post(thread_pool, task) != NGX_OK) {
+        return NGX_ERROR;
+    }
+
+    return NGX_OK;
+}
 
 static void
 ngx_http_modsecurity_body_handler(ngx_http_request_t *r)
@@ -1149,8 +1274,17 @@ ngx_http_modsecurity_handler(ngx_http_request_t *r)
         return NGX_DECLINED;
     }
 
+    /* When in detection mode, don't wait for background task to complete because it won't affect the request status */
+    if (cf->config->is_enabled == MODSEC_DETECTION_ONLY) {
+        if (ngx_http_modsecurity_detection_task_offload(r) != NGX_OK) {
+            return NGX_ERROR;
+        }
+
+        return NGX_DECLINED;
+    }
+
     ctx->thread_running = 1;
-    if (ngx_http_modsecurity_task_offload(r) != NGX_OK) {
+    if (ngx_http_modsecurity_prevention_task_offload(r) != NGX_OK) {
         return NGX_ERROR;
     }
 
@@ -1197,9 +1331,9 @@ ngx_http_modsecurity_create_ctx(ngx_http_request_t *r)
         ctx->connection = modsecNewConnection();
 
         /* fill apr_sockaddr_t */
-        asa = ngx_palloc(r->pool, sizeof(apr_sockaddr_t));
+        asa = apr_palloc(ctx->connection->pool, sizeof(apr_sockaddr_t));
         asa->pool = ctx->connection->pool;
-        asa->hostname = (char *)ngx_pstrdup0(r->pool, &r->connection->addr_text);
+        asa->hostname = dup_ngx_str_to_apr(asa->pool, &r->connection->addr_text);
         asa->servname = asa->hostname;
         asa->next = NULL;
         asa->salen = r->connection->socklen;
@@ -1243,7 +1377,9 @@ ngx_http_modsecurity_create_ctx(ngx_http_request_t *r)
 
     ctx->req = modsecNewRequest(ctx->connection, cf->config);
 
-    apr_table_setn(ctx->req->notes, NOTE_NGINX_REQUEST_CTX, (const char *) ctx);
+    if (cf->config->is_enabled != MODSEC_DETECTION_ONLY) {
+        apr_table_setn(ctx->req->notes, NOTE_NGINX_REQUEST_CTX, (const char *)ctx);
+    }
     apr_generate_random_bytes(salt, TXID_SIZE);
 
     txid = apr_pcalloc (ctx->req->pool, TXID_SIZE);

From 4dfda1de9e09c6ea6c4cbf48f98918720f96e402 Mon Sep 17 00:00:00 2001
From: Vladimir Krivopalov <vladimir.krivopalov@gmail.com>
Date: Tue, 5 Feb 2019 11:05:40 -0800
Subject: [PATCH 02/58] Remove unused helpers from ngx_http_modsecurity.c (#98)

Signed-off-by: Vladimir Krivopalov <vlkrivop@microsoft.com>
---
 nginx/modsecurity/ngx_http_modsecurity.c | 458 -----------------------
 1 file changed, 458 deletions(-)

diff --git a/nginx/modsecurity/ngx_http_modsecurity.c b/nginx/modsecurity/ngx_http_modsecurity.c
index f7a73d88d3..d132564d53 100644
--- a/nginx/modsecurity/ngx_http_modsecurity.c
+++ b/nginx/modsecurity/ngx_http_modsecurity.c
@@ -76,10 +76,6 @@ static int ngx_http_modsecurity_drop_action(request_rec *r);
 static void ngx_http_modsecurity_terminate(ngx_cycle_t *cycle);
 static void ngx_http_modsecurity_cleanup(void *data);
 
-static int ngx_http_modsecurity_save_headers_in_visitor(void *data, const char *key, const char *value);
-static int ngx_http_modsecurity_save_headers_out_visitor(void *data, const char *key, const char *value);
-
-
 static ngx_str_t thread_pool_name = ngx_string("default");
 
 ngx_thread_mutex_t mtx;
@@ -140,39 +136,6 @@ ngx_module_t ngx_http_modsecurity = {
 
 static ngx_http_upstream_t ngx_http_modsecurity_upstream;
 
-static struct {
-    char      *name;
-    ngx_str_t  variable_name;
-} special_headers_out[] = {
-    {"Content-Type",      ngx_string("sent_http_content_type")  },
-    {"Content-Length",    ngx_string("sent_http_content_length")},
-    {"Location",          ngx_string("sent_http_location")},
-    {"Last-Modified",     ngx_string("sent_http_last_modified")},
-    {"Connection",        ngx_string("sent_http_connection")},
-    {"Keep-Alive",        ngx_string("sent_http_keep_alive")},
-    {"Transfer-Encoding", ngx_string("sent_http_transfer_encoding")},
-    {"Cache-Control",     ngx_string("sent_http_cache_control")},
-    {NULL,                ngx_null_string}
-};
-
-
-static inline u_char *
-ngx_pstrdup0(ngx_pool_t *pool, ngx_str_t *src)
-{
-    u_char  *dst;
-
-    dst = ngx_pnalloc(pool, src->len + 1);
-    if (dst == NULL) {
-        return NULL;
-    }
-
-    ngx_memcpy(dst, src->data, src->len);
-    dst[src->len] = '\0';
-
-    return dst;
-}
-
-
 static inline char *
 dup_ngx_str_to_apr(apr_pool_t *pool, ngx_str_t *src)
 {
@@ -413,121 +376,6 @@ ngx_http_modsecurity_load_headers_in(ngx_http_request_t *r)
     return NGX_OK;
 }
 
-static ngx_inline ngx_int_t
-ngx_http_modsecurity_save_headers_in(ngx_http_request_t *r)
-{
-    ngx_http_modsecurity_ctx_t  *ctx;
-
-    ctx = ngx_http_get_module_ctx(r, ngx_http_modsecurity);
-
-    /* clean up headers_in */
-    ngx_memzero(&r->headers_in, sizeof(ngx_http_headers_in_t));
-
-    if (ngx_list_init(&r->headers_in.headers, r->pool, 20,
-                      sizeof(ngx_table_elt_t))
-            != NGX_OK)
-    {
-        return NGX_ERROR;
-    }
-
-
-    if (ngx_array_init(&r->headers_in.cookies, r->pool, 2,
-                       sizeof(ngx_table_elt_t *))
-            != NGX_OK)
-    {
-        return NGX_ERROR;
-    }
-
-    r->headers_in.content_length_n = -1;
-    r->headers_in.keep_alive_n = -1;
-
-    r->headers_in.headers.part.nelts = 0;
-    r->headers_in.headers.part.next = NULL;
-    r->headers_in.headers.last = &r->headers_in.headers.part;
-
-    /* shadow copy */
-    if (apr_table_do(ngx_http_modsecurity_save_headers_in_visitor,
-                     r, ctx->req->headers_in, NULL) == 0) {
-
-        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                       "ModSecurity: save headers in error");
-
-        return NGX_ERROR;
-    }
-
-    if (r->headers_in.content_length) {
-        r->headers_in.content_length_n =
-            ngx_atoof(r->headers_in.content_length->value.data,
-                      r->headers_in.content_length->value.len);
-
-        if (r->headers_in.content_length_n == NGX_ERROR) {
-            ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
-                          "ModSecurity: invalid \"Content-Length\" header");
-            return NGX_ERROR;
-        }
-    }
-
-    if (r->headers_in.connection_type == NGX_HTTP_CONNECTION_KEEP_ALIVE) {
-        if (r->headers_in.keep_alive) {
-            r->headers_in.keep_alive_n =
-                ngx_atotm(r->headers_in.keep_alive->value.data,
-                          r->headers_in.keep_alive->value.len);
-        }
-    }
-
-    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                   "ModSecurity: save headers in done");
-
-    return NGX_OK;
-}
-
-
-static int
-ngx_http_modsecurity_save_headers_in_visitor(void *data, const char *key, const char *value)
-{
-    ngx_http_request_t         *r = data;
-    ngx_table_elt_t            *h;
-    ngx_http_header_t          *hh;
-    ngx_http_core_main_conf_t  *cmcf;
-
-    h = ngx_list_push(&r->headers_in.headers);
-    if (h == NULL) {
-        return 0;
-    }
-
-    h->key.data = (u_char *)key;
-    h->key.len = ngx_strlen(key);
-
-    h->value.data = (u_char *)value;
-    h->value.len = ngx_strlen(value);
-
-    h->lowcase_key = ngx_pnalloc(r->pool, h->key.len);
-
-    if (h->lowcase_key == NULL) {
-        return 0;
-    }
-
-    ngx_strlow(h->lowcase_key, h->key.data, h->key.len);
-
-    h->hash = ngx_hash_key(h->lowcase_key, h->key.len);
-
-    cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
-
-    hh = ngx_hash_find(&cmcf->headers_in_hash, h->hash,
-                       h->lowcase_key, h->key.len);
-
-    if (hh && hh->handler(r, h, hh->offset) != NGX_OK) {
-        return 0;
-    }
-
-    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                   "ModSecurity: save headers in: \"%V: %V\"",
-                   &h->key, &h->value);
-
-    return 1;
-}
-
-
 static ngx_inline ngx_int_t
 ngx_http_modsecurity_load_request_body(ngx_http_request_t *r)
 {
@@ -549,312 +397,6 @@ ngx_http_modsecurity_load_request_body(ngx_http_request_t *r)
     return NGX_OK;
 }
 
-
-static ngx_inline ngx_int_t
-ngx_http_modsecurity_save_request_body(ngx_http_request_t *r)
-{
-    ngx_http_modsecurity_ctx_t    *ctx;
-    apr_off_t                      content_length;
-    ngx_buf_t                     *buf;
-    ngx_http_core_srv_conf_t      *cscf;
-    size_t                         size;
-    ngx_http_connection_t         *hc;
-
-    ctx = ngx_http_get_module_ctx(r, ngx_http_modsecurity);
-
-    apr_brigade_length(ctx->brigade, 0, &content_length);
-
-    if (r->header_in->end - r->header_in->last >= content_length) {
-        /* use r->header_in */
-
-        if (ngx_buf_size(r->header_in)) {
-            /* move to the end */
-            ngx_memmove(r->header_in->pos + content_length,
-                        r->header_in->pos,
-                        ngx_buf_size(r->header_in));
-        }
-
-        if (apr_brigade_flatten(ctx->brigade,
-                                (char *)r->header_in->pos,
-                                (apr_size_t *)&content_length) != APR_SUCCESS) {
-            return NGX_ERROR;
-        }
-
-        apr_brigade_cleanup(ctx->brigade);
-
-        r->header_in->last += content_length;
-
-        return NGX_OK;
-    }
-
-    if (ngx_buf_size(r->header_in)) {
-
-        /*
-         * ngx_http_set_keepalive will reuse r->header_in if
-         * (r->header_in != c->buffer && r->header_in.last != r->header_in.end),
-         * so we need this code block.
-         * see ngx_http_set_keepalive, ngx_http_alloc_large_header_buffer
-         */
-        cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
-
-        size = ngx_max(cscf->large_client_header_buffers.size,
-                       (size_t)content_length + ngx_buf_size(r->header_in));
-
-        hc = r->http_connection;
-
-#if defined(nginx_version) && nginx_version >= 1011011
-        if (hc->free && size == cscf->large_client_header_buffers.size) {
-
-            buf = hc->free->buf;
-#else
-        if (hc->nfree && size == cscf->large_client_header_buffers.size) {
-
-            buf = hc->free[--hc->nfree];
-#endif
-
-            ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                           "ModSecurity: use http free large header buffer: %p %uz",
-                           buf->pos, buf->end - buf->last);
-
-        } else if (hc->nbusy < cscf->large_client_header_buffers.num) {
-
-            if (hc->busy == NULL) {
-                hc->busy = ngx_palloc(r->connection->pool,
-                                      cscf->large_client_header_buffers.num * sizeof(ngx_buf_t *));
-            }
-
-            if (hc->busy == NULL) {
-                return NGX_ERROR;
-            } else {
-                buf = ngx_create_temp_buf(r->connection->pool, size);
-            }
-        } else {
-            /* TODO: how to deal this case ? */
-            return NGX_ERROR;
-        }
-
-    } else {
-
-        buf = ngx_create_temp_buf(r->pool, (size_t) content_length);
-    }
-
-    if (buf == NULL) {
-        return NGX_ERROR;
-    }
-
-    if (apr_brigade_flatten(ctx->brigade, (char *)buf->pos,
-                            (apr_size_t *)&content_length) != APR_SUCCESS) {
-        return NGX_ERROR;
-    }
-
-    apr_brigade_cleanup(ctx->brigade);
-    buf->last += content_length;
-
-    ngx_memcpy(buf->last, r->header_in->pos, ngx_buf_size(r->header_in));
-    buf->last += ngx_buf_size(r->header_in);
-
-    r->header_in = buf;
-
-    return NGX_OK;
-}
-
-
-static ngx_inline ngx_int_t
-ngx_http_modsecurity_load_headers_out(ngx_http_request_t *r)
-{
-
-    ngx_http_modsecurity_ctx_t  *ctx;
-    char                        *data;
-    request_rec                 *req;
-    ngx_http_variable_value_t   *vv;
-    ngx_list_part_t             *part;
-    ngx_table_elt_t             *h;
-    ngx_uint_t                   i;
-    char                        *key, *value;
-    u_char                      *buf = NULL;
-    size_t                       size = 0;
-
-    ctx = ngx_http_get_module_ctx(r, ngx_http_modsecurity);
-    req = ctx->req;
-
-    req->status = r->headers_out.status;
-    req->status_line = (char *)ngx_pstrdup0(r->pool, &r->headers_out.status_line);
-
-    /* deep copy */
-    part = &r->headers_out.headers.part;
-    h = part->elts;
-
-    for (i = 0; ; i++) {
-        if (i >= part->nelts) {
-            if (part->next == NULL)
-                break;
-
-            part = part->next;
-            h = part->elts;
-            i = 0;
-        }
-        size += h[i].key.len + h[i].value.len + 2;
-
-        buf = ngx_palloc(r->pool, size);
-
-        if (buf == NULL) {
-            return NGX_ERROR;
-        }
-
-        key = (char *)buf;
-        buf = ngx_cpymem(buf, h[i].key.data, h[i].key.len);
-        *buf++ = '\0';
-
-        value = (char *)buf;
-        buf = ngx_cpymem(buf, h[i].value.data, h[i].value.len);
-        *buf++ = '\0';
-
-        apr_table_addn(req->headers_out, key, value);
-        ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                       "ModSecurity: load headers out: \"%V: %V\"",
-                       &h[i].key, &h[i].value);
-
-    }
-
-    for (i = 0; special_headers_out[i].name; i++) {
-
-        vv = ngx_http_get_variable(r, &special_headers_out[i].variable_name,
-                                   ngx_hash_key(special_headers_out[i].variable_name.data,
-                                                special_headers_out[i].variable_name.len));
-
-        if (vv && !vv->not_found) {
-
-            data = ngx_palloc(r->pool, vv->len + 1);
-            if (data == NULL) {
-                return NGX_ERROR;
-            }
-
-            ngx_memcpy(data,vv->data, vv->len);
-            data[vv->len] = '\0';
-
-            apr_table_setn(req->headers_out, special_headers_out[i].name, data);
-            ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                           "ModSecurity: load headers out: \"%s: %s\"",
-                           special_headers_out[i].name, data);
-        }
-    }
-
-    req->content_type = apr_table_get(ctx->req->headers_out, "Content-Type");
-    req->content_encoding = apr_table_get(ctx->req->headers_out, "Content-Encoding");
-
-    data = (char *)apr_table_get(ctx->req->headers_out, "Content-Languages");
-
-    if(data != NULL)
-    {
-        ctx->req->content_languages = apr_array_make(ctx->req->pool, 1, sizeof(const char *));
-        *(const char **)apr_array_push(ctx->req->content_languages) = data;
-    }
-
-    /* req->chunked = r->chunked; may be useless */
-    req->clength = r->headers_out.content_length_n;
-    req->mtime = apr_time_make(r->headers_out.last_modified_time, 0);
-
-    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                   "ModSecurity: load headers out done");
-
-    return NGX_OK;
-}
-
-
-static ngx_inline ngx_int_t
-ngx_http_modsecurity_save_headers_out(ngx_http_request_t *r)
-{
-    ngx_http_modsecurity_ctx_t      *ctx;
-    ngx_http_upstream_t             *upstream;
-
-    ctx = ngx_http_get_module_ctx(r, ngx_http_modsecurity);
-
-    /* r->chunked = ctx->req->chunked; */
-
-    ngx_http_clean_header(r);
-
-    upstream = r->upstream;
-    r->upstream = &ngx_http_modsecurity_upstream;
-
-    /* case SecServerSignature was used, the "Server: ..." header is added
-     * here, overwriting the default header supplied by nginx.
-     */
-    if (modsecIsServerSignatureAvailale() != NULL) {
-        apr_table_add(ctx->req->headers_out, "Server",
-                modsecIsServerSignatureAvailale());
-    }
-
-    if (apr_table_do(ngx_http_modsecurity_save_headers_out_visitor,
-                     r, ctx->req->headers_out, NULL) == 0) {
-
-        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                       "ModSecurity: save headers out error");
-
-        return NGX_ERROR;
-    }
-
-    r->upstream = upstream;
-
-    r->headers_out.status = ctx->req->status;
-    r->headers_out.status_line.data = (u_char *)ctx->req->status_line;
-    r->headers_out.status_line.len = ctx->req->status_line ?
-                                     ngx_strlen(ctx->req->status_line) : 0;
-
-    r->headers_out.content_length_n = ctx->req->clength;
-    r->headers_out.last_modified_time = apr_time_sec(ctx->req->mtime);
-
-    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                   "ModSecurity: save headers out done");
-
-    return NGX_OK;
-}
-
-
-static int
-ngx_http_modsecurity_save_headers_out_visitor(void *data, const char *key, const char *value)
-{
-    ngx_http_request_t             *r = data;
-    ngx_table_elt_t                *h, he;
-    ngx_http_upstream_header_t     *hh;
-    ngx_http_upstream_main_conf_t  *umcf;
-
-    umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module);
-
-    h = &he;
-
-    h->key.data = (u_char *)key;
-    h->key.len = ngx_strlen(key);
-
-    h->value.data = (u_char *)value;
-    h->value.len = ngx_strlen(value);
-
-    h->lowcase_key = ngx_palloc(r->pool, h->key.len);
-    if (h->lowcase_key == NULL) {
-        return 0;
-    }
-
-    ngx_strlow(h->lowcase_key, h->key.data, h->key.len);
-
-    h->hash = ngx_hash_key(h->lowcase_key, h->key.len);
-
-    hh = ngx_hash_find(&umcf->headers_in_hash, h->hash,
-                       h->lowcase_key, h->key.len);
-
-    if (hh) {
-        /* copy all */
-        if (hh->copy_handler(r, h, hh->conf) != NGX_OK) {
-            return 0;
-        }
-    }
-
-    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                   "ModSecurity: save headers out: \"%V: %V\"",
-                   &h->key, &h->value);
-
-    return 1;
-}
-
-
 static ngx_inline ngx_int_t
 ngx_http_modsecurity_status(int status)
 {

From 126eacfb350794ea04533749e6f9db2283de5b1b Mon Sep 17 00:00:00 2001
From: Vladimir Krivopalov <vlkrivop@microsoft.com>
Date: Fri, 8 Feb 2019 17:28:28 -0800
Subject: [PATCH 03/58] Remove 'inline' macro redefinition.

C++ Standard library does not accept re-defined keywords.

Signed-off-by: Vladimir Krivopalov <vlkrivop@microsoft.com>
---
 iis/main.cpp         | 1 -
 iis/moduleconfig.cpp | 1 -
 iis/mymodule.cpp     | 1 -
 3 files changed, 3 deletions(-)

diff --git a/iis/main.cpp b/iis/main.cpp
index 35bfa1dd6a..ff4a650a0f 100644
--- a/iis/main.cpp
+++ b/iis/main.cpp
@@ -15,7 +15,6 @@
 #define WIN32_LEAN_AND_MEAN
 
 #undef inline
-#define inline inline
 
 //  IIS7 Server API header file
 #include "httpserv.h"
diff --git a/iis/moduleconfig.cpp b/iis/moduleconfig.cpp
index b47a531a33..cccb25c742 100644
--- a/iis/moduleconfig.cpp
+++ b/iis/moduleconfig.cpp
@@ -15,7 +15,6 @@
 #define WIN32_LEAN_AND_MEAN
 
 #undef inline
-#define inline inline
 
 //  IIS7 Server API header file
 #include "httpserv.h"
diff --git a/iis/mymodule.cpp b/iis/mymodule.cpp
index f7ee79e25e..7cd4f7d92d 100644
--- a/iis/mymodule.cpp
+++ b/iis/mymodule.cpp
@@ -15,7 +15,6 @@
 #define WIN32_LEAN_AND_MEAN
 
 #undef inline
-#define inline inline
 
 //  IIS7 Server API header file
 #include <Windows.h>

From 1d7e3e285e9cd634cf9ced5215a333f213667079 Mon Sep 17 00:00:00 2001
From: Vladimir Krivopalov <vlkrivop@microsoft.com>
Date: Fri, 8 Feb 2019 17:29:10 -0800
Subject: [PATCH 04/58] Refactor main.cpp with C++ exception-safety and RAII.

Signed-off-by: Vladimir Krivopalov <vlkrivop@microsoft.com>
---
 iis/main.cpp          | 78 ++++++++++++-------------------------------
 iis/mymodulefactory.h |  2 +-
 2 files changed, 23 insertions(+), 57 deletions(-)

diff --git a/iis/main.cpp b/iis/main.cpp
index ff4a650a0f..289560189a 100644
--- a/iis/main.cpp
+++ b/iis/main.cpp
@@ -16,6 +16,8 @@
 
 #undef inline
 
+#include <memory>
+
 //  IIS7 Server API header file
 #include "httpserv.h"
 
@@ -24,78 +26,42 @@
 #include "mymodulefactory.h"
 
 //  Global server instance
-IHttpServer *                       g_pHttpServer = NULL;
+IHttpServer* g_pHttpServer = nullptr;
 
 //  Global module context id
-PVOID                               g_pModuleContext = NULL;
+void* g_pModuleContext = nullptr;
 
 //  The RegisterModule entrypoint implementation.
 //  This method is called by the server when the module DLL is 
 //  loaded in order to create the module factory,
 //  and register for server events.
-HRESULT
-__stdcall
-RegisterModule(
-    DWORD                           dwServerVersion,
-    IHttpModuleRegistrationInfo *   pModuleInfo,
-    IHttpServer *                   pHttpServer
-)
+HRESULT __stdcall
+RegisterModule(DWORD, IHttpModuleRegistrationInfo* moduleInfo, IHttpServer * httpServer)
 {
-    HRESULT                             hr = S_OK;
-    CMyHttpModuleFactory  *             pFactory = NULL;
-    //IHttpModuleRegistrationInfo2 *		pModuleInfo2;
-
-    if ( pModuleInfo == NULL || pHttpServer == NULL )
+    if (moduleInfo == nullptr || httpServer == nullptr)
     {
-        hr = HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
-        goto Finished;
+        return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
     }
 
-    /*hr = HttpGetExtendedInterface( g_pGlobalInfo, 
-                                   pModuleInfo, 
-                                   &pModuleInfo2 );
-    if ( FAILED ( hr ) )
-    {
-        goto Finished;
-    }*/
-
     // step 1: save the IHttpServer and the module context id for future use
 	//
-    g_pModuleContext = pModuleInfo->GetId();
-    g_pHttpServer = pHttpServer;
+    g_pModuleContext = moduleInfo->GetId();
+    g_pHttpServer = httpServer;
 
-    // step 2: create the module factory
-	//
-    pFactory = new CMyHttpModuleFactory();
-    if ( pFactory == NULL )
+    try
     {
-        hr = HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
-        goto Finished;
+        // step 2: create the module factory
+        //
+        auto factory = std::make_unique<CMyHttpModuleFactory>();
+
+        // step 3: register for server events
+        //
+        return moduleInfo->SetRequestNotifications(factory.release(), /* module factory */
+                                                    RQ_BEGIN_REQUEST /* server event mask */,
+                                                    0 /* server post event mask */);
     }
-
-    // step 3: register for server events
-	//
-    hr = pModuleInfo->SetRequestNotifications( pFactory, /* module factory */
-                                               RQ_BEGIN_REQUEST | RQ_SEND_RESPONSE /* server event mask */,
-                                               RQ_END_REQUEST /* server post event mask */);
-    if ( FAILED( hr ) )
+    catch (const std::bad_alloc&)
     {
-        goto Finished;
+        return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
     }
-
-	hr = pModuleInfo->SetPriorityForRequestNotification(RQ_BEGIN_REQUEST, PRIORITY_ALIAS_FIRST);
-	hr = pModuleInfo->SetPriorityForRequestNotification(RQ_SEND_RESPONSE, PRIORITY_ALIAS_LAST);	// reverted!
-	//hr = pModuleInfo2->SetPriorityForPostRequestNotification(RQ_END_REQUEST, PRIORITY_ALIAS_LAST);
-
-    pFactory = NULL;
-
-Finished:
-    
-/*    if ( pFactory != NULL )
-    {
-        delete pFactory;
-        pFactory = NULL;
-    }   */
-
-    return hr;
 }
diff --git a/iis/mymodulefactory.h b/iis/mymodulefactory.h
index 2e5a28f3aa..3130d568a1 100644
--- a/iis/mymodulefactory.h
+++ b/iis/mymodulefactory.h
@@ -24,7 +24,7 @@ class CMyHttpModuleFactory : public IHttpModuleFactory
 		CRITICAL_SECTION			m_csLock;
 
 public:
-	CMyHttpModuleFactory()
+    CMyHttpModuleFactory() /* noexcept */
 	{
 		m_pModule = NULL;
 

From caffae5de62187069ce641b190c2f0a84a344356 Mon Sep 17 00:00:00 2001
From: Vladimir Krivopalov <vlkrivop@microsoft.com>
Date: Mon, 11 Feb 2019 09:27:30 -0800
Subject: [PATCH 05/58] Module factory class clean-up and refactoring.

Use idiomatic constructs from C++ Standard Library.

Signed-off-by: Vladimir Krivopalov <vlkrivop@microsoft.com>
---
 iis/mymodulefactory.h | 80 ++++++++++++++++---------------------------
 1 file changed, 30 insertions(+), 50 deletions(-)

diff --git a/iis/mymodulefactory.h b/iis/mymodulefactory.h
index 3130d568a1..1127f0048b 100644
--- a/iis/mymodulefactory.h
+++ b/iis/mymodulefactory.h
@@ -12,75 +12,55 @@
 * directly using the email address security@modsecurity.org.
 */
 
-#ifndef __MODULE_FACTORY_H__
-#define __MODULE_FACTORY_H__
+#pragma once
+
+#include <memory>
+#include <mutex>
 
 // Factory class for CMyHttpModule.
 // This class is responsible for creating instances
 // of CMyHttpModule for each request.
 class CMyHttpModuleFactory : public IHttpModuleFactory
 {
-        CMyHttpModule *				m_pModule;
-		CRITICAL_SECTION			m_csLock;
-
 public:
-    CMyHttpModuleFactory() /* noexcept */
-	{
-		m_pModule = NULL;
+    CMyHttpModuleFactory() /* noexcept */ = default;
 
-		InitializeCriticalSection(&m_csLock);
-	}
-
-	virtual
-    HRESULT
-    GetHttpModule(
-        OUT CHttpModule            **ppModule, 
-        IN IModuleAllocator        *
-    )
+    HRESULT GetHttpModule(CHttpModule** ppModule, IModuleAllocator*) override
     {
-        HRESULT                    hr = S_OK;
-
-	    if ( ppModule == NULL )
+	    if (ppModule == nullptr)
         {
-            hr = HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
-            goto Finished;
+            return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
         }
 
-		EnterCriticalSection(&m_csLock);
-
-		if(m_pModule == NULL)
-		{
-			m_pModule = new CMyHttpModule();
-
-			if ( m_pModule == NULL )
-			{
-				hr = HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
-				goto Finished;
-			}
-		}
-
-		LeaveCriticalSection(&m_csLock);
-
-        *ppModule = m_pModule;
-
-	Finished:
+        try
+        {
+            // In the unlikely case if the module allocation fails,
+            // the init_flag will not be set and the next time another
+            // attempt will be made to initialize the module.
+            std::call_once(init_flag, [this] {
+                this->module = std::make_unique<CMyHttpModule>();
+            });
+        }
+        catch (const std::bad_alloc&) 
+        {
+            return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
+        }
 
-        return hr;
+        *ppModule = module.get();
+        return S_OK;
     }
 
-    virtual 
-    void
-    Terminate()
+    void Terminate() override
     {
-        if ( m_pModule != NULL )
+        if (module)
         {
-			//m_pModule->WriteEventViewerLog("Module terminated.");
-            delete m_pModule;
-            m_pModule = NULL;
+            module.reset();
         }
 
         delete this;
     }
-};
 
-#endif
+private:
+    std::unique_ptr<CMyHttpModule> module;
+    std::once_flag init_flag;
+};
\ No newline at end of file

From 9e75d91a55d15e1eb54c05a3dd6d0de99ea0bc0d Mon Sep 17 00:00:00 2001
From: Vladimir Krivopalov <vlkrivop@microsoft.com>
Date: Mon, 11 Feb 2019 14:55:45 -0800
Subject: [PATCH 06/58] Add RAII wrapper for Windows CRITICAL_SECTION
 primitive.

Signed-off-by: Vladimir Krivopalov <vlkrivop@microsoft.com>
---
 iis/critical_section.h | 51 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 51 insertions(+)
 create mode 100644 iis/critical_section.h

diff --git a/iis/critical_section.h b/iis/critical_section.h
new file mode 100644
index 0000000000..14026be180
--- /dev/null
+++ b/iis/critical_section.h
@@ -0,0 +1,51 @@
+/*
+* ModSecurity for Apache 2.x, http://www.modsecurity.org/
+* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/)
+*
+* You may not use this file except in compliance with
+* the License.  You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* If any of the files related to licensing are missing or if you have any
+* other questions related to licensing please contact Trustwave Holdings, Inc.
+* directly using the email address security@modsecurity.org.
+*/
+
+#pragma once
+
+#include <Windows.h>
+
+#include <mutex>
+
+// Implements BasicLockable requirements:
+//      https://en.cppreference.com/w/cpp/named_req/BasicLockable
+//
+class CriticalSection
+{
+public:
+    CriticalSection()
+    {
+        InitializeCriticalSection(&cs);
+    }
+
+    void lock()
+    {
+        EnterCriticalSection(&cs);
+    }
+
+    void unlock()
+    {
+        LeaveCriticalSection(&cs);
+    }
+
+    ~CriticalSection()
+    {
+        DeleteCriticalSection(&cs);
+    }
+
+private:
+    CRITICAL_SECTION cs;
+};
+
+using CriticalSectionLock = std::unique_lock<CriticalSection>;
\ No newline at end of file

From ef2237447d42920ebf97957f4daefc4cd9e697fe Mon Sep 17 00:00:00 2001
From: Vladimir Krivopalov <vlkrivop@microsoft.com>
Date: Mon, 11 Feb 2019 14:57:28 -0800
Subject: [PATCH 07/58] HttpModule initial code clean-up and refactoring.

- Use RAII wrapper for locking CRITICAL_SECTION
- Use RAII wrappers for Apache structures
- Get rid of 'goto's in OnBeginRequest

Signed-off-by: Vladimir Krivopalov <vlkrivop@microsoft.com>
---
 iis/mymodule.cpp | 428 +++++++++++++++++++++++------------------------
 iis/mymodule.h   |   8 +-
 2 files changed, 216 insertions(+), 220 deletions(-)

diff --git a/iis/mymodule.cpp b/iis/mymodule.cpp
index 7cd4f7d92d..b55716ce6e 100644
--- a/iis/mymodule.cpp
+++ b/iis/mymodule.cpp
@@ -16,6 +16,8 @@
 
 #undef inline
 
+#include <memory>
+
 //  IIS7 Server API header file
 #include <Windows.h>
 #include <sal.h>
@@ -31,61 +33,113 @@
 
 #include "winsock2.h"
 
+// These helpers make sure that the underlying structures
+// are correctly released on any exit path due to RAII.
+using ConnRecPtr =
+    std::unique_ptr<conn_rec, decltype(modsecFinishConnection)*>;
+
+using RequestRecPtr =
+    std::unique_ptr<request_rec, decltype(modsecFinishRequest)*>;
 
-class REQUEST_STORED_CONTEXT : public IHttpStoredContext
+ConnRecPtr MakeConnReq()
 {
- public:
-    REQUEST_STORED_CONTEXT()
-	{
-		m_pConnRec = NULL;
-		m_pRequestRec = NULL;
-		m_pHttpContext = NULL;
-		m_pProvider = NULL;
-		m_pResponseBuffer = NULL;
-		m_pResponseLength = 0;
-		m_pResponsePosition = 0;
-	}
+    ConnRecPtr c{modsecNewConnection(), modsecFinishConnection};
+    modsecProcessConnection(c.get());
+    return c;
+}
 
-    ~REQUEST_STORED_CONTEXT()
-	{
-		FinishRequest();
-	}
-    
-    // virtual
-    VOID
-    CleanupStoredContext(
-        VOID
-    )
+RequestRecPtr MakeRequestRec(conn_rec* c, directory_config* config)
+{
+    return {modsecNewRequest(c, config), modsecFinishRequest};
+}
+
+class RequestStoredContext
+    : public IHttpStoredContext
+{
+public:
+    RequestStoredContext(directory_config* config,
+            IHttpContext* httpContext, IHttpEventProvider* provider)
+        : connRec(MakeConnReq())
+        , requestRec(MakeRequestRec(connRec.get(), config))
+        , httpContext(httpContext)
+        , provider(provider)
+    {}
+
+    RequestStoredContext(const RequestStoredContext&) = delete;
+    RequestStoredContext& operator=(const RequestStoredContext&) = delete;
+
+    // NB: these could have been defaulted with '= default' but VS2013 doesn't support it...
+    RequestStoredContext(RequestStoredContext&& rhs)
+        : connRec(std::move(rhs.connRec))
+        , requestRec(std::move(rhs.requestRec))
+        , httpContext(rhs.httpContext)
+        , provider(rhs.provider)
+    {}
+
+    RequestStoredContext& operator=(RequestStoredContext&& rhs)
+    {
+        connRec = std::move(rhs.connRec);
+        requestRec = std::move(rhs.requestRec);
+        httpContext = rhs.httpContext;
+        provider = rhs.provider;
+        return *this;
+    }
+
+    void CleanupStoredContext() override
     {
-		FinishRequest();
         delete this;
     }
 
-	void FinishRequest()
-	{
-		if(m_pRequestRec != NULL)
-		{
-			modsecFinishRequest(m_pRequestRec);
-			m_pRequestRec = NULL;
-		}
-		if(m_pConnRec != NULL)
-		{
-			modsecFinishConnection(m_pConnRec);
-			m_pConnRec = NULL;
-		}
-	}
+    conn_rec* Connection() const
+    {
+        return connRec.get();
+    }
 
-	conn_rec			*m_pConnRec;
-	request_rec			*m_pRequestRec;
-	IHttpContext		*m_pHttpContext;
-	IHttpEventProvider	*m_pProvider;
-	char				*m_pResponseBuffer;
-	ULONGLONG			m_pResponseLength;
-	ULONGLONG			m_pResponsePosition;
-};
+    request_rec* Request() const
+    {
+        return requestRec.get();
+    }
 
+    IHttpContext* HttpContext() const
+    {
+        return httpContext;
+    }
 
-//----------------------------------------------------------------------------
+    IHttpEventProvider* Provider() const
+    {
+        return provider;
+    }
+
+    char*& ResponseBuffer()
+    {
+        return responseBuffer;
+    }
+
+    ULONGLONG& ResponseLength()
+    {
+        return responseLength;
+    }
+
+    ULONGLONG& ResponsePosition()
+    {
+        return responsePosition;
+    }
+
+    void FinishRequest()
+    {
+        requestRec.reset();
+        connRec.reset();
+    }
+
+private:
+	ConnRecPtr connRec;
+	RequestRecPtr requestRec;
+	IHttpContext* httpContext;
+	IHttpEventProvider* provider;
+    char* responseBuffer = nullptr;
+    ULONGLONG responseLength = 0;
+    ULONGLONG responsePosition = 0;
+};
 
 char *GetIpAddr(apr_pool_t *pool, PSOCKADDR pAddr)
 {
@@ -247,18 +301,18 @@ void Log(void *obj, int level, char *str)
 
 #define NOTE_IIS "iis-tx-context"
 
-void StoreIISContext(request_rec *r, REQUEST_STORED_CONTEXT *rsc)
+void StoreIISContext(request_rec *r, RequestStoredContext *rsc)
 {
     apr_table_setn(r->notes, NOTE_IIS, (const char *)rsc);
 }
 
-REQUEST_STORED_CONTEXT *RetrieveIISContext(request_rec *r)
+RequestStoredContext *RetrieveIISContext(request_rec *r)
 {
-    REQUEST_STORED_CONTEXT *msr = NULL;
+    RequestStoredContext *msr = NULL;
     request_rec *rx = NULL;
 
     /* Look in the current request first. */
-    msr = (REQUEST_STORED_CONTEXT *)apr_table_get(r->notes, NOTE_IIS);
+    msr = (RequestStoredContext *)apr_table_get(r->notes, NOTE_IIS);
     if (msr != NULL) {
         //msr->r = r;
         return msr;
@@ -266,7 +320,7 @@ REQUEST_STORED_CONTEXT *RetrieveIISContext(request_rec *r)
 
     /* If this is a subrequest then look in the main request. */
     if (r->main != NULL) {
-        msr = (REQUEST_STORED_CONTEXT *)apr_table_get(r->main->notes, NOTE_IIS);
+        msr = (RequestStoredContext *)apr_table_get(r->main->notes, NOTE_IIS);
         if (msr != NULL) {
             //msr->r = r;
             return msr;
@@ -276,7 +330,7 @@ REQUEST_STORED_CONTEXT *RetrieveIISContext(request_rec *r)
     /* If the request was redirected then look in the previous requests. */
     rx = r->prev;
     while(rx != NULL) {
-        msr = (REQUEST_STORED_CONTEXT *)apr_table_get(rx->notes, NOTE_IIS);
+        msr = (RequestStoredContext *)apr_table_get(rx->notes, NOTE_IIS);
         if (msr != NULL) {
             //msr->r = r;
             return msr;
@@ -419,15 +473,12 @@ CMyHttpModule::OnSendResponse(
     IN ISendResponseProvider * pResponseProvider
 )
 {
-	REQUEST_STORED_CONTEXT *rsc = NULL;
-
-	rsc = (REQUEST_STORED_CONTEXT *)pHttpContext->GetModuleContextContainer()->GetModuleContext(g_pModuleContext);
-
-	EnterCriticalSection(&m_csLock);
+    RequestStoredContext* rsc = dynamic_cast<RequestStoredContext*>(pHttpContext->GetModuleContextContainer()->GetModuleContext(g_pModuleContext));
 
+    CriticalSectionLock lock{cs};
 	// here we must check if response body processing is enabled
 	//
-	if(rsc == NULL || rsc->m_pRequestRec == NULL || rsc->m_pResponseBuffer != NULL || !modsecIsResponseBodyAccessEnabled(rsc->m_pRequestRec))
+	if(rsc == nullptr || rsc->Request() == nullptr || rsc->ResponseBuffer() != nullptr || !modsecIsResponseBodyAccessEnabled(rsc->Request()))
 	{
 		goto Exit;
 	}
@@ -441,7 +492,7 @@ CMyHttpModule::OnSendResponse(
     REQUEST_NOTIFICATION_STATUS ret = RQ_NOTIFICATION_CONTINUE;
 	ULONGLONG ulTotalLength = 0;
 	DWORD c;
-	request_rec *r = rsc->m_pRequestRec;
+    request_rec *r = rsc->Request();
 
 	pHttpResponse = pHttpContext->GetResponse();
 	pRawHttpResponse = pHttpResponse->GetRawHttpResponse();
@@ -583,7 +634,7 @@ CMyHttpModule::OnSendResponse(
         }
     }
 
-	rsc->m_pResponseBuffer = (char *)apr_palloc(rsc->m_pRequestRec->pool, ulTotalLength);
+	rsc->ResponseBuffer() = (char *)apr_palloc(rsc->Request()->pool, ulTotalLength);
 
 	ulTotalLength = 0;
 
@@ -594,13 +645,13 @@ CMyHttpModule::OnSendResponse(
         switch( pSourceDataChunk->DataChunkType )
         {
             case HttpDataChunkFromMemory:
-				memcpy(rsc->m_pResponseBuffer + ulTotalLength, pSourceDataChunk->FromMemory.pBuffer, pSourceDataChunk->FromMemory.BufferLength);
+				memcpy(rsc->ResponseBuffer() + ulTotalLength, pSourceDataChunk->FromMemory.pBuffer, pSourceDataChunk->FromMemory.BufferLength);
                 ulTotalLength += pSourceDataChunk->FromMemory.BufferLength;
                 break;
             case HttpDataChunkFromFileHandle:
                 pFileByteRange = &pSourceDataChunk->FromFileHandle.ByteRange;
 
-				if(ReadFileChunk(pSourceDataChunk, rsc->m_pResponseBuffer + ulTotalLength) != S_OK)
+				if(ReadFileChunk(pSourceDataChunk, rsc->ResponseBuffer() + ulTotalLength) != S_OK)
 				{
 			        DWORD dwErr = GetLastError();
 
@@ -618,7 +669,7 @@ CMyHttpModule::OnSendResponse(
         }
     }
 
-	rsc->m_pResponseLength = ulTotalLength;
+	rsc->ResponseLength() = ulTotalLength;
 
 	//
     // If there's no content-length set, we need to set it to avoid chunked transfer mode
@@ -659,7 +710,7 @@ CMyHttpModule::OnSendResponse(
 
 Finished:
 
-	int status = modsecProcessResponse(rsc->m_pRequestRec);
+	int status = modsecProcessResponse(rsc->Request());
 
 	// the logic here is temporary, needs clarification
 	//
@@ -670,8 +721,6 @@ CMyHttpModule::OnSendResponse(
 		pHttpContext->SetRequestHandled();
 
 		rsc->FinishRequest();
-
-		LeaveCriticalSection(&m_csLock);
 		
 		return RQ_NOTIFICATION_FINISH_REQUEST;
 	}
@@ -680,8 +729,6 @@ CMyHttpModule::OnSendResponse(
 	//
 	if(rsc != NULL)
 		rsc->FinishRequest();
-
-	LeaveCriticalSection(&m_csLock);
 		
 	return RQ_NOTIFICATION_CONTINUE;
 }
@@ -692,146 +739,106 @@ CMyHttpModule::OnPostEndRequest(
     IN IHttpEventProvider * pProvider
 )
 {
-	REQUEST_STORED_CONTEXT *rsc = NULL;
-
-	rsc = (REQUEST_STORED_CONTEXT *)pHttpContext->GetModuleContextContainer()->GetModuleContext(g_pModuleContext);
+	RequestStoredContext* rsc = dynamic_cast<RequestStoredContext*>(pHttpContext->GetModuleContextContainer()->GetModuleContext(g_pModuleContext));
 
 	// only finish request if OnSendResponse have been called already
 	//
-	if(rsc != NULL && rsc->m_pResponseBuffer != NULL)
-	{
-		EnterCriticalSection(&m_csLock);
-
+	if(rsc != nullptr && rsc->ResponseBuffer() != nullptr)
+    {
+        CriticalSectionLock lock{cs};
 		rsc->FinishRequest();
-
-		LeaveCriticalSection(&m_csLock);
 	}
 
 	return RQ_NOTIFICATION_CONTINUE;
 }
 
 REQUEST_NOTIFICATION_STATUS
-CMyHttpModule::OnBeginRequest(
-    IN IHttpContext * pHttpContext,
-    IN IHttpEventProvider * pProvider
-)
+CMyHttpModule::OnBeginRequest(IHttpContext* httpContext, IHttpEventProvider* provider)
 {
-    HRESULT                         hr                  = S_OK;
-    IHttpRequest*                   pRequest            = NULL;
-	MODSECURITY_STORED_CONTEXT*		pConfig = NULL;
-    
-    UNREFERENCED_PARAMETER ( pProvider );
-
-	EnterCriticalSection(&m_csLock);
-
-    if ( pHttpContext == NULL ) 
+    if (httpContext == nullptr || httpContext->GetRequest() == nullptr)
     {
-        hr = E_UNEXPECTED;
-        goto Finished;
+        return RQ_NOTIFICATION_FINISH_REQUEST;
     }
 
-    pRequest = pHttpContext->GetRequest();
-
-    if ( pRequest == NULL )
+    CriticalSectionLock lock{cs};
+    MODSECURITY_STORED_CONTEXT* config = nullptr;
+    HRESULT hr = MODSECURITY_STORED_CONTEXT::GetConfig(httpContext, &config);
+    if (FAILED(hr))
     {
-        hr = E_UNEXPECTED;
-        goto Finished;
+        return RQ_NOTIFICATION_CONTINUE;
     }
 
-    hr = MODSECURITY_STORED_CONTEXT::GetConfig(pHttpContext, &pConfig );
-    
-    if ( FAILED( hr ) )
+    // If module is disabled, don't go any further
+    //
+    if (!config->GetIsEnabled())
     {
-        //hr = E_UNEXPECTED;
-		hr = S_OK;
-        goto Finished;
+        return RQ_NOTIFICATION_CONTINUE;
     }
 
-	// If module is disabled, dont go any further
-	//
-	if( pConfig->GetIsEnabled() == false )
-	{
-        goto Finished;
-	}
-
-	if(pConfig->m_Config == NULL)
-	{
-		char *path;
-		USHORT pathlen;
-
-		hr = pConfig->GlobalWideCharToMultiByte(pConfig->GetPath(), wcslen(pConfig->GetPath()), &path, &pathlen);
-
-		if ( FAILED( hr ) )
-		{
-			hr = E_UNEXPECTED;
-			goto Finished;
-		}
-
-		pConfig->m_Config = modsecGetDefaultConfig();
-
-		PCWSTR servpath = pHttpContext->GetApplication()->GetApplicationPhysicalPath();
-		char *apppath;
-		USHORT apppathlen;
-
-		hr = pConfig->GlobalWideCharToMultiByte((WCHAR *)servpath, wcslen(servpath), &apppath, &apppathlen);
-
-		if ( FAILED( hr ) )
-		{
-			delete path;
-			hr = E_UNEXPECTED;
-			goto Finished;
-		}
-
-		if(path[0] != 0)
-		{
-			const char * err = modsecProcessConfig((directory_config *)pConfig->m_Config, path, apppath);
-
-			if(err != NULL)
-			{
-				WriteEventViewerLog(err, EVENTLOG_ERROR_TYPE);
-				delete apppath;
-				delete path;
-				goto Finished;
-			}
+    if (config->m_Config == NULL)
+    {
+        char *path;
+        USHORT pathlen;
 
-			modsecReportRemoteLoadedRules();
-			if (this->status_call_already_sent == false)
-			{
-				this->status_call_already_sent = true;
-				modsecStatusEngineCall();
-			}
-		}
+        hr = config->GlobalWideCharToMultiByte(config->GetPath(), wcslen(config->GetPath()), &path, &pathlen);
+        if (FAILED(hr))
+        {
+            return RQ_NOTIFICATION_FINISH_REQUEST;
+        }
 
-		delete apppath;
-		delete path;
-	}
+        config->m_Config = modsecGetDefaultConfig();
 
-	conn_rec *c;
-	request_rec *r;
+        PCWSTR servpath = httpContext->GetApplication()->GetApplicationPhysicalPath();
+        char *apppath;
+        USHORT apppathlen;
 
-	c = modsecNewConnection();
+        hr = config->GlobalWideCharToMultiByte((WCHAR *)servpath, wcslen(servpath), &apppath, &apppathlen);
 
-	modsecProcessConnection(c);
+        if (FAILED(hr))
+        {
+            delete path;
+            return RQ_NOTIFICATION_FINISH_REQUEST;
+        }
 
-	r = modsecNewRequest(c, (directory_config *)pConfig->m_Config);
+        if (path[0] != 0)
+        {
+            const char * err = modsecProcessConfig((directory_config *)config->m_Config, path, apppath);
+
+            if (err != NULL)
+            {
+                WriteEventViewerLog(err, EVENTLOG_ERROR_TYPE);
+                delete apppath;
+                delete path;
+                return RQ_NOTIFICATION_CONTINUE;
+            }
+
+            modsecReportRemoteLoadedRules();
+            if (this->status_call_already_sent == false)
+            {
+                this->status_call_already_sent = true;
+                modsecStatusEngineCall();
+            }
+        }
 
-	// on IIS we force input stream inspection flag, because its absence does not add any performance gain
-	// it's because on IIS request body must be restored each time it was read
-	//
-	modsecSetConfigForIISRequestBody(r);
+        delete apppath;
+        delete path;
+    }
 
-	REQUEST_STORED_CONTEXT *rsc = new REQUEST_STORED_CONTEXT();
+    auto rsc = std::make_unique<RequestStoredContext>(
+        static_cast<directory_config*>(config->m_Config), httpContext, provider);
+    conn_rec* c = rsc->Connection();
+    request_rec* r = rsc->Request();
 
-	rsc->m_pConnRec = c;
-	rsc->m_pRequestRec = r;
-	rsc->m_pHttpContext = pHttpContext;
-	rsc->m_pProvider = pProvider;
+    // on IIS we force input stream inspection flag, because its absence does not add any performance gain
+    // it's because on IIS request body must be restored each time it was read
+    //
+    modsecSetConfigForIISRequestBody(r);
 
-	pHttpContext->GetModuleContextContainer()->SetModuleContext(rsc, g_pModuleContext);
+    StoreIISContext(r, rsc.get());
 
-	StoreIISContext(r, rsc);
+    httpContext->GetModuleContextContainer()->SetModuleContext(rsc.release(), g_pModuleContext);
 
-	HTTP_REQUEST *req = pRequest->GetRawHttpRequest();
+	HTTP_REQUEST *req = httpContext->GetRequest()->GetRawHttpRequest();
 
 	r->hostname = ConvertUTF16ToUTF8(req->CookedUrl.pHost, req->CookedUrl.HostLength / sizeof(WCHAR), r->pool);
 	r->path_info = ConvertUTF16ToUTF8(req->CookedUrl.pAbsPath, req->CookedUrl.AbsPathLength / sizeof(WCHAR), r->pool);
@@ -1040,13 +1047,13 @@ CMyHttpModule::OnBeginRequest(
 	HTTP_REQUEST_ID httpRequestID;
 	char *pszValue = (char *)apr_palloc(r->pool, 24);
 
-	httpRequestID = pRequest->GetRawHttpRequest()->RequestId;
+	httpRequestID = httpContext->GetRequest()->GetRawHttpRequest()->RequestId;
 
 	_ui64toa(httpRequestID, pszValue, 10);
 
 	apr_table_setn(r->subprocess_env, "UNIQUE_ID", pszValue);
 
-	PSOCKADDR pAddr = pRequest->GetRemoteAddress();
+    PSOCKADDR pAddr = httpContext->GetRequest()->GetRemoteAddress();
 
 #if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER < 3
     c->remote_addr = CopySockAddr(r->pool, pAddr);
@@ -1057,33 +1064,25 @@ CMyHttpModule::OnBeginRequest(
 #endif
 	c->remote_host = NULL;
 
-    LeaveCriticalSection(&m_csLock);
-	int status = modsecProcessRequest(r);
-    EnterCriticalSection(&m_csLock);
+    lock.unlock();
+    int status = modsecProcessRequest(r);
+    lock.lock();
 
 	if(status != DECLINED)
 	{
-		pHttpContext->GetResponse()->SetStatus(status, "ModSecurity Action");
-		pHttpContext->SetRequestHandled();
+		httpContext->GetResponse()->SetStatus(status, "ModSecurity Action");
+		httpContext->SetRequestHandled();
 
-		hr = E_FAIL;
-		goto Finished;
+        return RQ_NOTIFICATION_FINISH_REQUEST;
 	}
 
-Finished:
-	LeaveCriticalSection(&m_csLock);
-
-    if ( FAILED( hr )  )
-    {
-        return RQ_NOTIFICATION_FINISH_REQUEST;
-    }
 	return RQ_NOTIFICATION_CONTINUE;
 }
 
 
 apr_status_t ReadBodyCallback(request_rec *r, char *buf, unsigned int length, unsigned int *readcnt, int *is_eos)
 {
-    REQUEST_STORED_CONTEXT *rsc = RetrieveIISContext(r);
+    RequestStoredContext *rsc = RetrieveIISContext(r);
 
     *readcnt = 0;
 
@@ -1093,7 +1092,7 @@ apr_status_t ReadBodyCallback(request_rec *r, char *buf, unsigned int length, un
         return APR_SUCCESS;
     }
 
-    IHttpContext *pHttpContext = rsc->m_pHttpContext;
+    IHttpContext *pHttpContext = rsc->HttpContext();
     IHttpRequest *pRequest = pHttpContext->GetRequest();
 
     if (pRequest->GetRemainingEntityBytes() == 0)
@@ -1110,7 +1109,7 @@ apr_status_t ReadBodyCallback(request_rec *r, char *buf, unsigned int length, un
         if (ERROR_HANDLE_EOF != (hr & 0x0000FFFF))
         {
             // Set the error status.
-            rsc->m_pProvider->SetErrorStatus(hr);
+            rsc->Provider()->SetErrorStatus(hr);
         }
 
         *is_eos = 1;
@@ -1121,12 +1120,12 @@ apr_status_t ReadBodyCallback(request_rec *r, char *buf, unsigned int length, un
 
 apr_status_t WriteBodyCallback(request_rec *r, char *buf, unsigned int length)
 {
-	REQUEST_STORED_CONTEXT *rsc = RetrieveIISContext(r);
+	RequestStoredContext *rsc = RetrieveIISContext(r);
 
-	if(rsc == NULL || rsc->m_pRequestRec == NULL)
+	if(rsc == NULL || rsc->Request() == NULL)
 		return APR_SUCCESS;
 
-	IHttpContext *pHttpContext = rsc->m_pHttpContext;
+	IHttpContext *pHttpContext = rsc->HttpContext();
 	IHttpRequest *pHttpRequest = pHttpContext->GetRequest();
 
     CHAR szLength[21]; //Max length for a 64 bit int is 20
@@ -1184,11 +1183,11 @@ apr_status_t WriteBodyCallback(request_rec *r, char *buf, unsigned int length)
 
 apr_status_t ReadResponseCallback(request_rec *r, char *buf, unsigned int length, unsigned int *readcnt, int *is_eos)
 {
-	REQUEST_STORED_CONTEXT *rsc = RetrieveIISContext(r);
+	RequestStoredContext* rsc = RetrieveIISContext(r);
 
 	*readcnt = 0;
 
-	if(rsc == NULL || rsc->m_pResponseBuffer == NULL)
+	if(rsc == nullptr || rsc->ResponseBuffer() == nullptr)
 	{
 		*is_eos = 1;
 		return APR_SUCCESS;
@@ -1196,15 +1195,15 @@ apr_status_t ReadResponseCallback(request_rec *r, char *buf, unsigned int length
 
 	unsigned int size = length;
 
-	if(size > rsc->m_pResponseLength - rsc->m_pResponsePosition)
-		size = rsc->m_pResponseLength - rsc->m_pResponsePosition;
+	if(size > rsc->ResponseLength() - rsc->ResponsePosition())
+		size = rsc->ResponseLength() - rsc->ResponsePosition();
 
-	memcpy(buf, rsc->m_pResponseBuffer + rsc->m_pResponsePosition, size);
+	memcpy(buf, rsc->ResponseBuffer() + rsc->ResponsePosition(), size);
 
 	*readcnt = size;
-	rsc->m_pResponsePosition += size;
+	rsc->ResponsePosition() += size;
 
-	if(rsc->m_pResponsePosition >= rsc->m_pResponseLength)
+	if(rsc->ResponsePosition() >= rsc->ResponseLength())
 		*is_eos = 1;
 
 	return APR_SUCCESS;
@@ -1212,15 +1211,15 @@ apr_status_t ReadResponseCallback(request_rec *r, char *buf, unsigned int length
 
 apr_status_t WriteResponseCallback(request_rec *r, char *buf, unsigned int length)
 {
-	REQUEST_STORED_CONTEXT *rsc = RetrieveIISContext(r);
+	RequestStoredContext* rsc = RetrieveIISContext(r);
 
-	if(rsc == NULL || rsc->m_pRequestRec == NULL || rsc->m_pResponseBuffer == NULL)
+	if(rsc == nullptr || rsc->Request() == nullptr || rsc->ResponseBuffer() == nullptr)
 		return APR_SUCCESS;
 
-	IHttpContext *pHttpContext = rsc->m_pHttpContext;
+	IHttpContext *pHttpContext = rsc->HttpContext();
 	IHttpResponse *pHttpResponse = pHttpContext->GetResponse();
 	HTTP_RESPONSE *pRawHttpResponse = pHttpResponse->GetRawHttpResponse();
-	HTTP_DATA_CHUNK *pDataChunk = (HTTP_DATA_CHUNK *)apr_palloc(rsc->m_pRequestRec->pool, sizeof(HTTP_DATA_CHUNK));
+	HTTP_DATA_CHUNK *pDataChunk = (HTTP_DATA_CHUNK *)apr_palloc(rsc->Request()->pool, sizeof(HTTP_DATA_CHUNK));
 
 	pRawHttpResponse->EntityChunkCount = 0;
 
@@ -1270,15 +1269,8 @@ CMyHttpModule::CMyHttpModule()
     // Open a handle to the Event Viewer.
     m_hEventLog = RegisterEventSource( NULL, "ModSecurity" );
 
-    SYSTEM_INFO         sysInfo;
-
-    GetSystemInfo(&sysInfo);
-    m_dwPageSize = sysInfo.dwPageSize;
-
     this->status_call_already_sent = false;
 
-	InitializeCriticalSection(&m_csLock);
-
 	modsecSetLogHook(this, Log);
 
 	modsecSetReadBody(ReadBodyCallback);
@@ -1294,6 +1286,10 @@ CMyHttpModule::CMyHttpModule()
 
 	s->server_hostname = compname;
 
+    SYSTEM_INFO         sysInfo;
+    GetSystemInfo(&sysInfo);
+    m_dwPageSize = sysInfo.dwPageSize;
+
 	modsecStartConfig();
 
 	modsecFinalizeConfig();
@@ -1316,8 +1312,6 @@ CMyHttpModule::~CMyHttpModule()
         // Close the handle to the Event Viewer.
         DeregisterEventSource( m_hEventLog );
         m_hEventLog = NULL;
-
-		DeleteCriticalSection(&m_csLock);
     }
 }
 
diff --git a/iis/mymodule.h b/iis/mymodule.h
index eb7a4b0163..7ad4d7ac3e 100644
--- a/iis/mymodule.h
+++ b/iis/mymodule.h
@@ -15,6 +15,8 @@
 #ifndef __MY_MODULE_H__
 #define __MY_MODULE_H__
 
+#include "critical_section.h"
+
 //  The module implementation.
 //  This class is responsible for implementing the 
 //  module functionality for each of the server events
@@ -22,9 +24,9 @@
 class CMyHttpModule : public CHttpModule
 {
 public:
-    HANDLE				m_hEventLog;
-    DWORD				m_dwPageSize;
-	CRITICAL_SECTION	m_csLock;
+    HANDLE m_hEventLog;
+    DWORD m_dwPageSize;
+    CriticalSection cs;
 
     REQUEST_NOTIFICATION_STATUS
     OnBeginRequest(

From 8872596dcbfb1c6bb87e82951314cf2c361c22c3 Mon Sep 17 00:00:00 2001
From: Vladimir Krivopalov <vlkrivop@microsoft.com>
Date: Mon, 11 Feb 2019 15:12:24 -0800
Subject: [PATCH 08/58] Get rid of void* -> directory_config* casts.

Signed-off-by: Vladimir Krivopalov <vlkrivop@microsoft.com>
---
 iis/moduleconfig.cpp |  3 +--
 iis/moduleconfig.h   |  4 +++-
 iis/mymodule.cpp     | 10 ++++------
 3 files changed, 8 insertions(+), 9 deletions(-)

diff --git a/iis/moduleconfig.cpp b/iis/moduleconfig.cpp
index cccb25c742..8f90a8a018 100644
--- a/iis/moduleconfig.cpp
+++ b/iis/moduleconfig.cpp
@@ -464,8 +464,7 @@ MODSECURITY_STORED_CONTEXT::~MODSECURITY_STORED_CONTEXT()
 
 MODSECURITY_STORED_CONTEXT::MODSECURITY_STORED_CONTEXT():
     m_bIsEnabled ( FALSE ),
-    m_pszPath( NULL ),
-	m_Config( NULL )
+    m_pszPath( NULL )
 {
 }
 
diff --git a/iis/moduleconfig.h b/iis/moduleconfig.h
index 2729006c70..a59c45e47f 100644
--- a/iis/moduleconfig.h
+++ b/iis/moduleconfig.h
@@ -22,6 +22,8 @@ extern IHttpServer *                       g_pHttpServer;
 
 extern PVOID                               g_pModuleContext;
 
+struct directory_config; // forward declaration
+
 class MODSECURITY_STORED_CONTEXT : public IHttpStoredContext
 {
  public:
@@ -67,7 +69,7 @@ class MODSECURITY_STORED_CONTEXT : public IHttpStoredContext
             CHAR**  ppszDestination,
             USHORT*  pdwLengthDestination );
 
-	void*			  m_Config;
+    directory_config* config = nullptr;
 
 private:
     HRESULT 
diff --git a/iis/mymodule.cpp b/iis/mymodule.cpp
index b55716ce6e..db0a2184c0 100644
--- a/iis/mymodule.cpp
+++ b/iis/mymodule.cpp
@@ -775,7 +775,7 @@ CMyHttpModule::OnBeginRequest(IHttpContext* httpContext, IHttpEventProvider* pro
         return RQ_NOTIFICATION_CONTINUE;
     }
 
-    if (config->m_Config == NULL)
+    if (config->config == nullptr)
     {
         char *path;
         USHORT pathlen;
@@ -786,14 +786,13 @@ CMyHttpModule::OnBeginRequest(IHttpContext* httpContext, IHttpEventProvider* pro
             return RQ_NOTIFICATION_FINISH_REQUEST;
         }
 
-        config->m_Config = modsecGetDefaultConfig();
+        config->config = modsecGetDefaultConfig();
 
         PCWSTR servpath = httpContext->GetApplication()->GetApplicationPhysicalPath();
         char *apppath;
         USHORT apppathlen;
 
         hr = config->GlobalWideCharToMultiByte((WCHAR *)servpath, wcslen(servpath), &apppath, &apppathlen);
-
         if (FAILED(hr))
         {
             delete path;
@@ -802,7 +801,7 @@ CMyHttpModule::OnBeginRequest(IHttpContext* httpContext, IHttpEventProvider* pro
 
         if (path[0] != 0)
         {
-            const char * err = modsecProcessConfig((directory_config *)config->m_Config, path, apppath);
+            const char * err = modsecProcessConfig(config->config, path, apppath);
 
             if (err != NULL)
             {
@@ -824,8 +823,7 @@ CMyHttpModule::OnBeginRequest(IHttpContext* httpContext, IHttpEventProvider* pro
         delete path;
     }
 
-    auto rsc = std::make_unique<RequestStoredContext>(
-        static_cast<directory_config*>(config->m_Config), httpContext, provider);
+    auto rsc = std::make_unique<RequestStoredContext>(config->config, httpContext, provider);
     conn_rec* c = rsc->Connection();
     request_rec* r = rsc->Request();
 

From 5b77e3d757e8b33b8bdf98a08715310c03096c74 Mon Sep 17 00:00:00 2001
From: Vladimir Krivopalov <vlkrivop@microsoft.com>
Date: Mon, 11 Feb 2019 15:52:18 -0800
Subject: [PATCH 09/58] Add EventLogger wrapper around Windows event log
 handle.

Signed-off-by: Vladimir Krivopalov <vlkrivop@microsoft.com>
---
 iis/event_logger.h | 46 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 46 insertions(+)
 create mode 100644 iis/event_logger.h

diff --git a/iis/event_logger.h b/iis/event_logger.h
new file mode 100644
index 0000000000..9eb1b67868
--- /dev/null
+++ b/iis/event_logger.h
@@ -0,0 +1,46 @@
+/*
+* ModSecurity for Apache 2.x, http://www.modsecurity.org/
+* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/)
+*
+* You may not use this file except in compliance with
+* the License.  You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* If any of the files related to licensing are missing or if you have any
+* other questions related to licensing please contact Trustwave Holdings, Inc.
+* directly using the email address security@modsecurity.org.
+*/
+
+#pragma once
+
+#include <Windows.h>
+
+class EventLogger
+{
+public:
+    EventLogger() /* noexcept */
+    {
+        handle = RegisterEventSource(nullptr, "ModSecurity");
+    }
+
+    BOOL Log(const char* message, DWORD category)
+    {
+        if (handle != nullptr)
+        {
+            return ReportEvent(
+                handle,
+                category, 0, 0x1,
+                NULL, 1, 0, &message, NULL);
+        }
+        return FALSE;
+    }
+
+    ~EventLogger()
+    {
+        DeregisterEventSource(handle);
+    }
+
+private:
+    HANDLE handle;
+};
\ No newline at end of file

From 5ef8094bfec8c28aa11113f0e5de7aec86f5a879 Mon Sep 17 00:00:00 2001
From: Vladimir Krivopalov <vlkrivop@microsoft.com>
Date: Mon, 11 Feb 2019 15:52:43 -0800
Subject: [PATCH 10/58] Clean-up HttpModule class members.

- Use event log handle wrapper
- Use built-in 'bool' type instead of the 'BOOL' typedef for consistency
- Make class members private
- Check memory allocation in the class constructor to avoid NULL pointer dereference

Signed-off-by: Vladimir Krivopalov <vlkrivop@microsoft.com>
---
 iis/mymodule.cpp | 86 ++++++++++++++----------------------------------
 iis/mymodule.h   | 37 +++++++++------------
 2 files changed, 39 insertions(+), 84 deletions(-)

diff --git a/iis/mymodule.cpp b/iis/mymodule.cpp
index db0a2184c0..f08c038367 100644
--- a/iis/mymodule.cpp
+++ b/iis/mymodule.cpp
@@ -283,7 +283,7 @@ char *ConvertUTF16ToUTF8( __in const WCHAR * pszTextUTF16, size_t cchUTF16, apr_
     return pszUTF8;
 }
  
-void Log(void *obj, int level, char *str)
+static void Log(void *obj, int level, char *str)
 {
 	CMyHttpModule *mod = (CMyHttpModule *)obj;
 	WORD logcat = EVENTLOG_INFORMATION_TYPE;
@@ -380,13 +380,13 @@ HRESULT CMyHttpModule::ReadFileChunk(HTTP_DATA_CHUNK *chunk, char *buf)
 		ZeroMemory(&ovl, sizeof ovl);
 		ovl.hEvent     = hIoEvent;
 		ovl.Offset = (DWORD)offset;
-		dwDataStartOffset = ovl.Offset & (m_dwPageSize - 1);
-		ovl.Offset &= ~(m_dwPageSize - 1);
+		dwDataStartOffset = ovl.Offset & (pageSize - 1);
+		ovl.Offset &= ~(pageSize - 1);
 		ovl.OffsetHigh = offset >> 32;
 
 		if (!ReadFile(chunk->FromFileHandle.FileHandle,
 					  pIoBuffer,
-					  m_dwPageSize,
+					  pageSize,
 					  &bytesRead,
 					  &ovl))
 		{
@@ -812,9 +812,9 @@ CMyHttpModule::OnBeginRequest(IHttpContext* httpContext, IHttpEventProvider* pro
             }
 
             modsecReportRemoteLoadedRules();
-            if (this->status_call_already_sent == false)
+            if (!statusCallAlreadySent)
             {
-                this->status_call_already_sent = true;
+                statusCallAlreadySent = true;
                 modsecStatusEngineCall();
             }
         }
@@ -1261,56 +1261,27 @@ apr_status_t WriteResponseCallback(request_rec *r, char *buf, unsigned int lengt
 	return APR_SUCCESS;
 }
 
-
 CMyHttpModule::CMyHttpModule()
 {
-    // Open a handle to the Event Viewer.
-    m_hEventLog = RegisterEventSource( NULL, "ModSecurity" );
-
-    this->status_call_already_sent = false;
-
-	modsecSetLogHook(this, Log);
-
-	modsecSetReadBody(ReadBodyCallback);
-	modsecSetReadResponse(ReadResponseCallback);
-	modsecSetWriteBody(WriteBodyCallback);
-	modsecSetWriteResponse(WriteResponseCallback);
-
-	server_rec *s = modsecInit();
-	char *compname = (char *)malloc(128);
-	DWORD size = 128;
-
-	GetComputerName(compname, &size);
-
-	s->server_hostname = compname;
-
-    SYSTEM_INFO         sysInfo;
-    GetSystemInfo(&sysInfo);
-    m_dwPageSize = sysInfo.dwPageSize;
-
-	modsecStartConfig();
-
-	modsecFinalizeConfig();
-
-	modsecInitProcess();
-}
-
-CMyHttpModule::~CMyHttpModule()
-{
-	// ModSecurity registers APR pool cleanups, which interfere with APR pool tear down process
-	// this causes crashes and since we are exiting the process here, so this is a temporary solution
-	//
-	//modsecTerminate();
-
-	//WriteEventViewerLog("Module deleted.");
-
-	// Test whether the handle for the Event Viewer is open.
-    if (NULL != m_hEventLog)
+    modsecSetLogHook(this, Log);
+    modsecSetReadBody(ReadBodyCallback);
+    modsecSetReadResponse(ReadResponseCallback);
+    modsecSetWriteBody(WriteBodyCallback);
+    modsecSetWriteResponse(WriteResponseCallback);
+
+    server_rec* s = modsecInit();
+    DWORD size = MAX_COMPUTERNAME_LENGTH + 1;
+    char* compname = static_cast<char *>(malloc(size));
+    if (compname == nullptr)
     {
-        // Close the handle to the Event Viewer.
-        DeregisterEventSource( m_hEventLog );
-        m_hEventLog = NULL;
+        throw std::bad_alloc();
     }
+    GetComputerName(compname, &size);
+    s->server_hostname = compname;
+
+    modsecStartConfig();
+    modsecFinalizeConfig();
+    modsecInitProcess();
 }
 
 void CMyHttpModule::Dispose()
@@ -1319,14 +1290,5 @@ void CMyHttpModule::Dispose()
 
 BOOL CMyHttpModule::WriteEventViewerLog(LPCSTR szNotification, WORD category)
 {
-    // Test whether the handle for the Event Viewer is open.
-    if (NULL != m_hEventLog)
-    {
-        // Write any strings to the Event Viewer and return.
-        return ReportEvent(
-            m_hEventLog,
-            category, 0, 0x1,
-            NULL, 1, 0, &szNotification, NULL );
-    }
-    return FALSE;
+    return logger.Log(szNotification, category);
 }
diff --git a/iis/mymodule.h b/iis/mymodule.h
index 7ad4d7ac3e..c14180965c 100644
--- a/iis/mymodule.h
+++ b/iis/mymodule.h
@@ -16,45 +16,38 @@
 #define __MY_MODULE_H__
 
 #include "critical_section.h"
+#include "event_logger.h"
 
 //  The module implementation.
 //  This class is responsible for implementing the 
 //  module functionality for each of the server events
 //  that it registers for.
-class CMyHttpModule : public CHttpModule
+class CMyHttpModule 
+    : public CHttpModule
 {
 public:
-    HANDLE m_hEventLog;
-    DWORD m_dwPageSize;
-    CriticalSection cs;
+    CMyHttpModule();
 
     REQUEST_NOTIFICATION_STATUS
-    OnBeginRequest(
-        IN IHttpContext * pHttpContext,
-        IN IHttpEventProvider * pProvider
-    );
+    OnBeginRequest(IHttpContext*, IHttpEventProvider*) override;
 
     REQUEST_NOTIFICATION_STATUS
-    OnSendResponse(
-    IN IHttpContext * pHttpContext,
-        IN ISendResponseProvider * pProvider
-    );
+    OnSendResponse(IHttpContext*, ISendResponseProvider*) override;
 
     REQUEST_NOTIFICATION_STATUS
-    OnPostEndRequest(
-    IN IHttpContext * pHttpContext,
-    IN IHttpEventProvider * pProvider
-    );
-
-    HRESULT ReadFileChunk(HTTP_DATA_CHUNK *chunk, char *buf);
+    OnPostEndRequest(IHttpContext*, IHttpEventProvider*) override;
 
-    CMyHttpModule();
-    ~CMyHttpModule();
+    void Dispose() override;
 
-    void Dispose();
+    HRESULT ReadFileChunk(HTTP_DATA_CHUNK* chunk, char* buf);
 
     BOOL WriteEventViewerLog(LPCSTR szNotification, WORD category = EVENTLOG_INFORMATION_TYPE);
-    BOOL status_call_already_sent;
+
+private:
+    CriticalSection cs;
+    EventLogger logger;
+    DWORD pageSize = 0;
+    bool statusCallAlreadySent = false;
 };
 
 #endif

From bcfcaab34bb081c3171843a1481925ffe4b7fd44 Mon Sep 17 00:00:00 2001
From: Vladimir Krivopalov <vlkrivop@microsoft.com>
Date: Tue, 12 Feb 2019 13:59:35 -0800
Subject: [PATCH 11/58] Run CMake from a dedicated 'build' subdirectory for
 PCRE.

Signed-off-by: Vladimir Krivopalov <vlkrivop@microsoft.com>
---
 iis/build_modsecurity.bat       |  6 +++---
 iis/dependencies/build_pcre.bat | 10 ++++++----
 2 files changed, 9 insertions(+), 7 deletions(-)

diff --git a/iis/build_modsecurity.bat b/iis/build_modsecurity.bat
index 4ee8348f56..ab297d19bf 100644
--- a/iis/build_modsecurity.bat
+++ b/iis/build_modsecurity.bat
@@ -15,21 +15,21 @@ set CURRENT_DIR=%cd%
 cd ..\apache2
 del *.obj *.dll *.lib
 del libinjection\*.obj libinjection\*.dll libinjection\*.lib
-NMAKE -f Makefile.win APACHE=..\iis\%DEPENDENCIES_DIR%\Apache24 PCRE=..\iis\%DEPENDENCIES_DIR%\pcre LIBXML2=..\iis\%DEPENDENCIES_DIR%\libxml2 LUA=..\iis\%DEPENDENCIES_DIR%\lua\src VERSION=VERSION_IIS YAJL=..\iis\%DEPENDENCIES_DIR%\yajl\build\yajl-2.1.0 SSDEEP=..\iis\%DEPENDENCIES_DIR%\ssdeep CURL=..\iis\%DEPENDENCIES_DIR%\curl IIS_BUILD=yes
+NMAKE -f Makefile.win APACHE=..\iis\%DEPENDENCIES_DIR%\Apache24 PCRE=..\iis\%DEPENDENCIES_DIR%\pcre\build LIBXML2=..\iis\%DEPENDENCIES_DIR%\libxml2 LUA=..\iis\%DEPENDENCIES_DIR%\lua\src VERSION=VERSION_IIS YAJL=..\iis\%DEPENDENCIES_DIR%\yajl\build\yajl-2.1.0 SSDEEP=..\iis\%DEPENDENCIES_DIR%\ssdeep CURL=..\iis\%DEPENDENCIES_DIR%\curl IIS_BUILD=yes
 @if NOT (%ERRORLEVEL%) == (0) goto build_failed
 
 @echo mlogc...
 cd ..\mlogc
 del *.obj *.dll *.lib
 nmake -f Makefile.win clean
-nmake -f Makefile.win APACHE=..\iis\%DEPENDENCIES_DIR%\Apache24 PCRE=..\iis\%DEPENDENCIES_DIR%\pcre CURL=..\iis\%DEPENDENCIES_DIR%\curl YAJL=..\iis\%DEPENDENCIES_DIR%\yajl\build\yajl-2.1.0 SSDEEP=..\iis\%DEPENDENCIES_DIR%\ssdeep VERSION=VERSION_IIS
+nmake -f Makefile.win APACHE=..\iis\%DEPENDENCIES_DIR%\Apache24 PCRE=..\iis\%DEPENDENCIES_DIR%\pcre\build CURL=..\iis\%DEPENDENCIES_DIR%\curl YAJL=..\iis\%DEPENDENCIES_DIR%\yajl\build\yajl-2.1.0 SSDEEP=..\iis\%DEPENDENCIES_DIR%\ssdeep VERSION=VERSION_IIS
 @if NOT (%ERRORLEVEL%) == (0) goto build_failed
 
 @echo iis...
 cd ..\iis
 del *.obj *.dll *.lib
 nmake -f Makefile.win clean
-NMAKE -f Makefile.win APACHE=..\iis\%DEPENDENCIES_DIR%\Apache24 PCRE=..\iis\%DEPENDENCIES_DIR%\pcre LIBXML2=..\iis\%DEPENDENCIES_DIR%\libxml2 LUA=..\iis\%DEPENDENCIES_DIR%\lua\src VERSION=VERSION_IIS YAJL=..\iis\%DEPENDENCIES_DIR%\yajl\build\yajl-2.1.0 SSDEEP=..\iis\%DEPENDENCIES_DIR%\ssdeep CURL=..\iis\%DEPENDENCIES_DIR%\curl
+NMAKE -f Makefile.win APACHE=..\iis\%DEPENDENCIES_DIR%\Apache24 PCRE=..\iis\%DEPENDENCIES_DIR%\pcre\build LIBXML2=..\iis\%DEPENDENCIES_DIR%\libxml2 LUA=..\iis\%DEPENDENCIES_DIR%\lua\src VERSION=VERSION_IIS YAJL=..\iis\%DEPENDENCIES_DIR%\yajl\build\yajl-2.1.0 SSDEEP=..\iis\%DEPENDENCIES_DIR%\ssdeep CURL=..\iis\%DEPENDENCIES_DIR%\curl
 @if NOT (%ERRORLEVEL%) == (0) goto build_failed
 
 cd %CURRENT_DIR%
diff --git a/iis/dependencies/build_pcre.bat b/iis/dependencies/build_pcre.bat
index 78a4df9847..b1cc496014 100644
--- a/iis/dependencies/build_pcre.bat
+++ b/iis/dependencies/build_pcre.bat
@@ -18,15 +18,17 @@ cd "pcre"
 cat CMakeLists.txt | sed "s/PCRE_STATIC_RUNTIME OFF CACHE BOOL/PCRE_STATIC_RUNTIME/g" | sed "s/PCRE_NO_RECURSE OFF/PCRE_NO_RECURSE ON/g" > CMakeLists.txt.ops
 move CMakeLists.txt CMakeLists.txt.old
 move CMakeLists.txt.ops CMakeLists.txt
-CMAKE -G "NMake Makefiles" -DCMAKE_BUILD_TYPE=RelWithDebInfo -DBUILD_SHARED_LIBS=True
+mkdir build
+cd build
+CMAKE -G "NMake Makefiles" -DCMAKE_BUILD_TYPE=RelWithDebInfo -DBUILD_SHARED_LIBS=True ../
 @if NOT (%ERRORLEVEL%) == (0) goto build_failed
 NMAKE
 @if NOT (%ERRORLEVEL%) == (0) goto build_failed
 cd "%WORK%"
 
-copy /y "%WORK_DIR%\pcre\pcre.dll" "%OUTPUT_DIR%"
-copy /y "%WORK_DIR%\pcre\pcre.pdb" "%OUTPUT_DIR%"
-copy /y "%WORK_DIR%\pcre\pcre.lib" "%OUTPUT_DIR%"
+copy /y "%WORK_DIR%\pcre\build\pcre.dll" "%OUTPUT_DIR%"
+copy /y "%WORK_DIR%\pcre\build\pcre.pdb" "%OUTPUT_DIR%"
+copy /y "%WORK_DIR%\pcre\build\pcre.lib" "%OUTPUT_DIR%"
 copy /y "%WORK_DIR%\pcre\pcre.h.generic" "%WORK_DIR%\pcre\pcre.h"
 echo "a"
 @exit /B 0

From b5695bc54403414a0fad918e0a6b432363a4d156 Mon Sep 17 00:00:00 2001
From: Vladimir Krivopalov <vlkrivop@microsoft.com>
Date: Wed, 13 Feb 2019 16:40:45 -0800
Subject: [PATCH 12/58] Restore response body processing support.

It has been accidentally disabled by removing subscription to
corresponding events during refactoring.

Signed-off-by: Vladimir Krivopalov <vlkrivop@microsoft.com>
---
 iis/main.cpp | 19 ++++++++++++++++---
 1 file changed, 16 insertions(+), 3 deletions(-)

diff --git a/iis/main.cpp b/iis/main.cpp
index 289560189a..8c179ccf10 100644
--- a/iis/main.cpp
+++ b/iis/main.cpp
@@ -56,9 +56,22 @@ RegisterModule(DWORD, IHttpModuleRegistrationInfo* moduleInfo, IHttpServer * htt
 
         // step 3: register for server events
         //
-        return moduleInfo->SetRequestNotifications(factory.release(), /* module factory */
-                                                    RQ_BEGIN_REQUEST /* server event mask */,
-                                                    0 /* server post event mask */);
+        auto result = moduleInfo->SetRequestNotifications(
+            factory.release(), /* module factory */
+            RQ_BEGIN_REQUEST | RQ_SEND_RESPONSE /* server event mask */,
+            RQ_END_REQUEST /* server post event mask */);
+        if (FAILED(result))
+        {
+            return result;
+        }
+
+        result = moduleInfo->SetPriorityForRequestNotification(RQ_BEGIN_REQUEST, PRIORITY_ALIAS_FIRST);
+        if (FAILED(result))
+        {
+            return result;
+        }
+
+        return moduleInfo->SetPriorityForRequestNotification(RQ_SEND_RESPONSE, PRIORITY_ALIAS_LAST);
     }
     catch (const std::bad_alloc&)
     {

From 9f387c65536bb7898436fa5c3e9a79b30ad1b6b4 Mon Sep 17 00:00:00 2001
From: Vladimir Krivopalov <vlkrivop@microsoft.com>
Date: Tue, 12 Feb 2019 16:35:42 -0800
Subject: [PATCH 13/58] Add Asio library v.1.12.2 as a submodule.

Signed-off-by: Vladimir Krivopalov <vlkrivop@microsoft.com>
---
 .gitmodules  | 4 ++++
 appveyor.yml | 1 +
 iis/asio     | 1 +
 3 files changed, 6 insertions(+)
 create mode 100644 .gitmodules
 create mode 160000 iis/asio

diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000000..6a5a4a47b1
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,4 @@
+[submodule "iis/asio"]
+	path = iis/asio
+	url = https://github.com/chriskohlhoff/asio.git
+	branch = tags/asio-1-12-2
diff --git a/appveyor.yml b/appveyor.yml
index 85695c56e3..9a952be94c 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -4,6 +4,7 @@ services:
     - iis                 # start IIS
 
 install:
+    - git submodule update --init --recursive
     - "python --version"
     - ps: cd iis; .\getModSecurityPkgs.ps1 https://modsecurity.blob.core.windows.net/windows-artifacts
 
diff --git a/iis/asio b/iis/asio
new file mode 160000
index 0000000000..22afb86087
--- /dev/null
+++ b/iis/asio
@@ -0,0 +1 @@
+Subproject commit 22afb86087a77037cd296d27134756c9b0d2cb75

From b59c6f7488990dc055cf434c658bac487cb17c94 Mon Sep 17 00:00:00 2001
From: Vladimir Krivopalov <vlkrivop@microsoft.com>
Date: Wed, 13 Feb 2019 10:53:38 -0800
Subject: [PATCH 14/58] Use std::shared_ptr instead of std::unique_ptr for
 request_rec.

This will further allow us to share the ownership between request
context and background thread when we offload processing to the thread
pool.

Signed-off-by: Vladimir Krivopalov <vlkrivop@microsoft.com>
---
 iis/mymodule.cpp | 7 ++-----
 1 file changed, 2 insertions(+), 5 deletions(-)

diff --git a/iis/mymodule.cpp b/iis/mymodule.cpp
index f08c038367..240a17c17f 100644
--- a/iis/mymodule.cpp
+++ b/iis/mymodule.cpp
@@ -35,11 +35,8 @@
 
 // These helpers make sure that the underlying structures
 // are correctly released on any exit path due to RAII.
-using ConnRecPtr =
-    std::unique_ptr<conn_rec, decltype(modsecFinishConnection)*>;
-
-using RequestRecPtr =
-    std::unique_ptr<request_rec, decltype(modsecFinishRequest)*>;
+using ConnRecPtr = std::shared_ptr<conn_rec>;
+using RequestRecPtr = std::shared_ptr<request_rec>;
 
 ConnRecPtr MakeConnReq()
 {

From e966cf27f5725b7144f98d016ce92488df27de9e Mon Sep 17 00:00:00 2001
From: Vladimir Krivopalov <vlkrivop@microsoft.com>
Date: Thu, 21 Feb 2019 14:34:06 -0800
Subject: [PATCH 15/58] Simplify RequestStoredContext struct.

Access fields directly instead of using getter methods.

Signed-off-by: Vladimir Krivopalov <vlkrivop@microsoft.com>
---
 iis/mymodule.cpp | 138 ++++++++++++++---------------------------------
 1 file changed, 40 insertions(+), 98 deletions(-)

diff --git a/iis/mymodule.cpp b/iis/mymodule.cpp
index 240a17c17f..e5e076f62e 100644
--- a/iis/mymodule.cpp
+++ b/iis/mymodule.cpp
@@ -50,92 +50,27 @@ RequestRecPtr MakeRequestRec(conn_rec* c, directory_config* config)
     return {modsecNewRequest(c, config), modsecFinishRequest};
 }
 
-class RequestStoredContext
-    : public IHttpStoredContext
+struct RequestStoredContext
+    : IHttpStoredContext
 {
-public:
-    RequestStoredContext(directory_config* config,
-            IHttpContext* httpContext, IHttpEventProvider* provider)
-        : connRec(MakeConnReq())
-        , requestRec(MakeRequestRec(connRec.get(), config))
-        , httpContext(httpContext)
-        , provider(provider)
-    {}
-
-    RequestStoredContext(const RequestStoredContext&) = delete;
-    RequestStoredContext& operator=(const RequestStoredContext&) = delete;
-
-    // NB: these could have been defaulted with '= default' but VS2013 doesn't support it...
-    RequestStoredContext(RequestStoredContext&& rhs)
-        : connRec(std::move(rhs.connRec))
-        , requestRec(std::move(rhs.requestRec))
-        , httpContext(rhs.httpContext)
-        , provider(rhs.provider)
-    {}
-
-    RequestStoredContext& operator=(RequestStoredContext&& rhs)
-    {
-        connRec = std::move(rhs.connRec);
-        requestRec = std::move(rhs.requestRec);
-        httpContext = rhs.httpContext;
-        provider = rhs.provider;
-        return *this;
-    }
+    ConnRecPtr connRec;
+    RequestRecPtr requestRec;
+    IHttpContext* httpContext;
+    IHttpEventProvider* provider;
+    char* responseBuffer = nullptr;
+    ULONGLONG responseLength = 0;
+    ULONGLONG responsePosition = 0;
 
     void CleanupStoredContext() override
     {
         delete this;
     }
 
-    conn_rec* Connection() const
-    {
-        return connRec.get();
-    }
-
-    request_rec* Request() const
-    {
-        return requestRec.get();
-    }
-
-    IHttpContext* HttpContext() const
-    {
-        return httpContext;
-    }
-
-    IHttpEventProvider* Provider() const
-    {
-        return provider;
-    }
-
-    char*& ResponseBuffer()
-    {
-        return responseBuffer;
-    }
-
-    ULONGLONG& ResponseLength()
-    {
-        return responseLength;
-    }
-
-    ULONGLONG& ResponsePosition()
-    {
-        return responsePosition;
-    }
-
     void FinishRequest()
     {
         requestRec.reset();
         connRec.reset();
     }
-
-private:
-	ConnRecPtr connRec;
-	RequestRecPtr requestRec;
-	IHttpContext* httpContext;
-	IHttpEventProvider* provider;
-    char* responseBuffer = nullptr;
-    ULONGLONG responseLength = 0;
-    ULONGLONG responsePosition = 0;
 };
 
 char *GetIpAddr(apr_pool_t *pool, PSOCKADDR pAddr)
@@ -475,7 +410,7 @@ CMyHttpModule::OnSendResponse(
     CriticalSectionLock lock{cs};
 	// here we must check if response body processing is enabled
 	//
-	if(rsc == nullptr || rsc->Request() == nullptr || rsc->ResponseBuffer() != nullptr || !modsecIsResponseBodyAccessEnabled(rsc->Request()))
+	if(!rsc || !rsc->requestRec || rsc->responseBuffer != nullptr || !modsecIsResponseBodyAccessEnabled(rsc->requestRec.get()))
 	{
 		goto Exit;
 	}
@@ -489,7 +424,7 @@ CMyHttpModule::OnSendResponse(
     REQUEST_NOTIFICATION_STATUS ret = RQ_NOTIFICATION_CONTINUE;
 	ULONGLONG ulTotalLength = 0;
 	DWORD c;
-    request_rec *r = rsc->Request();
+    request_rec *r = rsc->requestRec.get();
 
 	pHttpResponse = pHttpContext->GetResponse();
 	pRawHttpResponse = pHttpResponse->GetRawHttpResponse();
@@ -631,7 +566,7 @@ CMyHttpModule::OnSendResponse(
         }
     }
 
-	rsc->ResponseBuffer() = (char *)apr_palloc(rsc->Request()->pool, ulTotalLength);
+	rsc->responseBuffer = (char *)apr_palloc(rsc->requestRec->pool, ulTotalLength);
 
 	ulTotalLength = 0;
 
@@ -642,13 +577,13 @@ CMyHttpModule::OnSendResponse(
         switch( pSourceDataChunk->DataChunkType )
         {
             case HttpDataChunkFromMemory:
-				memcpy(rsc->ResponseBuffer() + ulTotalLength, pSourceDataChunk->FromMemory.pBuffer, pSourceDataChunk->FromMemory.BufferLength);
+				memcpy(rsc->responseBuffer + ulTotalLength, pSourceDataChunk->FromMemory.pBuffer, pSourceDataChunk->FromMemory.BufferLength);
                 ulTotalLength += pSourceDataChunk->FromMemory.BufferLength;
                 break;
             case HttpDataChunkFromFileHandle:
                 pFileByteRange = &pSourceDataChunk->FromFileHandle.ByteRange;
 
-				if(ReadFileChunk(pSourceDataChunk, rsc->ResponseBuffer() + ulTotalLength) != S_OK)
+				if(ReadFileChunk(pSourceDataChunk, rsc->responseBuffer + ulTotalLength) != S_OK)
 				{
 			        DWORD dwErr = GetLastError();
 
@@ -666,7 +601,7 @@ CMyHttpModule::OnSendResponse(
         }
     }
 
-	rsc->ResponseLength() = ulTotalLength;
+	rsc->responseLength = ulTotalLength;
 
 	//
     // If there's no content-length set, we need to set it to avoid chunked transfer mode
@@ -707,7 +642,7 @@ CMyHttpModule::OnSendResponse(
 
 Finished:
 
-	int status = modsecProcessResponse(rsc->Request());
+	int status = modsecProcessResponse(r);
 
 	// the logic here is temporary, needs clarification
 	//
@@ -740,7 +675,7 @@ CMyHttpModule::OnPostEndRequest(
 
 	// only finish request if OnSendResponse have been called already
 	//
-	if(rsc != nullptr && rsc->ResponseBuffer() != nullptr)
+	if(rsc != nullptr && rsc->responseBuffer != nullptr)
     {
         CriticalSectionLock lock{cs};
 		rsc->FinishRequest();
@@ -820,9 +755,16 @@ CMyHttpModule::OnBeginRequest(IHttpContext* httpContext, IHttpEventProvider* pro
         delete path;
     }
 
-    auto rsc = std::make_unique<RequestStoredContext>(config->config, httpContext, provider);
-    conn_rec* c = rsc->Connection();
-    request_rec* r = rsc->Request();
+    ConnRecPtr connRec = MakeConnReq();
+    conn_rec* c = connRec.get();
+    RequestRecPtr requestRec = MakeRequestRec(c, config->config);
+    request_rec* r = requestRec.get();
+
+    auto rsc = std::make_unique<RequestStoredContext>();
+    rsc->connRec = connRec;
+    rsc->requestRec = requestRec;
+    rsc->httpContext = httpContext;
+    rsc->provider = provider;
 
     // on IIS we force input stream inspection flag, because its absence does not add any performance gain
     // it's because on IIS request body must be restored each time it was read
@@ -1087,7 +1029,7 @@ apr_status_t ReadBodyCallback(request_rec *r, char *buf, unsigned int length, un
         return APR_SUCCESS;
     }
 
-    IHttpContext *pHttpContext = rsc->HttpContext();
+    IHttpContext *pHttpContext = rsc->httpContext;
     IHttpRequest *pRequest = pHttpContext->GetRequest();
 
     if (pRequest->GetRemainingEntityBytes() == 0)
@@ -1104,7 +1046,7 @@ apr_status_t ReadBodyCallback(request_rec *r, char *buf, unsigned int length, un
         if (ERROR_HANDLE_EOF != (hr & 0x0000FFFF))
         {
             // Set the error status.
-            rsc->Provider()->SetErrorStatus(hr);
+            rsc->provider->SetErrorStatus(hr);
         }
 
         *is_eos = 1;
@@ -1117,10 +1059,10 @@ apr_status_t WriteBodyCallback(request_rec *r, char *buf, unsigned int length)
 {
 	RequestStoredContext *rsc = RetrieveIISContext(r);
 
-	if(rsc == NULL || rsc->Request() == NULL)
+	if(!rsc || !rsc->requestRec)
 		return APR_SUCCESS;
 
-	IHttpContext *pHttpContext = rsc->HttpContext();
+	IHttpContext *pHttpContext = rsc->httpContext;
 	IHttpRequest *pHttpRequest = pHttpContext->GetRequest();
 
     CHAR szLength[21]; //Max length for a 64 bit int is 20
@@ -1182,7 +1124,7 @@ apr_status_t ReadResponseCallback(request_rec *r, char *buf, unsigned int length
 
 	*readcnt = 0;
 
-	if(rsc == nullptr || rsc->ResponseBuffer() == nullptr)
+	if(rsc == nullptr || rsc->responseBuffer == nullptr)
 	{
 		*is_eos = 1;
 		return APR_SUCCESS;
@@ -1190,15 +1132,15 @@ apr_status_t ReadResponseCallback(request_rec *r, char *buf, unsigned int length
 
 	unsigned int size = length;
 
-	if(size > rsc->ResponseLength() - rsc->ResponsePosition())
-		size = rsc->ResponseLength() - rsc->ResponsePosition();
+	if(size > rsc->responseLength - rsc->responsePosition)
+		size = rsc->responseLength - rsc->responsePosition;
 
-	memcpy(buf, rsc->ResponseBuffer() + rsc->ResponsePosition(), size);
+	memcpy(buf, rsc->responseBuffer + rsc->responsePosition, size);
 
 	*readcnt = size;
-	rsc->ResponsePosition() += size;
+	rsc->responsePosition += size;
 
-	if(rsc->ResponsePosition() >= rsc->ResponseLength())
+	if(rsc->responsePosition >= rsc->responseLength)
 		*is_eos = 1;
 
 	return APR_SUCCESS;
@@ -1208,13 +1150,13 @@ apr_status_t WriteResponseCallback(request_rec *r, char *buf, unsigned int lengt
 {
 	RequestStoredContext* rsc = RetrieveIISContext(r);
 
-	if(rsc == nullptr || rsc->Request() == nullptr || rsc->ResponseBuffer() == nullptr)
+	if(!rsc || !rsc->requestRec || rsc->responseBuffer == nullptr)
 		return APR_SUCCESS;
 
-	IHttpContext *pHttpContext = rsc->HttpContext();
+	IHttpContext *pHttpContext = rsc->httpContext;
 	IHttpResponse *pHttpResponse = pHttpContext->GetResponse();
 	HTTP_RESPONSE *pRawHttpResponse = pHttpResponse->GetRawHttpResponse();
-	HTTP_DATA_CHUNK *pDataChunk = (HTTP_DATA_CHUNK *)apr_palloc(rsc->Request()->pool, sizeof(HTTP_DATA_CHUNK));
+	HTTP_DATA_CHUNK *pDataChunk = (HTTP_DATA_CHUNK *)apr_palloc(rsc->requestRec->pool, sizeof(HTTP_DATA_CHUNK));
 
 	pRawHttpResponse->EntityChunkCount = 0;
 

From 5be299dbfbc9e35d2d7199a0194f177b07b6a7f7 Mon Sep 17 00:00:00 2001
From: Vladimir Krivopalov <vlkrivop@microsoft.com>
Date: Thu, 21 Feb 2019 15:53:34 -0800
Subject: [PATCH 16/58] Add function that copies request body into Apache
 brigade buckets.

Signed-off-by: Vladimir Krivopalov <vlkrivop@microsoft.com>
---
 iis/mymodule.cpp | 97 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 97 insertions(+)

diff --git a/iis/mymodule.cpp b/iis/mymodule.cpp
index e5e076f62e..26e79b0f04 100644
--- a/iis/mymodule.cpp
+++ b/iis/mymodule.cpp
@@ -16,6 +16,8 @@
 
 #undef inline
 
+#include <string>
+#include <cctype>
 #include <memory>
 
 //  IIS7 Server API header file
@@ -399,6 +401,101 @@ HRESULT CMyHttpModule::ReadFileChunk(HTTP_DATA_CHUNK *chunk, char *buf)
 	return hr;
 }
 
+/*
+ * Read request body from IIS structures, copy it over into
+ * Apache buckets and then assign back the entire flatten body
+ * to IHttpRequest.
+ * If the request body is chunked, it will be transformed into fixed-length.
+*/
+static HRESULT SaveRequestBodyToRequestRec(RequestStoredContext* rsc)
+{
+    request_rec* aprRequest = rsc->requestRec.get();
+    conn_rec* conn = rsc->connRec.get();
+    IHttpRequest* iisRequest = rsc->httpContext->GetRequest();
+    apr_bucket_brigade* brigade = apr_brigade_create(conn->pool, conn->bucket_alloc);
+    if (brigade == nullptr)
+    {
+        return E_OUTOFMEMORY;
+    }
+
+    while (iisRequest->GetRemainingEntityBytes() > 0)
+    {
+        DWORD bytesRead = 0;
+        char* buf = static_cast<char*>(apr_palloc(aprRequest->pool, HUGE_STRING_LEN));
+        HRESULT hr = iisRequest->ReadEntityBody(buf, HUGE_STRING_LEN, false, &bytesRead, nullptr);
+        if (FAILED(hr))
+        {
+            // End of data is okay.
+            if (ERROR_HANDLE_EOF != (hr & 0x0000FFFF))
+            {
+                return hr;
+            }
+
+            break;
+        }
+
+        apr_bucket* bucket = apr_bucket_pool_create(buf, bytesRead, aprRequest->pool, conn->bucket_alloc);
+        if (bucket == nullptr)
+        {
+            return E_OUTOFMEMORY;
+        }
+        APR_BRIGADE_INSERT_TAIL(brigade, bucket);
+    }
+
+    apr_bucket* e = apr_bucket_eos_create(conn->bucket_alloc);
+    if (e == nullptr)
+    {
+        return E_OUTOFMEMORY;
+    }
+    APR_BRIGADE_INSERT_TAIL(brigade, e);
+
+    modsecSetBodyBrigade(aprRequest, brigade);
+
+    apr_off_t contentLength = 0;
+    apr_status_t status = apr_brigade_length(brigade, FALSE, &contentLength);
+    if (status != APR_SUCCESS)
+    {
+        return E_FAIL;
+    }
+
+    // Remove/Modify Transfer-Encoding header if "chunked" Encoding is set in the request. 
+    // This is to avoid sending both Content-Length and Chunked Transfer-Encoding in the request header.
+    static const std::string CHUNKED = "chunked";
+    USHORT encodingLength = 0;
+    const char* transferEncoding = iisRequest->GetHeader(HttpHeaderTransferEncoding, &encodingLength);
+    if (transferEncoding)
+    {
+        if (CHUNKED.size() == encodingLength &&
+            std::equal(CHUNKED.cbegin(), CHUNKED.cend(), transferEncoding,
+                [](char lhs, char rhs) { return std::tolower(lhs) == std::tolower(rhs); }))
+        {
+            iisRequest->DeleteHeader(HttpHeaderTransferEncoding);
+        }
+    }
+
+    auto contentLengthStr = std::to_string(contentLength);
+    HRESULT hr = iisRequest->SetHeader(
+        HttpHeaderContentLength,
+        contentLengthStr.c_str(),
+        contentLengthStr.size(),
+        TRUE);
+
+    if (FAILED(hr))
+    {
+        return hr;
+    }
+
+    // since we clean the APR pool at the end of OnSendRequest, we must get IIS-managed memory chunk
+    //
+    char* requestBuffer = static_cast<char*>(rsc->httpContext->AllocateRequestMemory(contentLength));
+    status = apr_brigade_flatten(brigade, requestBuffer, reinterpret_cast<apr_size_t*>(&contentLength));
+    if (status != APR_SUCCESS)
+    {
+        return E_FAIL;
+    }
+    return iisRequest->InsertEntityBody(requestBuffer, contentLength);
+}
+
 REQUEST_NOTIFICATION_STATUS
 CMyHttpModule::OnSendResponse(
     IN IHttpContext * pHttpContext,

From 2aa9412ae490d1f9b195ba2c150deeaa689a5514 Mon Sep 17 00:00:00 2001
From: Vladimir Krivopalov <vlkrivop@microsoft.com>
Date: Fri, 22 Feb 2019 10:44:08 -0800
Subject: [PATCH 17/58] Process request in background when in detection mode.

We don't have to block until request processing is completed when in
detection mode because we are not going to block request based on
processing result.
To speed up processing and improve latencies, we offload processing to a
background thread.

Signed-off-by: Vladimir Krivopalov <vlkrivop@microsoft.com>
---
 iis/Makefile.win |   3 +-
 iis/mymodule.cpp | 263 ++++++++++++++++++++++++++---------------------
 iis/mymodule.h   |   8 +-
 3 files changed, 155 insertions(+), 119 deletions(-)

diff --git a/iis/Makefile.win b/iis/Makefile.win
index 1e198f65c3..740021d3e3 100644
--- a/iis/Makefile.win
+++ b/iis/Makefile.win
@@ -37,7 +37,8 @@ INCLUDES = -I. -I.. \
            -I..\apache2 \
            -I..\standalone \
            -I..\apache2\ag_mdb \
-           -I..\apache2\waf_lock
+           -I..\apache2\waf_lock \
+           -Iasio\asio\include
 
 # Enables support for SecRemoteRules and external resources.
 DEFS=$(DEFS) -DWITH_CURL -DWITH_REMOTE_RULES
diff --git a/iis/mymodule.cpp b/iis/mymodule.cpp
index 26e79b0f04..81f9b91a93 100644
--- a/iis/mymodule.cpp
+++ b/iis/mymodule.cpp
@@ -19,6 +19,7 @@
 #include <string>
 #include <cctype>
 #include <memory>
+#include <future>
 
 //  IIS7 Server API header file
 #include <Windows.h>
@@ -35,6 +36,9 @@
 
 #include "winsock2.h"
 
+#include "asio/packaged_task.hpp"
+#include "asio/post.hpp"
+
 // These helpers make sure that the underlying structures
 // are correctly released on any exit path due to RAII.
 using ConnRecPtr = std::shared_ptr<conn_rec>;
@@ -62,6 +66,8 @@ struct RequestStoredContext
     char* responseBuffer = nullptr;
     ULONGLONG responseLength = 0;
     ULONGLONG responsePosition = 0;
+    bool responseProcessingEnabled = false;
+    std::future<int> detectionProcessing;
 
     void CleanupStoredContext() override
     {
@@ -496,6 +502,97 @@ static HRESULT SaveRequestBodyToRequestRec(RequestStoredContext* rsc)
     return iisRequest->InsertEntityBody(requestBuffer, contentLength);
 }
 
+
+static apr_status_t ReadBodyCallback(request_rec *r, char *buf, unsigned int length, unsigned int *readcnt, int *is_eos)
+{
+    RequestStoredContext *rsc = RetrieveIISContext(r);
+
+    *readcnt = 0;
+
+    if (rsc == NULL)
+    {
+        *is_eos = 1;
+        return APR_SUCCESS;
+    }
+
+    IHttpContext *pHttpContext = rsc->httpContext;
+    IHttpRequest *pRequest = pHttpContext->GetRequest();
+
+    if (pRequest->GetRemainingEntityBytes() == 0)
+    {
+        *is_eos = 1;
+        return APR_SUCCESS;
+    }
+
+    HRESULT hr = pRequest->ReadEntityBody(buf, length, false, (DWORD *)readcnt, NULL);
+
+    if (FAILED(hr))
+    {
+        // End of data is okay.
+        if (ERROR_HANDLE_EOF != (hr & 0x0000FFFF))
+        {
+            // Set the error status.
+            rsc->provider->SetErrorStatus(hr);
+        }
+
+        *is_eos = 1;
+    }
+
+    return APR_SUCCESS;
+}
+
+static apr_status_t WriteBodyCallback(request_rec *r, char *buf, unsigned int length)
+{
+    RequestStoredContext *rsc = RetrieveIISContext(r);
+
+    if (!rsc || !rsc->requestRec)
+        return APR_SUCCESS;
+
+    IHttpContext *pHttpContext = rsc->httpContext;
+    IHttpRequest *pHttpRequest = pHttpContext->GetRequest();
+
+    auto lengthStr = std::to_string(length);
+
+    // Remove/Modify Transfer-Encoding header if "chunked" Encoding is set in the request. 
+    // This is to avoid sending both Content-Length and Chunked Transfer-Encoding in the request header.
+
+    USHORT ctcch = 0;
+    char *ct = (char *)pHttpRequest->GetHeader(HttpHeaderTransferEncoding, &ctcch);
+    if (ct)
+    {
+        char *ctz = ZeroTerminate(ct, ctcch, r->pool);
+        if (ctcch != 0)
+        {
+            if (0 == stricmp(ctz, "chunked"))
+            {
+                pHttpRequest->DeleteHeader(HttpHeaderTransferEncoding);
+            }
+        }
+    }
+
+    HRESULT hr = pHttpRequest->SetHeader(
+        HttpHeaderContentLength,
+        lengthStr.c_str(),
+        (USHORT)lengthStr.size(),
+        TRUE);
+
+    if (FAILED(hr))
+    {
+        // possible, but there's nothing we can do
+    }
+
+    // since we clean the APR pool at the end of OnSendRequest, we must get IIS-managed memory chunk
+    //
+    void *reqbuf = pHttpContext->AllocateRequestMemory(length);
+
+    memcpy(reqbuf, buf, length);
+
+    pHttpRequest->InsertEntityBody(reqbuf, length);
+
+    return APR_SUCCESS;
+}
+
+
 REQUEST_NOTIFICATION_STATUS
 CMyHttpModule::OnSendResponse(
     IN IHttpContext * pHttpContext,
@@ -505,12 +602,18 @@ CMyHttpModule::OnSendResponse(
     RequestStoredContext* rsc = dynamic_cast<RequestStoredContext*>(pHttpContext->GetModuleContextContainer()->GetModuleContext(g_pModuleContext));
 
     CriticalSectionLock lock{cs};
-	// here we must check if response body processing is enabled
-	//
-	if(!rsc || !rsc->requestRec || rsc->responseBuffer != nullptr || !modsecIsResponseBodyAccessEnabled(rsc->requestRec.get()))
-	{
-		goto Exit;
-	}
+    // here we must check if response body processing is enabled
+    //
+    if (!rsc || !rsc->requestRec || rsc->responseBuffer != nullptr || !rsc->responseProcessingEnabled)
+    {
+        goto Exit;
+    }
+
+    // If we have offloaded request processing to the thread pool
+    // we need to wait for its completion before we can proceed
+    if (rsc->detectionProcessing.valid()) {
+        rsc->detectionProcessing.get();
+    }
 
     HRESULT hr = S_OK;
 	IHttpResponse *pHttpResponse = NULL;
@@ -850,6 +953,17 @@ CMyHttpModule::OnBeginRequest(IHttpContext* httpContext, IHttpEventProvider* pro
 
         delete apppath;
         delete path;
+
+        if (config->config->is_enabled == MODSEC_DETECTION_ONLY)
+        {
+            modsecSetReadBody(nullptr);
+            modsecSetWriteBody(nullptr);
+        }
+        else
+        {
+            modsecSetReadBody(ReadBodyCallback);
+            modsecSetWriteBody(WriteBodyCallback);
+        }
     }
 
     ConnRecPtr connRec = MakeConnReq();
@@ -862,6 +976,8 @@ CMyHttpModule::OnBeginRequest(IHttpContext* httpContext, IHttpEventProvider* pro
     rsc->requestRec = requestRec;
     rsc->httpContext = httpContext;
     rsc->provider = provider;
+    rsc->responseProcessingEnabled = (config->config->resbody_access == 1);
+    RequestStoredContext* context = rsc.get();
 
     // on IIS we force input stream inspection flag, because its absence does not add any performance gain
     // it's because on IIS request body must be restored each time it was read
@@ -1098,121 +1214,40 @@ CMyHttpModule::OnBeginRequest(IHttpContext* httpContext, IHttpEventProvider* pro
 #endif
 	c->remote_host = NULL;
 
-    lock.unlock();
-    int status = modsecProcessRequest(r);
-    lock.lock();
-
-	if(status != DECLINED)
-	{
-		httpContext->GetResponse()->SetStatus(status, "ModSecurity Action");
-		httpContext->SetRequestHandled();
-
-        return RQ_NOTIFICATION_FINISH_REQUEST;
-	}
-
-	return RQ_NOTIFICATION_CONTINUE;
-}
-
-
-apr_status_t ReadBodyCallback(request_rec *r, char *buf, unsigned int length, unsigned int *readcnt, int *is_eos)
-{
-    RequestStoredContext *rsc = RetrieveIISContext(r);
-
-    *readcnt = 0;
-
-    if (rsc == NULL)
-    {
-        *is_eos = 1;
-        return APR_SUCCESS;
-    }
-
-    IHttpContext *pHttpContext = rsc->httpContext;
-    IHttpRequest *pRequest = pHttpContext->GetRequest();
-
-    if (pRequest->GetRemainingEntityBytes() == 0)
+    if (config->config->is_enabled == MODSEC_DETECTION_ONLY)
     {
-        *is_eos = 1;
-        return APR_SUCCESS;
-    }
-
-    HRESULT hr = pRequest->ReadEntityBody(buf, length, false, (DWORD *)readcnt, NULL);
-
-    if (FAILED(hr))
-    {
-        // End of data is okay.
-        if (ERROR_HANDLE_EOF != (hr & 0x0000FFFF))
-        {
-            // Set the error status.
-            rsc->provider->SetErrorStatus(hr);
+        hr = SaveRequestBodyToRequestRec(context);
+        if (FAILED(hr)) {
+            context->provider->SetErrorStatus(hr);
+            return RQ_NOTIFICATION_FINISH_REQUEST;
         }
-
-        *is_eos = 1;
+        // We post the processing task to the thread pool to happen in the background.
+        // We store the future to track and wait for this processing in case if we also
+        // need to process the response because we need request processing to finish
+        // before we can start with the response.
+        context->detectionProcessing = asio::post(threadPool,
+            std::packaged_task<int()> {
+            [connRec, requestRec] {
+                return modsecProcessRequest(requestRec.get());
+            }
+        });
     }
-
-    return APR_SUCCESS;
-}
-
-apr_status_t WriteBodyCallback(request_rec *r, char *buf, unsigned int length)
-{
-	RequestStoredContext *rsc = RetrieveIISContext(r);
-
-	if(!rsc || !rsc->requestRec)
-		return APR_SUCCESS;
-
-	IHttpContext *pHttpContext = rsc->httpContext;
-	IHttpRequest *pHttpRequest = pHttpContext->GetRequest();
-
-    CHAR szLength[21]; //Max length for a 64 bit int is 20
-
-    ZeroMemory(szLength, sizeof(szLength));
-
-    HRESULT hr = StringCchPrintfA(
-            szLength, 
-            sizeof(szLength) / sizeof(CHAR) - 1, "%d", 
-            length);
-
-    if(FAILED(hr))
+    else
     {
-		// not possible
-    }
+        lock.unlock();
+        int status = modsecProcessRequest(r);
+        lock.lock();
 
-	// Remove/Modify Transfer-Encoding header if "chunked" Encoding is set in the request. 
-	// This is to avoid sending both Content-Length and Chunked Transfer-Encoding in the request header.
-
-	USHORT ctcch = 0;
-	char *ct = (char *)pHttpRequest->GetHeader(HttpHeaderTransferEncoding, &ctcch);
-	if (ct)
-	{
-		char *ctz = ZeroTerminate(ct, ctcch, r->pool);
-		if (ctcch != 0)
-		{
-			if (0 == stricmp(ctz, "chunked"))
-			{
-				pHttpRequest->DeleteHeader(HttpHeaderTransferEncoding);
-			}
-		}
-	}
-	
-    hr = pHttpRequest->SetHeader(
-            HttpHeaderContentLength, 
-            szLength, 
-            (USHORT)strlen(szLength),
-            TRUE);
+        if (status != DECLINED)
+        {
+            httpContext->GetResponse()->SetStatus(status, "ModSecurity Action");
+            httpContext->SetRequestHandled();
 
-    if(FAILED(hr))
-    {
-		// possible, but there's nothing we can do
+            return RQ_NOTIFICATION_FINISH_REQUEST;
+        }
     }
 
-	// since we clean the APR pool at the end of OnSendRequest, we must get IIS-managed memory chunk
-	//
-	void *reqbuf = pHttpContext->AllocateRequestMemory(length);
-
-	memcpy(reqbuf, buf, length);
-
-	pHttpRequest->InsertEntityBody(reqbuf, length);
-
-	return APR_SUCCESS;
+	return RQ_NOTIFICATION_CONTINUE;
 }
 
 apr_status_t ReadResponseCallback(request_rec *r, char *buf, unsigned int length, unsigned int *readcnt, int *is_eos)
@@ -1300,9 +1335,7 @@ apr_status_t WriteResponseCallback(request_rec *r, char *buf, unsigned int lengt
 CMyHttpModule::CMyHttpModule()
 {
     modsecSetLogHook(this, Log);
-    modsecSetReadBody(ReadBodyCallback);
     modsecSetReadResponse(ReadResponseCallback);
-    modsecSetWriteBody(WriteBodyCallback);
     modsecSetWriteResponse(WriteResponseCallback);
 
     server_rec* s = modsecInit();
diff --git a/iis/mymodule.h b/iis/mymodule.h
index c14180965c..83d7adb697 100644
--- a/iis/mymodule.h
+++ b/iis/mymodule.h
@@ -12,8 +12,10 @@
 * directly using the email address security@modsecurity.org.
 */
 
-#ifndef __MY_MODULE_H__
-#define __MY_MODULE_H__
+#pragma once
+
+#define ASIO_STANDALONE
+#include "asio/thread_pool.hpp"
 
 #include "critical_section.h"
 #include "event_logger.h"
@@ -46,8 +48,8 @@ class CMyHttpModule
 private:
     CriticalSection cs;
     EventLogger logger;
+    asio::thread_pool threadPool;
     DWORD pageSize = 0;
     bool statusCallAlreadySent = false;
 };
 
-#endif

From b11486e5cc18817f8830124de53efe784c6504fd Mon Sep 17 00:00:00 2001
From: Yanshu <yanshu.zhao7@gmail.com>
Date: Mon, 11 Mar 2019 14:46:33 -0700
Subject: [PATCH 18/58] Add signal process for waf log rotation (#102)

* add signal process for waf log rotation

* fix build for windows

* remove unnessary lock

* address comments

* fix build for windows

* define file name length and add full code for signal registration
---
 apache2/apache2_config.c | 19 +++++++------------
 apache2/apache2_util.c   | 21 ++++++++++++++++++++-
 apache2/mod_security2.c  |  4 ++++
 apache2/modsecurity.c    | 19 ++++++++++++++++++-
 apache2/modsecurity.h    | 11 ++++++++---
 5 files changed, 57 insertions(+), 17 deletions(-)

diff --git a/apache2/apache2_config.c b/apache2/apache2_config.c
index c93f811e93..6051c39316 100755
--- a/apache2/apache2_config.c
+++ b/apache2/apache2_config.c
@@ -114,9 +114,6 @@ void *create_directory_config(apr_pool_t *mp, char *path)
 
     /* Misc */
     dcfg->data_dir = NOT_SET_P;
-#ifdef WAF_JSON_LOGGING_ENABLE
-    dcfg->wafjsonlog_fd = NOT_SET_P;
-#endif
     dcfg->webappid = NOT_SET_P;
     dcfg->sensor_id = NOT_SET_P;
     dcfg->httpBlkey = NOT_SET_P;
@@ -554,10 +551,6 @@ void *merge_directory_configs(apr_pool_t *mp, void *_parent, void *_child)
     /* Misc */
     merged->data_dir = (child->data_dir == NOT_SET_P
         ? parent->data_dir : child->data_dir);
-#ifdef WAF_JSON_LOGGING_ENABLE
-    merged->wafjsonlog_fd = (child->wafjsonlog_fd == NOT_SET_P
-        ? parent->wafjsonlog_fd : child->wafjsonlog_fd);
-#endif
     merged->webappid = (child->webappid == NOT_SET_P
         ? parent->webappid : child->webappid);
     merged->sensor_id = (child->sensor_id == NOT_SET_P
@@ -726,9 +719,6 @@ void init_directory_config(directory_config *dcfg)
 
     /* Misc */
     if (dcfg->data_dir == NOT_SET_P) dcfg->data_dir = NULL;
-#ifdef WAF_JSON_LOGGING_ENABLE
-    if (dcfg->wafjsonlog_fd == NOT_SET_P) dcfg->wafjsonlog_fd = NULL;
-#endif
     if (dcfg->webappid == NOT_SET_P) dcfg->webappid = "default";
     if (dcfg->sensor_id == NOT_SET_P) dcfg->sensor_id = "default";
     if (dcfg->httpBlkey == NOT_SET_P) dcfg->httpBlkey = NULL;
@@ -1544,7 +1534,7 @@ static const char *cmd_data_dir(cmd_parms *cmd, void *_dcfg, const char *p1)
 {
 #ifdef WAF_JSON_LOGGING_ENABLE
     int rc;
-    char wafjsonlog_path[1024]; 
+    char wafjsonlog_path[WAF_LOG_PATH_LENGTH]; 
 #endif
     directory_config *dcfg = (directory_config *)_dcfg;
 
@@ -1557,7 +1547,7 @@ static const char *cmd_data_dir(cmd_parms *cmd, void *_dcfg, const char *p1)
 #ifdef WAF_JSON_LOGGING_ENABLE
     strcpy( wafjsonlog_path, dcfg->data_dir );
     strcat( wafjsonlog_path, WAF_LOG_UTIL_FILE );
-    rc = apr_file_open(&dcfg->wafjsonlog_fd, wafjsonlog_path,
+    rc = apr_file_open(&msc_waf_log_fd, wafjsonlog_path,
                    APR_WRITE | APR_APPEND | APR_CREATE | APR_BINARY,
                    CREATEMODE | APR_WREAD, cmd->pool);
 
@@ -1565,10 +1555,15 @@ static const char *cmd_data_dir(cmd_parms *cmd, void *_dcfg, const char *p1)
         return apr_psprintf(cmd->pool, "ModSecurity: Failed to open wafjson log file: %s",
             wafjsonlog_path);
     }
+    
+    // Global variable to share between threads
+    strncpy( msc_waf_log_path, wafjsonlog_path, WAF_LOG_PATH_LENGTH );
+    msc_waf_log_cmd = cmd;
 #endif
     return NULL;
 }
 
+
 static const char *cmd_debug_log(cmd_parms *cmd, void *_dcfg, const char *p1)
 {
     directory_config *dcfg = (directory_config *)_dcfg;
diff --git a/apache2/apache2_util.c b/apache2/apache2_util.c
index b91d2855d1..1e7a16a9b6 100755
--- a/apache2/apache2_util.c
+++ b/apache2/apache2_util.c
@@ -390,6 +390,7 @@ static void internal_log_ex(request_rec *r, directory_config *dcfg, modsec_rec *
     char *str = NULL;
     char str1[1024] = "";
     char str2[1256] = "";
+    int rc = 0;
 
     /* Find the logging FD and determine the logging level from configuration. */
     if (dcfg != NULL) {
@@ -461,7 +462,25 @@ static void internal_log_ex(request_rec *r, directory_config *dcfg, modsec_rec *
         else requestheaderhostname = "";
 
 #ifdef WAF_JSON_LOGGING_ENABLE
-        send_waf_log(msr->modsecurity->wafjsonlog_lock, dcfg->wafjsonlog_fd, str1, r->useragent_ip ? r->useragent_ip : r->connection->client_ip, log_escape(msr->mp, r->uri), dcfg->is_enabled, (char*)msr->hostname, unique_id, r);
+        if (msc_waf_log_reopened) {
+            rc = apr_file_open(&msc_waf_log_fd, msc_waf_log_path,
+                   APR_WRITE | APR_APPEND | APR_CREATE | APR_BINARY,
+                   CREATEMODE | APR_WREAD, msc_waf_log_cmd->pool);
+
+            if (rc != APR_SUCCESS) {
+                #if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER > 2
+                	ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r,
+                            "ModSecurity not able to reopen %s file", WAF_LOG_UTIL_FILE);
+                #else
+                        ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r->server,
+                            "ModSecurity not able to reopen %s file", WAF_LOG_UTIL_FILE);
+                #endif
+            }
+            
+            msc_waf_log_reopened = 0;
+        }
+
+        send_waf_log(msr->modsecurity->wafjsonlog_lock, msc_waf_log_fd, str1, r->useragent_ip ? r->useragent_ip : r->connection->client_ip, log_escape(msr->mp, r->uri), dcfg->is_enabled, (char*)msr->hostname, unique_id, r);
 #endif
 
 #if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER > 2
diff --git a/apache2/mod_security2.c b/apache2/mod_security2.c
index d11093acc0..c719e6f5bf 100755
--- a/apache2/mod_security2.c
+++ b/apache2/mod_security2.c
@@ -95,6 +95,10 @@ TreeRoot DSOLOCAL *conn_write_state_suspicious_list = 0;
 #ifdef WAF_JSON_LOGGING_ENABLE
 char DSOLOCAL *msc_waf_resourceId = NULL;
 char DSOLOCAL *msc_waf_instanceId = NULL;
+sig_atomic_t DSOLOCAL msc_waf_log_reopened = 0;
+apr_file_t DSOLOCAL *msc_waf_log_fd = NULL;
+char DSOLOCAL msc_waf_log_path[WAF_LOG_PATH_LENGTH] = ""; 
+cmd_parms DSOLOCAL *msc_waf_log_cmd = NULL;
 #endif
 
 #ifndef _WIN32
diff --git a/apache2/modsecurity.c b/apache2/modsecurity.c
index 0faa5dff79..73660fc5ac 100755
--- a/apache2/modsecurity.c
+++ b/apache2/modsecurity.c
@@ -240,12 +240,23 @@ int modsecurity_init(msc_engine *msce, apr_pool_t *mp) {
     return 1;
 }
 
+#ifdef WAF_JSON_LOGGING_ENABLE
+void modsecurity_handle_signals_for_reopen(int signum)
+{
+    msc_waf_log_reopened = 1;
+}
+#endif
+
 /**
  * Performs per-child (new process) initialisation.
  */
 void modsecurity_child_init(msc_engine *msce) {
     struct waf_lock_args *lock_args;
     char *lock_name;
+#ifdef WAF_JSON_LOGGING_ENABLE
+    struct sigaction psa;
+    sigset_t block_mask;
+#endif
 
     /* Need to call this once per process before any other XML calls. */
     xmlInitParser();
@@ -266,7 +277,13 @@ void modsecurity_child_init(msc_engine *msce) {
 
     set_lock_args(lock_args, WAFJSONLOG_LOCK_ID);
 
-    waf_create_lock(msce->wafjsonlog_lock, lock_args);    
+    waf_create_lock(msce->wafjsonlog_lock, lock_args); 
+
+    sigfillset (&block_mask);
+    psa.sa_handler = modsecurity_handle_signals_for_reopen;
+    psa.sa_mask = block_mask;
+    psa.sa_flags = 0;
+    sigaction(SIGUSR1, &psa, NULL);     
 #endif
 
     if (msce->geo_lock == NULL) {
diff --git a/apache2/modsecurity.h b/apache2/modsecurity.h
index 2ec5a77e4b..cdd707300a 100755
--- a/apache2/modsecurity.h
+++ b/apache2/modsecurity.h
@@ -115,6 +115,10 @@ typedef struct msc_parm msc_parm;
 #define SECMARKER_ARGS                          "@noMatch"
 #define SECMARKER_BASE_ACTIONS                  "t:none,pass,marker:"
 
+#ifdef WAF_JSON_LOGGING_ENABLE
+#define WAF_LOG_PATH_LENGTH                     1024
+#endif
+
 #if !defined(OS2) && !defined(WIN32) && !defined(BEOS) && !defined(NETWARE)
 #include "unixd.h"
 #define __SET_MUTEX_PERMS
@@ -171,6 +175,10 @@ extern DSOLOCAL int *unicode_map_table;
 #ifdef WAF_JSON_LOGGING_ENABLE
 extern DSOLOCAL char *msc_waf_resourceId;
 extern DSOLOCAL char *msc_waf_instanceId;
+extern DSOLOCAL sig_atomic_t msc_waf_log_reopened;
+extern DSOLOCAL apr_file_t *msc_waf_log_fd;
+extern DSOLOCAL char msc_waf_log_path[WAF_LOG_PATH_LENGTH];
+extern DSOLOCAL cmd_parms *msc_waf_log_cmd;
 #endif
 
 #ifndef _WIN32
@@ -596,9 +604,6 @@ struct directory_config {
 
     /* Misc */
     const char          *data_dir;
-#ifdef WAF_JSON_LOGGING_ENABLE
-    apr_file_t          *wafjsonlog_fd;
-#endif
     const char          *webappid;
     const char          *sensor_id;
     const char          *httpBlkey;

From 43669754ed3c5f515116c7ad3b960921ca5cd6d4 Mon Sep 17 00:00:00 2001
From: Vladimir Krivopalov <vlkrivop@microsoft.com>
Date: Tue, 12 Mar 2019 12:18:25 -0700
Subject: [PATCH 19/58] Turn tabs into 4 spaces in the entire project.

Signed-off-by: Vladimir Krivopalov <vlkrivop@microsoft.com>
---
 apache2/apache2_config.c                 |   2 +-
 apache2/apache2_util.c                   |  18 +-
 apache2/libinjection/libinjection_sqli.c |   8 +-
 apache2/mod_security2.c                  |   2 +-
 apache2/modsecurity.h                    |  28 +-
 apache2/modsecurity_config.h             |   2 +-
 apache2/msc_json.h                       |   2 +-
 apache2/msc_logging.c                    |  22 +-
 apache2/msc_release.h                    |   6 +-
 apache2/msc_util.c                       |  32 +-
 apache2/persist_dbm.c                    |  34 +-
 apache2/re.c                             |   2 +-
 apache2/re_actions.c                     |  12 +-
 iis/main.cpp                             |   2 +-
 iis/moduleconfig.cpp                     |  10 +-
 iis/moduleconfig.h                       |   4 +-
 iis/mymodule.cpp                         | 780 +++++++++++------------
 iis/mymodule.def                         |   2 +-
 iis/mymodulefactory.h                    |   2 +-
 mlogc/mlogc.c                            |  54 +-
 standalone/api.c                         |  54 +-
 standalone/api.h                         |   2 +-
 standalone/buckets.c                     |   2 +-
 standalone/config.c                      | 298 ++++-----
 standalone/filters.c                     |  68 +-
 standalone/hooks.c                       |   4 +-
 standalone/server.c                      |  66 +-
 27 files changed, 759 insertions(+), 759 deletions(-)

diff --git a/apache2/apache2_config.c b/apache2/apache2_config.c
index 6051c39316..75ede330da 100755
--- a/apache2/apache2_config.c
+++ b/apache2/apache2_config.c
@@ -820,7 +820,7 @@ static const char *add_rule(cmd_parms *cmd, directory_config *dcfg, int type,
     }
 
 #ifndef ALLOW_ID_NOT_UNIQUE
-	/* Rules must have uniq ID */
+    /* Rules must have uniq ID */
     type_rule = (dcfg->tmp_chain_starter == NULL);
 #if defined(WITH_LUA)
             type_rule = (type != RULE_TYPE_LUA && type_rule);
diff --git a/apache2/apache2_util.c b/apache2/apache2_util.c
index 1e7a16a9b6..3ec830af19 100755
--- a/apache2/apache2_util.c
+++ b/apache2/apache2_util.c
@@ -200,7 +200,7 @@ char *get_env_var(request_rec *r, char *name) {
 static void get_field_value(const char* from, const char* to, const char* text, char* output) {
     char* first = strstr(text, from);
     int first_index = first - text;
-	char backslash[] = "\\";
+    char backslash[] = "\\";
 
     if (first != NULL ) {
         if ((first_index > 0 && strncmp((first-1), backslash, 2) != 0) || (first_index == 0)) {
@@ -332,16 +332,16 @@ static void send_waf_log(struct waf_lock* lock, apr_file_t* fd, const char* str1
     char waf_ruleset_type[50] = "";
     char waf_ruleset_version[50] = "";
     char waf_detail_message[1024] = "";
-	char waf_unique_id[100] = "";
+    char waf_unique_id[100] = "";
 
     get_field_value("[file ", "]", str1, waf_filename);
     get_field_value("[id ", "]", str1, waf_id);
     get_field_value("[line ", "]", str1, waf_line);
     get_field_value("[msg ", "]", str1, waf_message);
     get_field_value("[data ", "]", str1, waf_data);
-	get_field_value("[ver ", "]", str1, waf_ruleset_info);
-	get_field_value("[unique_id ", "]", unique_id, waf_unique_id);
-	get_ip_port(ip_port, waf_ip, waf_port);
+    get_field_value("[ver ", "]", str1, waf_ruleset_info);
+    get_field_value("[unique_id ", "]", unique_id, waf_unique_id);
+    get_ip_port(ip_port, waf_ip, waf_port);
     get_detail_message(str1, waf_detail_message); 
     get_short_filename(waf_filename);
     get_ruleset_type_version(waf_ruleset_info, waf_ruleset_type, waf_ruleset_version); 
@@ -438,8 +438,8 @@ static void internal_log_ex(request_rec *r, directory_config *dcfg, modsec_rec *
 
     /* Send message levels 1-3 to the Apache error log and 
      * add it to the message list in the audit log. */
-	char *unique_id = (char *)get_env_var(r, "UNIQUE_ID");
-	if (level <= 3) {
+    char *unique_id = (char *)get_env_var(r, "UNIQUE_ID");
+    if (level <= 3) {
         char *hostname = (char *)msr->hostname;
         char *requestheaderhostname = (char *)r->hostname;
 
@@ -469,7 +469,7 @@ static void internal_log_ex(request_rec *r, directory_config *dcfg, modsec_rec *
 
             if (rc != APR_SUCCESS) {
                 #if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER > 2
-                	ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r,
+                    ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r,
                             "ModSecurity not able to reopen %s file", WAF_LOG_UTIL_FILE);
                 #else
                         ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r->server,
@@ -484,7 +484,7 @@ static void internal_log_ex(request_rec *r, directory_config *dcfg, modsec_rec *
 #endif
 
 #if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER > 2
-	ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r,
+    ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r,
             "[client %s] ModSecurity: %s%s [uri \"%s\"]%s%s", r->useragent_ip ? r->useragent_ip : r->connection->client_ip, str1,
             hostname, log_escape(msr->mp, r->uri), unique_id, requestheaderhostname);
 #else
diff --git a/apache2/libinjection/libinjection_sqli.c b/apache2/libinjection/libinjection_sqli.c
index cecbbea3fb..d2048ec010 100644
--- a/apache2/libinjection/libinjection_sqli.c
+++ b/apache2/libinjection/libinjection_sqli.c
@@ -1444,7 +1444,7 @@ int libinjection_sqli_fold(struct libinjection_sqli_state * sf)
                 )
             {
                 if (pos > LIBINJECTION_SQLI_MAX_TOKENS) {
-		    st_copy(&(sf->tokenvec[1]), &(sf->tokenvec[LIBINJECTION_SQLI_MAX_TOKENS]));
+            st_copy(&(sf->tokenvec[1]), &(sf->tokenvec[LIBINJECTION_SQLI_MAX_TOKENS]));
                     pos = 2;
                     left = 0;
                 } else {
@@ -1521,9 +1521,9 @@ int libinjection_sqli_fold(struct libinjection_sqli_state * sf)
             continue;
         } else if (sf->tokenvec[left].type == TYPE_SEMICOLON &&
                    sf->tokenvec[left+1].type == TYPE_FUNCTION &&
-		   (sf->tokenvec[left+1].val[0] == 'I' ||
-		    sf->tokenvec[left+1].val[0] == 'i' ) &&
-		   (sf->tokenvec[left+1].val[1] == 'F' ||
+           (sf->tokenvec[left+1].val[0] == 'I' ||
+            sf->tokenvec[left+1].val[0] == 'i' ) &&
+           (sf->tokenvec[left+1].val[1] == 'F' ||
                     sf->tokenvec[left+1].val[1] == 'f' )) {
             /* IF is normally a function, except in Transact-SQL where it can be used as a
              * standalone control flow operator, e.g. ; IF 1=1 ...
diff --git a/apache2/mod_security2.c b/apache2/mod_security2.c
index c719e6f5bf..272f4fd35d 100755
--- a/apache2/mod_security2.c
+++ b/apache2/mod_security2.c
@@ -294,7 +294,7 @@ int perform_interception(modsec_rec *msr) {
                     csd = ap_get_module_config(msr->r->connection->conn_config, &core_module);
                 }
 #else
-		csd = ap_get_module_config(msr->r->connection->conn_config, &core_module);
+        csd = ap_get_module_config(msr->r->connection->conn_config, &core_module);
 #endif
                 if (csd) {
                     if (apr_socket_close(csd) == APR_SUCCESS) {
diff --git a/apache2/modsecurity.h b/apache2/modsecurity.h
index cdd707300a..2e0367aa7a 100755
--- a/apache2/modsecurity.h
+++ b/apache2/modsecurity.h
@@ -231,8 +231,8 @@ extern DSOLOCAL char *msc_waf_lock_group;
 #define STATUS_ENGINE_ENABLED           1
 #define STATUS_ENGINE_DISABLED          0
 
-#define REMOTE_RULES_ABORT_ON_FAIL	0
-#define REMOTE_RULES_WARN_ON_FAIL	1
+#define REMOTE_RULES_ABORT_ON_FAIL    0
+#define REMOTE_RULES_WARN_ON_FAIL    1
 
 #define HASH_DISABLED             0
 #define HASH_ENABLED              1
@@ -412,8 +412,8 @@ struct modsec_rec {
 
     apr_size_t           msc_reqbody_no_files_length;
 
-    char		*msc_full_request_buffer;
-    int			msc_full_request_length;
+    char        *msc_full_request_buffer;
+    int            msc_full_request_length;
 
     char                *multipart_filename;
     char                *multipart_name;
@@ -439,15 +439,15 @@ struct modsec_rec {
 
     /* performance measurement */
     apr_time_t       request_time;
-    apr_time_t		 time_phase1;
-    apr_time_t		 time_phase2;
-    apr_time_t		 time_phase3;
-    apr_time_t		 time_phase4;
-    apr_time_t		 time_phase5;
-    apr_time_t		 time_storage_read;
-    apr_time_t		 time_storage_write;
-    apr_time_t		 time_logging;
-    apr_time_t		 time_gc;
+    apr_time_t         time_phase1;
+    apr_time_t         time_phase2;
+    apr_time_t         time_phase3;
+    apr_time_t         time_phase4;
+    apr_time_t         time_phase5;
+    apr_time_t         time_storage_read;
+    apr_time_t         time_storage_write;
+    apr_time_t         time_logging;
+    apr_time_t         time_gc;
     apr_table_t      *perf_rules;
 
     apr_array_header_t  *matched_rules;
@@ -670,7 +670,7 @@ struct directory_config {
     int                 xml_external_entity;
 #ifdef MEMORY_DATABASE_ENABLE
     /* AGMDB */
-    directory_config	*root_config;
+    directory_config    *root_config;
     int                 db_option;
     void                *agmdb_handles;    
 #endif
diff --git a/apache2/modsecurity_config.h b/apache2/modsecurity_config.h
index f18101683b..69d9d8ef19 100644
--- a/apache2/modsecurity_config.h
+++ b/apache2/modsecurity_config.h
@@ -2,7 +2,7 @@
  * so this is here to prevent that by removing them.
  */
 
-#ifndef	WIN32
+#ifndef    WIN32
 
 /* Undefine all these so there are no conflicts */
 #undef PACKAGE
diff --git a/apache2/msc_json.h b/apache2/msc_json.h
index 02326ec03d..f22fe3ab2c 100644
--- a/apache2/msc_json.h
+++ b/apache2/msc_json.h
@@ -54,7 +54,7 @@ int DSOLOCAL json_complete(modsec_rec *msr, char **error_msg);
 apr_status_t DSOLOCAL json_cleanup(modsec_rec *msr);
 
 int DSOLOCAL json_process_chunk(modsec_rec *msr, const char *buf,
-		unsigned int size, char **error_msg);
+        unsigned int size, char **error_msg);
 
 #endif
 #endif
diff --git a/apache2/msc_logging.c b/apache2/msc_logging.c
index 35d867eb77..0f5ade79bb 100755
--- a/apache2/msc_logging.c
+++ b/apache2/msc_logging.c
@@ -735,7 +735,7 @@ void sec_audit_logger_json(modsec_rec *msr) {
 
     /* Lock the mutex, but only if we are using serial format. */
     if (msr->txcfg->auditlog_type != AUDITLOG_CONCURRENT) {
-	    rc = waf_get_exclusive_lock(msr->modsecurity->auditlog_lock);
+        rc = waf_get_exclusive_lock(msr->modsecurity->auditlog_lock);
         if (waf_lock_is_error(rc)) {
             msr_log(msr, 1, "Audit log: Failed to lock global mutex: %s",
                 get_apr_error(msr->mp, rc));
@@ -1279,7 +1279,7 @@ void sec_audit_logger_json(modsec_rec *msr) {
             yajl_gen_map_close(g); // sanitized args map is finished
         }
 #ifdef LOG_NO_SERVER_CONTEXT
-	}
+    }
 #endif
 
         /* Web application info. */
@@ -1447,7 +1447,7 @@ void sec_audit_logger_json(modsec_rec *msr) {
     if (msr->txcfg->auditlog_type != AUDITLOG_CONCURRENT) {
 
         /* Unlock the mutex we used to serialise access to the audit log file. */
-	    rc = waf_free_exclusive_lock(msr->modsecurity->auditlog_lock);
+        rc = waf_free_exclusive_lock(msr->modsecurity->auditlog_lock);
         if (waf_lock_is_error(rc)) {
             msr_log(msr, 1, "Audit log: Failed to unlock global mutex: %s",
                     get_apr_error(msr->mp, rc));
@@ -1622,7 +1622,7 @@ void sec_audit_logger_native(modsec_rec *msr) {
 
     /* Lock the mutex, but only if we are using serial format. */
     if (msr->txcfg->auditlog_type != AUDITLOG_CONCURRENT) {
-	    rc = waf_get_exclusive_lock(msr->modsecurity->auditlog_lock);
+        rc = waf_get_exclusive_lock(msr->modsecurity->auditlog_lock);
         if (waf_lock_is_error(rc)) {
             msr_log(msr, 1, "Audit log: Failed to lock global mutex: %s",
                 get_apr_error(msr->mp, rc));
@@ -1991,16 +1991,16 @@ void sec_audit_logger_native(modsec_rec *msr) {
 
         /* Apache-Handler */
 #ifdef LOG_NO_HANDLER
-	if (msr->txcfg->debuglog_level >= 9)
+    if (msr->txcfg->debuglog_level >= 9)
 #endif
-	if (msr->r->handler != NULL) {
+    if (msr->r->handler != NULL) {
             text = apr_psprintf(msr->mp, "Apache-Handler: %s\n", msr->r->handler);
             sec_auditlog_write(msr, text, strlen(text));
         }
 
         /* Stopwatch; left in for compatibility reasons */
 #ifdef LOG_NO_STOPWATCH
-	if (msr->txcfg->debuglog_level >= 9) {
+    if (msr->txcfg->debuglog_level >= 9) {
 #endif
         text = apr_psprintf(msr->mp, "Stopwatch: %" APR_TIME_T_FMT " %" APR_TIME_T_FMT " (- - -)\n",
             msr->request_time, (now - msr->request_time));
@@ -2022,7 +2022,7 @@ void sec_audit_logger_native(modsec_rec *msr) {
         /* ENH Only write this when the output was chunked. */
         /* ENH Add info when request body was decompressed, dechunked too. */
 #ifdef LOG_NO_DECHUNK
-	if (msr->txcfg->debuglog_level >= 9)
+    if (msr->txcfg->debuglog_level >= 9)
 #endif
         if (wrote_response_body) {
             text = apr_psprintf(msr->mp, "Response-Body-Transformed: Dechunked\n");
@@ -2101,10 +2101,10 @@ void sec_audit_logger_native(modsec_rec *msr) {
             }
         }
 #ifdef LOG_NO_SERVER_CONTEXT
-	}
+    }
 #endif
 
-	/* Web application info. */
+    /* Web application info. */
         if ( ((msr->txcfg->webappid != NULL)&&(strcmp(msr->txcfg->webappid, "default") != 0))
             || (msr->sessionid != NULL) || (msr->userid != NULL))
         {
@@ -2227,7 +2227,7 @@ void sec_audit_logger_native(modsec_rec *msr) {
         sec_auditlog_write(msr, "\n", 1);
 
         /* Unlock the mutex we used to serialise access to the audit log file. */
-	    rc = waf_free_exclusive_lock(msr->modsecurity->auditlog_lock);
+        rc = waf_free_exclusive_lock(msr->modsecurity->auditlog_lock);
         if (waf_lock_is_error(rc)) {
             msr_log(msr, 1, "Audit log: Failed to unlock global mutex: %s",
                     get_apr_error(msr->mp, rc));
diff --git a/apache2/msc_release.h b/apache2/msc_release.h
index dcfde11c89..f1793be7ad 100644
--- a/apache2/msc_release.h
+++ b/apache2/msc_release.h
@@ -49,13 +49,13 @@
   MODSEC_VERSION_SUFFIX
 
 /* Apache Module Defines */
-#ifdef	VERSION_IIS
+#ifdef    VERSION_IIS
 #define MODSEC_MODULE_NAME "ModSecurity for IIS (STABLE)"
 #else
-#ifdef	VERSION_NGINX
+#ifdef    VERSION_NGINX
 #define MODSEC_MODULE_NAME "ModSecurity for nginx (STABLE)"
 #else
-#ifdef	VERSION_STANDALONE
+#ifdef    VERSION_STANDALONE
 #define MODSEC_MODULE_NAME "ModSecurity Standalone (STABLE)"
 #else
 #define MODSEC_MODULE_NAME "ModSecurity for Apache"
diff --git a/apache2/msc_util.c b/apache2/msc_util.c
index 4f7fc2d084..be3e2ec071 100644
--- a/apache2/msc_util.c
+++ b/apache2/msc_util.c
@@ -1225,22 +1225,22 @@ char *log_escape(apr_pool_t *mp, const char *text) {
 
 char *log_escape_nq(apr_pool_t *mp, const char *text) {
 #ifdef VERSION_IIS
-	int l = 0;
-
-	// this is a workaround for unknown bug that causes 'text' sometimes to lack zero-termination
-	//
-	__try
-	{
-		l = text ? strlen(text) : 0;
-	}
-	__except(EXCEPTION_EXECUTE_HANDLER)
-	{
-		l = -1;
-	}
-	if(l < 0)
-	    return _log_escape(mp, "BUG: see log_escape_nq()", 24, 0, 0, 0);
-
-	return _log_escape(mp, (const unsigned char *)text, l, 0, 0, 0);
+    int l = 0;
+
+    // this is a workaround for unknown bug that causes 'text' sometimes to lack zero-termination
+    //
+    __try
+    {
+        l = text ? strlen(text) : 0;
+    }
+    __except(EXCEPTION_EXECUTE_HANDLER)
+    {
+        l = -1;
+    }
+    if(l < 0)
+        return _log_escape(mp, "BUG: see log_escape_nq()", 24, 0, 0, 0);
+
+    return _log_escape(mp, (const unsigned char *)text, l, 0, 0, 0);
 #else
     return _log_escape(mp, (const unsigned char *)text, text ? strlen(text) : 0, 0, 0, 0);
 #endif
diff --git a/apache2/persist_dbm.c b/apache2/persist_dbm.c
index 04262c97f4..dbe7e5ad6a 100755
--- a/apache2/persist_dbm.c
+++ b/apache2/persist_dbm.c
@@ -171,8 +171,8 @@ static apr_table_t *collection_retrieve_ex(int db_option, void *existing_dbm, mo
         
         if (existing_dbm == NULL) {
 #ifdef GLOBAL_COLLECTION_LOCK
-	    rc = waf_get_exclusive_lock(msr->modsecurity->dbm_lock);
-	    if (waf_lock_is_error(rc)) {
+        rc = waf_get_exclusive_lock(msr->modsecurity->dbm_lock);
+        if (waf_lock_is_error(rc)) {
                 msr_log(msr, 1, "collection_retrieve_ex: Failed to lock proc mutex: %s",
                         get_apr_error(msr->mp, rc));
                 goto cleanup;
@@ -183,7 +183,7 @@ static apr_table_t *collection_retrieve_ex(int db_option, void *existing_dbm, mo
             if (rc != APR_SUCCESS) {
                 apr_dbm = NULL;
 #ifdef GLOBAL_COLLECTION_LOCK
-	            waf_free_exclusive_lock(msr->modsecurity->dbm_lock);
+                waf_free_exclusive_lock(msr->modsecurity->dbm_lock);
 #endif
                 goto cleanup;
             }
@@ -256,7 +256,7 @@ static apr_table_t *collection_retrieve_ex(int db_option, void *existing_dbm, mo
         if (existing_dbm == NULL) {
             apr_sdbm_close(apr_dbm);
 #ifdef GLOBAL_COLLECTION_LOCK
-	        waf_free_exclusive_lock(msr->modsecurity->dbm_lock);
+            waf_free_exclusive_lock(msr->modsecurity->dbm_lock);
 #endif
             apr_dbm = NULL;
         }
@@ -339,8 +339,8 @@ static apr_table_t *collection_retrieve_ex(int db_option, void *existing_dbm, mo
 #endif
             if (existing_dbm == NULL) {
 #ifdef GLOBAL_COLLECTION_LOCK
-	        rc = waf_get_exclusive_lock(msr->modsecurity->dbm_lock);
-	        if (waf_lock_is_error(rc)) {
+            rc = waf_get_exclusive_lock(msr->modsecurity->dbm_lock);
+            if (waf_lock_is_error(rc)) {
                     msr_log(msr, 1, "collection_retrieve_ex: Failed to lock proc mutex: %s",
                             get_apr_error(msr->mp, rc));
                     goto cleanup;
@@ -353,7 +353,7 @@ static apr_table_t *collection_retrieve_ex(int db_option, void *existing_dbm, mo
                         log_escape(msr->mp, dbm_filename), get_apr_error(msr->mp, rc));
                     apr_dbm = NULL;
 #ifdef GLOBAL_COLLECTION_LOCK
-	                waf_free_exclusive_lock(msr->modsecurity->dbm_lock);
+                    waf_free_exclusive_lock(msr->modsecurity->dbm_lock);
 #endif
                     goto cleanup;
                 }
@@ -368,7 +368,7 @@ static apr_table_t *collection_retrieve_ex(int db_option, void *existing_dbm, mo
             if (existing_dbm == NULL) {
                 apr_sdbm_close(apr_dbm);
 #ifdef GLOBAL_COLLECTION_LOCK
-	            waf_free_exclusive_lock(msr->modsecurity->dbm_lock);
+                waf_free_exclusive_lock(msr->modsecurity->dbm_lock);
 #endif
                 apr_dbm = NULL;
             }
@@ -451,7 +451,7 @@ static apr_table_t *collection_retrieve_ex(int db_option, void *existing_dbm, mo
 
         apr_sdbm_close(apr_dbm);
 #ifdef GLOBAL_COLLECTION_LOCK
-	    waf_free_exclusive_lock(msr->modsecurity->dbm_lock);
+        waf_free_exclusive_lock(msr->modsecurity->dbm_lock);
 #endif
     }
 
@@ -466,7 +466,7 @@ static apr_table_t *collection_retrieve_ex(int db_option, void *existing_dbm, mo
         if ((existing_dbm == NULL) && apr_dbm) {
             apr_sdbm_close(apr_dbm);
 #ifdef GLOBAL_COLLECTION_LOCK
-	        waf_free_exclusive_lock(msr->modsecurity->dbm_lock);
+            waf_free_exclusive_lock(msr->modsecurity->dbm_lock);
 #endif
         }
 #ifdef MEMORY_DATABASE_ENABLE
@@ -644,8 +644,8 @@ static int collection_store_ex(int db_option, modsec_rec *msr, apr_table_t *col)
         
 #ifdef GLOBAL_COLLECTION_LOCK
         /* Need to lock to pull in the stored data again and apply deltas. */
-	rc = waf_get_exclusive_lock(msr->modsecurity->dbm_lock);
-	if (waf_lock_is_error(rc)) {
+    rc = waf_get_exclusive_lock(msr->modsecurity->dbm_lock);
+    if (waf_lock_is_error(rc)) {
             msr_log(msr, 1, "collection_store: Failed to lock proc mutex: %s",
                     get_apr_error(msr->mp, rc));
             goto error;
@@ -656,7 +656,7 @@ static int collection_store_ex(int db_option, modsec_rec *msr, apr_table_t *col)
             CREATEMODE, msr->mp);
         if (rc != APR_SUCCESS) {
 #ifdef GLOBAL_COLLECTION_LOCK
-	        waf_free_exclusive_lock(msr->modsecurity->dbm_lock);
+            waf_free_exclusive_lock(msr->modsecurity->dbm_lock);
 #endif
             msr_log(msr, 1, "collection_store_ex_origin: Failed to access DBM file \"%s\": %s", log_escape(msr->mp, dbm_filename),
                 get_apr_error(msr->mp, rc));
@@ -784,7 +784,7 @@ static int collection_store_ex(int db_option, modsec_rec *msr, apr_table_t *col)
             if (apr_dbm != NULL) {
 #ifdef GLOBAL_COLLECTION_LOCK
                 apr_sdbm_close(apr_dbm);
-	            waf_free_exclusive_lock(msr->modsecurity->dbm_lock);
+                waf_free_exclusive_lock(msr->modsecurity->dbm_lock);
 #else
                 apr_sdbm_unlock(apr_dbm);
                 apr_sdbm_close(apr_dbm);
@@ -866,7 +866,7 @@ static int collection_store_ex(int db_option, modsec_rec *msr, apr_table_t *col)
             if (apr_dbm != NULL) {
 #ifdef GLOBAL_COLLECTION_LOCK
                 apr_sdbm_close(apr_dbm);
-	            waf_free_exclusive_lock(msr->modsecurity->dbm_lock);
+                waf_free_exclusive_lock(msr->modsecurity->dbm_lock);
 #else
                 apr_sdbm_unlock(apr_dbm);
                 apr_sdbm_close(apr_dbm);
@@ -877,7 +877,7 @@ static int collection_store_ex(int db_option, modsec_rec *msr, apr_table_t *col)
         }
 #ifdef GLOBAL_COLLECTION_LOCK
         apr_sdbm_close(apr_dbm);
-	    waf_free_exclusive_lock(msr->modsecurity->dbm_lock);
+        waf_free_exclusive_lock(msr->modsecurity->dbm_lock);
 #else
         apr_sdbm_unlock(apr_dbm);
         apr_sdbm_close(apr_dbm);
@@ -1063,7 +1063,7 @@ static int collections_remove_stale_ex(int db_option, modsec_rec *msr, const cha
                     rc = apr_sdbm_delete(apr_dbm, key);
                     if (rc != APR_SUCCESS) {
 #ifdef LOG_NO_COLL_DELET_PB
-			if (msr->txcfg->debuglog_level >= 9)
+            if (msr->txcfg->debuglog_level >= 9)
 #endif
                         msr_log(msr, 1, "collections_remove_stale: Failed deleting collection (name \"%s\", "
                             "key \"%s\"): %s", log_escape(msr->mp, col_name),
diff --git a/apache2/re.c b/apache2/re.c
index cf9f655ad9..6573d625c4 100644
--- a/apache2/re.c
+++ b/apache2/re.c
@@ -1265,7 +1265,7 @@ msre_actionset *msre_actionset_merge(msre_engine *engine, apr_pool_t *mp, msre_a
 
     if (inherit_by_default == 0) {
         /* There is nothing to merge in this case. */
-	    return msre_actionset_copy(mp, child);
+        return msre_actionset_copy(mp, child);
     }
 
     /* Start with a copy of the parent configuration. */
diff --git a/apache2/re_actions.c b/apache2/re_actions.c
index f81ddc87c7..506b2f37ee 100644
--- a/apache2/re_actions.c
+++ b/apache2/re_actions.c
@@ -1253,10 +1253,10 @@ static apr_status_t msre_action_ctl_execute(modsec_rec *msr, apr_pool_t *mptmp,
         if (msr->txcfg->debuglog_level >= 4) {
             msr_log(msr, 4, "Ctl: ruleRemoveTargetByTag tag=%s targets=%s", p1, p2);
         }
-	if (p2 == NULL) {
+    if (p2 == NULL) {
             msr_log(msr, 1, "ModSecurity: Missing target for tag \"%s\"", p1);
-	    return -1;
-	}
+        return -1;
+    }
 
     re = apr_pcalloc(msr->mp, sizeof(rule_exception));
     re->type = RULE_EXCEPTION_REMOVE_TAG;
@@ -1568,7 +1568,7 @@ apr_status_t msre_action_setvar_execute(modsec_rec *msr, apr_pool_t *mptmp,
 
     if (strcasecmp(col_name,"USER") == 0 || strcasecmp(col_name,"SESSION") == 0
         || strcasecmp(col_name, "RESOURCE") == 0) {
-	real_col_name = apr_psprintf(mptmp, "%s_%s", msr->txcfg->webappid, col_name);
+    real_col_name = apr_psprintf(mptmp, "%s_%s", msr->txcfg->webappid, col_name);
     }
 
     /* Locate the collection. */
@@ -1581,8 +1581,8 @@ apr_status_t msre_action_setvar_execute(modsec_rec *msr, apr_pool_t *mptmp,
 
     if (target_col == NULL) {
         if (msr->txcfg->debuglog_level >= 3) {
-	    msr_log(msr, 3, "Could not set variable \"%s.%s\" as the collection does not exist.",
-	        log_escape(msr->mp, col_name), log_escape(msr->mp, var_name));
+        msr_log(msr, 3, "Could not set variable \"%s.%s\" as the collection does not exist.",
+            log_escape(msr->mp, col_name), log_escape(msr->mp, var_name));
         }
 
         return 0;
diff --git a/iis/main.cpp b/iis/main.cpp
index 8c179ccf10..db7451eea1 100644
--- a/iis/main.cpp
+++ b/iis/main.cpp
@@ -44,7 +44,7 @@ RegisterModule(DWORD, IHttpModuleRegistrationInfo* moduleInfo, IHttpServer * htt
     }
 
     // step 1: save the IHttpServer and the module context id for future use
-	//
+    //
     g_pModuleContext = moduleInfo->GetId();
     g_pHttpServer = httpServer;
 
diff --git a/iis/moduleconfig.cpp b/iis/moduleconfig.cpp
index 8f90a8a018..b78dc27d67 100644
--- a/iis/moduleconfig.cpp
+++ b/iis/moduleconfig.cpp
@@ -577,17 +577,17 @@ MODSECURITY_STORED_CONTEXT::GetConfig(
     HRESULT                          hr                 = S_OK;
     MODSECURITY_STORED_CONTEXT * pModuleConfig      = NULL;
     IHttpModuleContextContainer *    pMetadataContainer = NULL;
-	IAppHostConfigException *        pException         = NULL;
+    IAppHostConfigException *        pException         = NULL;
 
     pMetadataContainer = pContext->GetMetadata()->GetModuleContextContainer();
 
-	if ( pMetadataContainer == NULL )
-	{
+    if ( pMetadataContainer == NULL )
+    {
         hr = E_UNEXPECTED;
         return hr;
-	}
+    }
 
-    pModuleConfig = (MODSECURITY_STORED_CONTEXT *)pMetadataContainer->GetModuleContext( g_pModuleContext );	
+    pModuleConfig = (MODSECURITY_STORED_CONTEXT *)pMetadataContainer->GetModuleContext( g_pModuleContext );    
     if ( pModuleConfig != NULL )
     {
         //
diff --git a/iis/moduleconfig.h b/iis/moduleconfig.h
index a59c45e47f..e4f149b347 100644
--- a/iis/moduleconfig.h
+++ b/iis/moduleconfig.h
@@ -16,7 +16,7 @@
 
 #define MODSECURITY_SECTION                        L"system.webServer/ModSecurity"
 #define MODSECURITY_SECTION_ENABLED                L"enabled"
-#define MODSECURITY_SECTION_CONFIGFILE			   L"configFile"
+#define MODSECURITY_SECTION_CONFIGFILE               L"configFile"
 
 extern IHttpServer *                       g_pHttpServer;
 
@@ -30,7 +30,7 @@ class MODSECURITY_STORED_CONTEXT : public IHttpStoredContext
     MODSECURITY_STORED_CONTEXT();
     ~MODSECURITY_STORED_CONTEXT();
     
-	static
+    static
     HRESULT
     GetConfig(
         IHttpContext *   pContext,
diff --git a/iis/mymodule.cpp b/iis/mymodule.cpp
index 81f9b91a93..fddf37f8ba 100644
--- a/iis/mymodule.cpp
+++ b/iis/mymodule.cpp
@@ -83,46 +83,46 @@ struct RequestStoredContext
 
 char *GetIpAddr(apr_pool_t *pool, PSOCKADDR pAddr)
 {
-	const char *format = "%15[0-9.]:%5[0-9]";
-	char ip[16] = { 0 };  // ip4 addresses have max len 15
-	char port[6] = { 0 }; // port numbers are 16bit, ie 5 digits max
+    const char *format = "%15[0-9.]:%5[0-9]";
+    char ip[16] = { 0 };  // ip4 addresses have max len 15
+    char port[6] = { 0 }; // port numbers are 16bit, ie 5 digits max
 
-	DWORD len = 50;
-	char *buf = (char *)apr_palloc(pool, len);
+    DWORD len = 50;
+    char *buf = (char *)apr_palloc(pool, len);
 
-	if(buf == NULL)
-		return "";
+    if(buf == NULL)
+        return "";
 
-	buf[0] = 0;
+    buf[0] = 0;
 
-	WSAAddressToString(pAddr, sizeof(SOCKADDR), NULL, buf, &len);
+    WSAAddressToString(pAddr, sizeof(SOCKADDR), NULL, buf, &len);
 
-	// test for IPV4 with port on the end
-	if (sscanf(buf, format, ip, port) == 2) {
-		// IPV4 but with port - remove the port
-		char* input = ":";
-		char* ipv4 = strtok(buf, input);
-		return ipv4;
-	}
+    // test for IPV4 with port on the end
+    if (sscanf(buf, format, ip, port) == 2) {
+        // IPV4 but with port - remove the port
+        char* input = ":";
+        char* ipv4 = strtok(buf, input);
+        return ipv4;
+    }
 
-	return buf;
+    return buf;
 }
 
 apr_sockaddr_t *CopySockAddr(apr_pool_t *pool, PSOCKADDR pAddr)
 {
     apr_sockaddr_t *addr = (apr_sockaddr_t *)apr_palloc(pool, sizeof(apr_sockaddr_t));
-	int adrlen = 16, iplen = 4;
+    int adrlen = 16, iplen = 4;
 
-	if(pAddr->sa_family == AF_INET6)
-	{
-		adrlen = 46;
-		iplen = 16;
-	}
+    if(pAddr->sa_family == AF_INET6)
+    {
+        adrlen = 46;
+        iplen = 16;
+    }
 
-	addr->addr_str_len = adrlen;
-	addr->family = pAddr->sa_family;
+    addr->addr_str_len = adrlen;
+    addr->family = pAddr->sa_family;
 
-	addr->hostname = "unknown";
+    addr->hostname = "unknown";
 #ifdef WIN32
     addr->ipaddr_len = sizeof(IN_ADDR);
 #else
@@ -132,29 +132,29 @@ apr_sockaddr_t *CopySockAddr(apr_pool_t *pool, PSOCKADDR pAddr)
     addr->pool = pool;
     addr->port = 80;
 #ifdef WIN32
-	memcpy(&addr->sa.sin.sin_addr.S_un.S_addr, pAddr->sa_data, iplen);
+    memcpy(&addr->sa.sin.sin_addr.S_un.S_addr, pAddr->sa_data, iplen);
 #else
     memcpy(&addr->sa.sin.sin_addr.s_addr, pAddr->sa_data, iplen);
 #endif
-	addr->sa.sin.sin_family = pAddr->sa_family;
+    addr->sa.sin.sin_family = pAddr->sa_family;
     addr->sa.sin.sin_port = 80;
     addr->salen = sizeof(addr->sa);
-	addr->servname = addr->hostname;
+    addr->servname = addr->hostname;
 
-	return addr;
+    return addr;
 }
 
 //----------------------------------------------------------------------------
 
 char *ZeroTerminate(const char *str, size_t len, apr_pool_t *pool)
 {
-	char *_n = (char *)apr_palloc(pool, len + 1);
+    char *_n = (char *)apr_palloc(pool, len + 1);
 
-	memcpy(_n, str, len);
+    memcpy(_n, str, len);
 
-	_n[len] = 0;
+    _n[len] = 0;
 
-	return _n;
+    return _n;
 }
 
 //----------------------------------------------------------------------------
@@ -188,7 +188,7 @@ char *ConvertUTF16ToUTF8( __in const WCHAR * pszTextUTF16, size_t cchUTF16, apr_
 
     if ( cbUTF8 == 0 )
     {
-		return "";
+        return "";
     }
 
     //
@@ -215,28 +215,28 @@ char *ConvertUTF16ToUTF8( __in const WCHAR * pszTextUTF16, size_t cchUTF16, apr_
 
     if ( result == 0 )
     {
-		return "";
+        return "";
     }
 
-	pszUTF8[cchUTF8] =  0;
+    pszUTF8[cchUTF8] =  0;
 
     return pszUTF8;
 }
  
 static void Log(void *obj, int level, char *str)
 {
-	CMyHttpModule *mod = (CMyHttpModule *)obj;
-	WORD logcat = EVENTLOG_INFORMATION_TYPE;
+    CMyHttpModule *mod = (CMyHttpModule *)obj;
+    WORD logcat = EVENTLOG_INFORMATION_TYPE;
 
-	level &= APLOG_LEVELMASK;
+    level &= APLOG_LEVELMASK;
 
-	if(level <= APLOG_ERR)
-		logcat = EVENTLOG_ERROR_TYPE;
+    if(level <= APLOG_ERR)
+        logcat = EVENTLOG_ERROR_TYPE;
 
-	if(level == APLOG_WARNING || strstr(str, "Warning.") != NULL)
-		logcat = EVENTLOG_WARNING_TYPE;
+    if(level == APLOG_WARNING || strstr(str, "Warning.") != NULL)
+        logcat = EVENTLOG_WARNING_TYPE;
 
-	mod->WriteEventViewerLog(str, logcat);
+    mod->WriteEventViewerLog(str, logcat);
 }
 
 #define NOTE_IIS "iis-tx-context"
@@ -287,9 +287,9 @@ HRESULT CMyHttpModule::ReadFileChunk(HTTP_DATA_CHUNK *chunk, char *buf)
     OVERLAPPED ovl;
     DWORD dwDataStartOffset;
     ULONGLONG bytesTotal = 0;
-	BYTE *	pIoBuffer = NULL;
-	HANDLE	hIoEvent = INVALID_HANDLE_VALUE;
-	HRESULT hr = S_OK;
+    BYTE *    pIoBuffer = NULL;
+    HANDLE    hIoEvent = INVALID_HANDLE_VALUE;
+    HRESULT hr = S_OK;
 
     pIoBuffer = (BYTE *)VirtualAlloc(NULL,
                                         1,
@@ -298,7 +298,7 @@ HRESULT CMyHttpModule::ReadFileChunk(HTTP_DATA_CHUNK *chunk, char *buf)
     if (pIoBuffer == NULL)
     {
         hr = HRESULT_FROM_WIN32(GetLastError());
-		goto Done;
+        goto Done;
     }
 
     hIoEvent = CreateEvent(NULL,  // security attr
@@ -308,103 +308,103 @@ HRESULT CMyHttpModule::ReadFileChunk(HTTP_DATA_CHUNK *chunk, char *buf)
     if (hIoEvent == NULL)
     {
         hr = HRESULT_FROM_WIN32(GetLastError());
-		goto Done;
+        goto Done;
     }
 
-	while(bytesTotal < chunk->FromFileHandle.ByteRange.Length.QuadPart)
-	{
-		DWORD bytesRead = 0;
-		int was_eof = 0;
-		ULONGLONG offset = chunk->FromFileHandle.ByteRange.StartingOffset.QuadPart + bytesTotal;
-
-		ZeroMemory(&ovl, sizeof ovl);
-		ovl.hEvent     = hIoEvent;
-		ovl.Offset = (DWORD)offset;
-		dwDataStartOffset = ovl.Offset & (pageSize - 1);
-		ovl.Offset &= ~(pageSize - 1);
-		ovl.OffsetHigh = offset >> 32;
-
-		if (!ReadFile(chunk->FromFileHandle.FileHandle,
-					  pIoBuffer,
-					  pageSize,
-					  &bytesRead,
-					  &ovl))
-		{
-			DWORD dwErr = GetLastError();
-
-			switch (dwErr)
-			{
-			case ERROR_IO_PENDING:
-				//
-				// GetOverlappedResult can return without waiting for the
-				// event thus leaving it signalled and causing problems
-				// with future use of that event handle, so just wait ourselves
-				//
-				WaitForSingleObject(ovl.hEvent, INFINITE); // == WAIT_OBJECT_0);
-
-				if (!GetOverlappedResult(
-						 chunk->FromFileHandle.FileHandle,
-						 &ovl,
-						 &bytesRead,
-						 TRUE))
-				{
-					dwErr = GetLastError();
-
-					switch(dwErr)
-					{
-					case ERROR_HANDLE_EOF:
-						was_eof = 1;
-						break;
-
-					default:
-						hr = HRESULT_FROM_WIN32(dwErr);
-						goto Done;
-					}
-				}
-				break;
-
-			case ERROR_HANDLE_EOF:
-				was_eof = 1;
-				break;
-
-			default:
-				hr = HRESULT_FROM_WIN32(dwErr);
-				goto Done;
-			}
-		}
-
-		bytesRead -= dwDataStartOffset;
-
-		if (bytesRead > chunk->FromFileHandle.ByteRange.Length.QuadPart)
-		{
-			bytesRead = (DWORD)chunk->FromFileHandle.ByteRange.Length.QuadPart;
-		}
-		if ((bytesTotal + bytesRead) > chunk->FromFileHandle.ByteRange.Length.QuadPart)
-		{ 
-			bytesRead = chunk->FromFileHandle.ByteRange.Length.QuadPart - bytesTotal; 
-		}
-
-		memcpy(buf, pIoBuffer + dwDataStartOffset, bytesRead);
-
-		buf += bytesRead;
-		bytesTotal += bytesRead;
-
-		if(was_eof != 0)
-			chunk->FromFileHandle.ByteRange.Length.QuadPart = bytesTotal;
-	}
+    while(bytesTotal < chunk->FromFileHandle.ByteRange.Length.QuadPart)
+    {
+        DWORD bytesRead = 0;
+        int was_eof = 0;
+        ULONGLONG offset = chunk->FromFileHandle.ByteRange.StartingOffset.QuadPart + bytesTotal;
+
+        ZeroMemory(&ovl, sizeof ovl);
+        ovl.hEvent     = hIoEvent;
+        ovl.Offset = (DWORD)offset;
+        dwDataStartOffset = ovl.Offset & (pageSize - 1);
+        ovl.Offset &= ~(pageSize - 1);
+        ovl.OffsetHigh = offset >> 32;
+
+        if (!ReadFile(chunk->FromFileHandle.FileHandle,
+                      pIoBuffer,
+                      pageSize,
+                      &bytesRead,
+                      &ovl))
+        {
+            DWORD dwErr = GetLastError();
+
+            switch (dwErr)
+            {
+            case ERROR_IO_PENDING:
+                //
+                // GetOverlappedResult can return without waiting for the
+                // event thus leaving it signalled and causing problems
+                // with future use of that event handle, so just wait ourselves
+                //
+                WaitForSingleObject(ovl.hEvent, INFINITE); // == WAIT_OBJECT_0);
+
+                if (!GetOverlappedResult(
+                         chunk->FromFileHandle.FileHandle,
+                         &ovl,
+                         &bytesRead,
+                         TRUE))
+                {
+                    dwErr = GetLastError();
+
+                    switch(dwErr)
+                    {
+                    case ERROR_HANDLE_EOF:
+                        was_eof = 1;
+                        break;
+
+                    default:
+                        hr = HRESULT_FROM_WIN32(dwErr);
+                        goto Done;
+                    }
+                }
+                break;
+
+            case ERROR_HANDLE_EOF:
+                was_eof = 1;
+                break;
+
+            default:
+                hr = HRESULT_FROM_WIN32(dwErr);
+                goto Done;
+            }
+        }
+
+        bytesRead -= dwDataStartOffset;
+
+        if (bytesRead > chunk->FromFileHandle.ByteRange.Length.QuadPart)
+        {
+            bytesRead = (DWORD)chunk->FromFileHandle.ByteRange.Length.QuadPart;
+        }
+        if ((bytesTotal + bytesRead) > chunk->FromFileHandle.ByteRange.Length.QuadPart)
+        { 
+            bytesRead = chunk->FromFileHandle.ByteRange.Length.QuadPart - bytesTotal; 
+        }
+
+        memcpy(buf, pIoBuffer + dwDataStartOffset, bytesRead);
+
+        buf += bytesRead;
+        bytesTotal += bytesRead;
+
+        if(was_eof != 0)
+            chunk->FromFileHandle.ByteRange.Length.QuadPart = bytesTotal;
+    }
 
 Done:
-	if(NULL != pIoBuffer)
-	{
-		VirtualFree(pIoBuffer, 0, MEM_RELEASE);
-	}
+    if(NULL != pIoBuffer)
+    {
+        VirtualFree(pIoBuffer, 0, MEM_RELEASE);
+    }
 
-	if(INVALID_HANDLE_VALUE != hIoEvent)
-	{
-		CloseHandle(hIoEvent);
-	}
+    if(INVALID_HANDLE_VALUE != hIoEvent)
+    {
+        CloseHandle(hIoEvent);
+    }
 
-	return hr;
+    return hr;
 }
 
 /*
@@ -616,45 +616,45 @@ CMyHttpModule::OnSendResponse(
     }
 
     HRESULT hr = S_OK;
-	IHttpResponse *pHttpResponse = NULL;
+    IHttpResponse *pHttpResponse = NULL;
     HTTP_RESPONSE *pRawHttpResponse = NULL;
     HTTP_BYTE_RANGE *pFileByteRange = NULL;
     HTTP_DATA_CHUNK *pSourceDataChunk = NULL;
     LARGE_INTEGER  lFileSize;
     REQUEST_NOTIFICATION_STATUS ret = RQ_NOTIFICATION_CONTINUE;
-	ULONGLONG ulTotalLength = 0;
-	DWORD c;
+    ULONGLONG ulTotalLength = 0;
+    DWORD c;
     request_rec *r = rsc->requestRec.get();
 
-	pHttpResponse = pHttpContext->GetResponse();
-	pRawHttpResponse = pHttpResponse->GetRawHttpResponse();
+    pHttpResponse = pHttpContext->GetResponse();
+    pRawHttpResponse = pHttpResponse->GetRawHttpResponse();
 
-	// here we must add handling of chunked response
-	// apparently IIS 7 calls this handler once per chunk
-	// see: http://stackoverflow.com/questions/4385249/how-to-buffer-and-process-chunked-data-before-sending-headers-in-iis7-native-mod
+    // here we must add handling of chunked response
+    // apparently IIS 7 calls this handler once per chunk
+    // see: http://stackoverflow.com/questions/4385249/how-to-buffer-and-process-chunked-data-before-sending-headers-in-iis7-native-mod
 
-	if(pRawHttpResponse->EntityChunkCount == 0)
-		goto Exit;
+    if(pRawHttpResponse->EntityChunkCount == 0)
+        goto Exit;
 
-	// here we must transfer response headers
-	//
-	USHORT ctcch = 0;
-	char *ct = (char *)pHttpResponse->GetHeader(HttpHeaderContentType, &ctcch);
-	char *ctz = ZeroTerminate(ct, ctcch, r->pool);
+    // here we must transfer response headers
+    //
+    USHORT ctcch = 0;
+    char *ct = (char *)pHttpResponse->GetHeader(HttpHeaderContentType, &ctcch);
+    char *ctz = ZeroTerminate(ct, ctcch, r->pool);
 
-	// assume HTML if content type not set
-	// without this output filter would not buffer response and processing would hang
-	//
-	if(ctz[0] == 0)
-		ctz = "text/html";
+    // assume HTML if content type not set
+    // without this output filter would not buffer response and processing would hang
+    //
+    if(ctz[0] == 0)
+        ctz = "text/html";
 
-	r->content_type = ctz;
+    r->content_type = ctz;
 
 #define _TRANSHEADER(id,str) if(pRawHttpResponse->Headers.KnownHeaders[id].pRawValue != NULL) \
-	{\
-		apr_table_setn(r->headers_out, str, \
-			ZeroTerminate(pRawHttpResponse->Headers.KnownHeaders[id].pRawValue, pRawHttpResponse->Headers.KnownHeaders[id].RawValueLength, r->pool)); \
-	}
+    {\
+        apr_table_setn(r->headers_out, str, \
+            ZeroTerminate(pRawHttpResponse->Headers.KnownHeaders[id].pRawValue, pRawHttpResponse->Headers.KnownHeaders[id].RawValueLength, r->pool)); \
+    }
 
     _TRANSHEADER(HttpHeaderCacheControl, "Cache-Control");
     _TRANSHEADER(HttpHeaderConnection, "Connection");
@@ -676,7 +676,7 @@ CMyHttpModule::OnSendResponse(
     _TRANSHEADER(HttpHeaderContentRange, "Content-Range");          
     _TRANSHEADER(HttpHeaderExpires, "Expires");               
     _TRANSHEADER(HttpHeaderLastModified, "Last-Modified");          
-	_TRANSHEADER(HttpHeaderAcceptRanges, "Accept-Ranges");
+    _TRANSHEADER(HttpHeaderAcceptRanges, "Accept-Ranges");
     _TRANSHEADER(HttpHeaderAge, "Age");                   
     _TRANSHEADER(HttpHeaderEtag, "Etag");                  
     _TRANSHEADER(HttpHeaderLocation, "Location");              
@@ -687,29 +687,29 @@ CMyHttpModule::OnSendResponse(
     _TRANSHEADER(HttpHeaderVary, "Vary");                  
     _TRANSHEADER(HttpHeaderWwwAuthenticate, "Www-Authenticate");
 
-#undef	_TRANSHEADER
+#undef    _TRANSHEADER
 
-	for(int i = 0; i < pRawHttpResponse->Headers.UnknownHeaderCount; i++)
-	{
-		apr_table_setn(r->headers_out, 
-			ZeroTerminate(pRawHttpResponse->Headers.pUnknownHeaders[i].pName, pRawHttpResponse->Headers.pUnknownHeaders[i].NameLength, r->pool), 
-			ZeroTerminate(pRawHttpResponse->Headers.pUnknownHeaders[i].pRawValue, pRawHttpResponse->Headers.pUnknownHeaders[i].RawValueLength, r->pool));
-	}
+    for(int i = 0; i < pRawHttpResponse->Headers.UnknownHeaderCount; i++)
+    {
+        apr_table_setn(r->headers_out, 
+            ZeroTerminate(pRawHttpResponse->Headers.pUnknownHeaders[i].pName, pRawHttpResponse->Headers.pUnknownHeaders[i].NameLength, r->pool), 
+            ZeroTerminate(pRawHttpResponse->Headers.pUnknownHeaders[i].pRawValue, pRawHttpResponse->Headers.pUnknownHeaders[i].RawValueLength, r->pool));
+    }
 
-	r->content_encoding = apr_table_get(r->headers_out, "Content-Encoding");
-	//r->content_type = apr_table_get(r->headers_out, "Content-Type");		-- already set above
+    r->content_encoding = apr_table_get(r->headers_out, "Content-Encoding");
+    //r->content_type = apr_table_get(r->headers_out, "Content-Type");        -- already set above
 
-	const char *lng = apr_table_get(r->headers_out, "Content-Languages");
+    const char *lng = apr_table_get(r->headers_out, "Content-Languages");
 
-	if(lng != NULL)
-	{
-		r->content_languages = apr_array_make(r->pool, 1, sizeof(const char *));
+    if(lng != NULL)
+    {
+        r->content_languages = apr_array_make(r->pool, 1, sizeof(const char *));
 
-		*(const char **)apr_array_push(r->content_languages) = lng;
-	}
+        *(const char **)apr_array_push(r->content_languages) = lng;
+    }
 
-	// Disable kernel caching for this response
-	// Probably we don't have to do it for ModSecurity
+    // Disable kernel caching for this response
+    // Probably we don't have to do it for ModSecurity
 
     //pHttpContext->GetResponse()->DisableKernelCache(
     //        IISCacheEvents::HTTPSYS_CACHEABLE::HANDLER_HTTPSYS_UNFRIENDLY);
@@ -766,9 +766,9 @@ CMyHttpModule::OnSendResponse(
         }
     }
 
-	rsc->responseBuffer = (char *)apr_palloc(rsc->requestRec->pool, ulTotalLength);
+    rsc->responseBuffer = (char *)apr_palloc(rsc->requestRec->pool, ulTotalLength);
 
-	ulTotalLength = 0;
+    ulTotalLength = 0;
 
     for(c = 0; c < pRawHttpResponse->EntityChunkCount; c++ )
     {
@@ -777,19 +777,19 @@ CMyHttpModule::OnSendResponse(
         switch( pSourceDataChunk->DataChunkType )
         {
             case HttpDataChunkFromMemory:
-				memcpy(rsc->responseBuffer + ulTotalLength, pSourceDataChunk->FromMemory.pBuffer, pSourceDataChunk->FromMemory.BufferLength);
+                memcpy(rsc->responseBuffer + ulTotalLength, pSourceDataChunk->FromMemory.pBuffer, pSourceDataChunk->FromMemory.BufferLength);
                 ulTotalLength += pSourceDataChunk->FromMemory.BufferLength;
                 break;
             case HttpDataChunkFromFileHandle:
                 pFileByteRange = &pSourceDataChunk->FromFileHandle.ByteRange;
 
-				if(ReadFileChunk(pSourceDataChunk, rsc->responseBuffer + ulTotalLength) != S_OK)
-				{
-			        DWORD dwErr = GetLastError();
+                if(ReadFileChunk(pSourceDataChunk, rsc->responseBuffer + ulTotalLength) != S_OK)
+                {
+                    DWORD dwErr = GetLastError();
 
-					hr = HRESULT_FROM_WIN32(dwErr);
-	                goto Finished;
-				}
+                    hr = HRESULT_FROM_WIN32(dwErr);
+                    goto Finished;
+                }
 
                 ulTotalLength += pFileByteRange->Length.QuadPart;
                 break;
@@ -801,16 +801,16 @@ CMyHttpModule::OnSendResponse(
         }
     }
 
-	rsc->responseLength = ulTotalLength;
+    rsc->responseLength = ulTotalLength;
 
-	//
+    //
     // If there's no content-length set, we need to set it to avoid chunked transfer mode
     // We can only do it if there is it's the only response to be sent.
     //
 
     DWORD dwFlags = pResponseProvider->GetFlags();
 
-	if (pResponseProvider->GetHeadersBeingSent() && 
+    if (pResponseProvider->GetHeadersBeingSent() && 
          (dwFlags & HTTP_SEND_RESPONSE_FLAG_MORE_DATA) == 0 &&
          pHttpContext->GetResponse()->GetHeader(HttpHeaderContentLength) == NULL)    
     {
@@ -842,27 +842,27 @@ CMyHttpModule::OnSendResponse(
 
 Finished:
 
-	int status = modsecProcessResponse(r);
+    int status = modsecProcessResponse(r);
 
-	// the logic here is temporary, needs clarification
-	//
-	if(status != 0 && status != -1)
-	{
-		pHttpContext->GetResponse()->Clear();
-		pHttpContext->GetResponse()->SetStatus(status, "ModSecurity Action");
-		pHttpContext->SetRequestHandled();
+    // the logic here is temporary, needs clarification
+    //
+    if(status != 0 && status != -1)
+    {
+        pHttpContext->GetResponse()->Clear();
+        pHttpContext->GetResponse()->SetStatus(status, "ModSecurity Action");
+        pHttpContext->SetRequestHandled();
 
-		rsc->FinishRequest();
-		
-		return RQ_NOTIFICATION_FINISH_REQUEST;
-	}
+        rsc->FinishRequest();
+        
+        return RQ_NOTIFICATION_FINISH_REQUEST;
+    }
 Exit:
-	// temporary hack, in reality OnSendRequest theoretically could possibly come before OnEndRequest
-	//
-	if(rsc != NULL)
-		rsc->FinishRequest();
-		
-	return RQ_NOTIFICATION_CONTINUE;
+    // temporary hack, in reality OnSendRequest theoretically could possibly come before OnEndRequest
+    //
+    if(rsc != NULL)
+        rsc->FinishRequest();
+        
+    return RQ_NOTIFICATION_CONTINUE;
 }
 
 REQUEST_NOTIFICATION_STATUS
@@ -871,17 +871,17 @@ CMyHttpModule::OnPostEndRequest(
     IN IHttpEventProvider * pProvider
 )
 {
-	RequestStoredContext* rsc = dynamic_cast<RequestStoredContext*>(pHttpContext->GetModuleContextContainer()->GetModuleContext(g_pModuleContext));
+    RequestStoredContext* rsc = dynamic_cast<RequestStoredContext*>(pHttpContext->GetModuleContextContainer()->GetModuleContext(g_pModuleContext));
 
-	// only finish request if OnSendResponse have been called already
-	//
-	if(rsc != nullptr && rsc->responseBuffer != nullptr)
+    // only finish request if OnSendResponse have been called already
+    //
+    if(rsc != nullptr && rsc->responseBuffer != nullptr)
     {
         CriticalSectionLock lock{cs};
-		rsc->FinishRequest();
-	}
+        rsc->FinishRequest();
+    }
 
-	return RQ_NOTIFICATION_CONTINUE;
+    return RQ_NOTIFICATION_CONTINUE;
 }
 
 REQUEST_NOTIFICATION_STATUS
@@ -988,45 +988,45 @@ CMyHttpModule::OnBeginRequest(IHttpContext* httpContext, IHttpEventProvider* pro
 
     httpContext->GetModuleContextContainer()->SetModuleContext(rsc.release(), g_pModuleContext);
 
-	HTTP_REQUEST *req = httpContext->GetRequest()->GetRawHttpRequest();
+    HTTP_REQUEST *req = httpContext->GetRequest()->GetRawHttpRequest();
 
-	r->hostname = ConvertUTF16ToUTF8(req->CookedUrl.pHost, req->CookedUrl.HostLength / sizeof(WCHAR), r->pool);
-	r->path_info = ConvertUTF16ToUTF8(req->CookedUrl.pAbsPath, req->CookedUrl.AbsPathLength / sizeof(WCHAR), r->pool);
+    r->hostname = ConvertUTF16ToUTF8(req->CookedUrl.pHost, req->CookedUrl.HostLength / sizeof(WCHAR), r->pool);
+    r->path_info = ConvertUTF16ToUTF8(req->CookedUrl.pAbsPath, req->CookedUrl.AbsPathLength / sizeof(WCHAR), r->pool);
 
-	if(r->hostname == NULL)
-	{
-		if(req->Headers.KnownHeaders[HttpHeaderHost].pRawValue != NULL)
-			r->hostname = ZeroTerminate(req->Headers.KnownHeaders[HttpHeaderHost].pRawValue,
-										req->Headers.KnownHeaders[HttpHeaderHost].RawValueLength, r->pool);
-	}
+    if(r->hostname == NULL)
+    {
+        if(req->Headers.KnownHeaders[HttpHeaderHost].pRawValue != NULL)
+            r->hostname = ZeroTerminate(req->Headers.KnownHeaders[HttpHeaderHost].pRawValue,
+                                        req->Headers.KnownHeaders[HttpHeaderHost].RawValueLength, r->pool);
+    }
 
-	int port = 0;
-	char *port_str = NULL;
+    int port = 0;
+    char *port_str = NULL;
 
-	if(r->hostname != NULL)
-	{
-		int k = 0;
-		char *ptr = (char *)r->hostname;
+    if(r->hostname != NULL)
+    {
+        int k = 0;
+        char *ptr = (char *)r->hostname;
 
-		while(*ptr != 0 && *ptr != ':')
-			ptr++;
+        while(*ptr != 0 && *ptr != ':')
+            ptr++;
 
-		if(*ptr == ':')
-		{
-			*ptr = 0;
-			port_str = ptr + 1;
-			port = atoi(port_str);
-		}
-	}
+        if(*ptr == ':')
+        {
+            *ptr = 0;
+            port_str = ptr + 1;
+            port = atoi(port_str);
+        }
+    }
 
-	if(req->CookedUrl.pQueryString != NULL && req->CookedUrl.QueryStringLength > 0)
-		r->args = ConvertUTF16ToUTF8(req->CookedUrl.pQueryString + 1, (req->CookedUrl.QueryStringLength / sizeof(WCHAR)) - 1, r->pool);
+    if(req->CookedUrl.pQueryString != NULL && req->CookedUrl.QueryStringLength > 0)
+        r->args = ConvertUTF16ToUTF8(req->CookedUrl.pQueryString + 1, (req->CookedUrl.QueryStringLength / sizeof(WCHAR)) - 1, r->pool);
 
 #define _TRANSHEADER(id,str) if(req->Headers.KnownHeaders[id].pRawValue != NULL) \
-	{\
-		apr_table_setn(r->headers_in, str, \
-			ZeroTerminate(req->Headers.KnownHeaders[id].pRawValue, req->Headers.KnownHeaders[id].RawValueLength, r->pool)); \
-	}
+    {\
+        apr_table_setn(r->headers_in, str, \
+            ZeroTerminate(req->Headers.KnownHeaders[id].pRawValue, req->Headers.KnownHeaders[id].RawValueLength, r->pool)); \
+    }
 
     _TRANSHEADER(HttpHeaderCacheControl, "Cache-Control");
     _TRANSHEADER(HttpHeaderConnection, "Connection");
@@ -1072,136 +1072,136 @@ CMyHttpModule::OnBeginRequest(IHttpContext* httpContext, IHttpEventProvider* pro
 
 #undef _TRANSHEADER
 
-	for(int i = 0; i < req->Headers.UnknownHeaderCount; i++)
-	{
-		apr_table_setn(r->headers_in, 
-			ZeroTerminate(req->Headers.pUnknownHeaders[i].pName, req->Headers.pUnknownHeaders[i].NameLength, r->pool), 
-			ZeroTerminate(req->Headers.pUnknownHeaders[i].pRawValue, req->Headers.pUnknownHeaders[i].RawValueLength, r->pool));
-	}
+    for(int i = 0; i < req->Headers.UnknownHeaderCount; i++)
+    {
+        apr_table_setn(r->headers_in, 
+            ZeroTerminate(req->Headers.pUnknownHeaders[i].pName, req->Headers.pUnknownHeaders[i].NameLength, r->pool), 
+            ZeroTerminate(req->Headers.pUnknownHeaders[i].pRawValue, req->Headers.pUnknownHeaders[i].RawValueLength, r->pool));
+    }
 
-	r->content_encoding = apr_table_get(r->headers_in, "Content-Encoding");
-	r->content_type = apr_table_get(r->headers_in, "Content-Type");
+    r->content_encoding = apr_table_get(r->headers_in, "Content-Encoding");
+    r->content_type = apr_table_get(r->headers_in, "Content-Type");
 
-	const char *lng = apr_table_get(r->headers_in, "Content-Languages");
+    const char *lng = apr_table_get(r->headers_in, "Content-Languages");
 
-	if(lng != NULL)
-	{
-		r->content_languages = apr_array_make(r->pool, 1, sizeof(const char *));
+    if(lng != NULL)
+    {
+        r->content_languages = apr_array_make(r->pool, 1, sizeof(const char *));
 
-		*(const char **)apr_array_push(r->content_languages) = lng;
-	}
+        *(const char **)apr_array_push(r->content_languages) = lng;
+    }
 
-	switch(req->Verb)
-	{
-	case HttpVerbUnparsed:
-	case HttpVerbUnknown:
-	case HttpVerbInvalid:
+    switch(req->Verb)
+    {
+    case HttpVerbUnparsed:
+    case HttpVerbUnknown:
+    case HttpVerbInvalid:
     case HttpVerbTRACK:  // used by Microsoft Cluster Server for a non-logged trace
     case HttpVerbSEARCH:
-	default:
-		r->method = "INVALID";
-		r->method_number = M_INVALID;
-		break;
-	case HttpVerbOPTIONS:
-		r->method = "OPTIONS";
-		r->method_number = M_OPTIONS;
-		break;
-	case HttpVerbGET:
-	case HttpVerbHEAD:
-		r->method = "GET";
-		r->method_number = M_GET;
-		break;
-	case HttpVerbPOST:
-		r->method = "POST";
-		r->method_number = M_POST;
-		break;
+    default:
+        r->method = "INVALID";
+        r->method_number = M_INVALID;
+        break;
+    case HttpVerbOPTIONS:
+        r->method = "OPTIONS";
+        r->method_number = M_OPTIONS;
+        break;
+    case HttpVerbGET:
+    case HttpVerbHEAD:
+        r->method = "GET";
+        r->method_number = M_GET;
+        break;
+    case HttpVerbPOST:
+        r->method = "POST";
+        r->method_number = M_POST;
+        break;
     case HttpVerbPUT:
-		r->method = "PUT";
-		r->method_number = M_PUT;
-		break;
+        r->method = "PUT";
+        r->method_number = M_PUT;
+        break;
     case HttpVerbDELETE:
-		r->method = "DELETE";
-		r->method_number = M_DELETE;
-		break;
+        r->method = "DELETE";
+        r->method_number = M_DELETE;
+        break;
     case HttpVerbTRACE:
-		r->method = "TRACE";
-		r->method_number = M_TRACE;
-		break;
+        r->method = "TRACE";
+        r->method_number = M_TRACE;
+        break;
     case HttpVerbCONNECT:
-		r->method = "CONNECT";
-		r->method_number = M_CONNECT;
-		break;
+        r->method = "CONNECT";
+        r->method_number = M_CONNECT;
+        break;
     case HttpVerbMOVE:
-		r->method = "MOVE";
-		r->method_number = M_MOVE;
-		break;
+        r->method = "MOVE";
+        r->method_number = M_MOVE;
+        break;
     case HttpVerbCOPY:
-		r->method = "COPY";
-		r->method_number = M_COPY;
-		break;
+        r->method = "COPY";
+        r->method_number = M_COPY;
+        break;
     case HttpVerbPROPFIND:
-		r->method = "PROPFIND";
-		r->method_number = M_PROPFIND;
-		break;
+        r->method = "PROPFIND";
+        r->method_number = M_PROPFIND;
+        break;
     case HttpVerbPROPPATCH:
-		r->method = "PROPPATCH";
-		r->method_number = M_PROPPATCH;
-		break;
+        r->method = "PROPPATCH";
+        r->method_number = M_PROPPATCH;
+        break;
     case HttpVerbMKCOL:
-		r->method = "MKCOL";
-		r->method_number = M_MKCOL;
-		break;
+        r->method = "MKCOL";
+        r->method_number = M_MKCOL;
+        break;
     case HttpVerbLOCK:
-		r->method = "LOCK";
-		r->method_number = M_LOCK;
-		break;
+        r->method = "LOCK";
+        r->method_number = M_LOCK;
+        break;
     case HttpVerbUNLOCK:
-		r->method = "UNLOCK";
-		r->method_number = M_UNLOCK;
-		break;
-	}
+        r->method = "UNLOCK";
+        r->method_number = M_UNLOCK;
+        break;
+    }
 
-	if(HTTP_EQUAL_VERSION(req->Version, 0, 9))
-		r->protocol = "HTTP/0.9";
-	else if(HTTP_EQUAL_VERSION(req->Version, 1, 0))
-		r->protocol = "HTTP/1.0";
-	else
-		r->protocol = "HTTP/1.1";
+    if(HTTP_EQUAL_VERSION(req->Version, 0, 9))
+        r->protocol = "HTTP/0.9";
+    else if(HTTP_EQUAL_VERSION(req->Version, 1, 0))
+        r->protocol = "HTTP/1.0";
+    else
+        r->protocol = "HTTP/1.1";
 
-	r->request_time = apr_time_now();
+    r->request_time = apr_time_now();
 
-	r->parsed_uri.scheme = "http";
-	r->parsed_uri.path = r->path_info;
-	r->parsed_uri.hostname = (char *)r->hostname;
-	r->parsed_uri.is_initialized = 1;
-	r->parsed_uri.port = port;
-	r->parsed_uri.port_str = port_str;
-	r->parsed_uri.query = r->args;
-	r->parsed_uri.dns_looked_up = 0;
-	r->parsed_uri.dns_resolved = 0;
-	r->parsed_uri.password = NULL;
-	r->parsed_uri.user = NULL;
-	r->parsed_uri.fragment = NULL;
+    r->parsed_uri.scheme = "http";
+    r->parsed_uri.path = r->path_info;
+    r->parsed_uri.hostname = (char *)r->hostname;
+    r->parsed_uri.is_initialized = 1;
+    r->parsed_uri.port = port;
+    r->parsed_uri.port_str = port_str;
+    r->parsed_uri.query = r->args;
+    r->parsed_uri.dns_looked_up = 0;
+    r->parsed_uri.dns_resolved = 0;
+    r->parsed_uri.password = NULL;
+    r->parsed_uri.user = NULL;
+    r->parsed_uri.fragment = NULL;
 
-	r->unparsed_uri = ZeroTerminate(req->pRawUrl, req->RawUrlLength, r->pool);
-	r->uri = r->unparsed_uri;
+    r->unparsed_uri = ZeroTerminate(req->pRawUrl, req->RawUrlLength, r->pool);
+    r->uri = r->unparsed_uri;
 
-	r->the_request = (char *)apr_palloc(r->pool, strlen(r->method) + 1 + req->RawUrlLength + 1 + strlen(r->protocol) + 1);
+    r->the_request = (char *)apr_palloc(r->pool, strlen(r->method) + 1 + req->RawUrlLength + 1 + strlen(r->protocol) + 1);
 
-	strcpy(r->the_request, r->method);
-	strcat(r->the_request, " ");
-	strcat(r->the_request, r->uri);
-	strcat(r->the_request, " ");
-	strcat(r->the_request, r->protocol);
+    strcpy(r->the_request, r->method);
+    strcat(r->the_request, " ");
+    strcat(r->the_request, r->uri);
+    strcat(r->the_request, " ");
+    strcat(r->the_request, r->protocol);
 
-	HTTP_REQUEST_ID httpRequestID;
-	char *pszValue = (char *)apr_palloc(r->pool, 24);
+    HTTP_REQUEST_ID httpRequestID;
+    char *pszValue = (char *)apr_palloc(r->pool, 24);
 
-	httpRequestID = httpContext->GetRequest()->GetRawHttpRequest()->RequestId;
+    httpRequestID = httpContext->GetRequest()->GetRawHttpRequest()->RequestId;
 
-	_ui64toa(httpRequestID, pszValue, 10);
+    _ui64toa(httpRequestID, pszValue, 10);
 
-	apr_table_setn(r->subprocess_env, "UNIQUE_ID", pszValue);
+    apr_table_setn(r->subprocess_env, "UNIQUE_ID", pszValue);
 
     PSOCKADDR pAddr = httpContext->GetRequest()->GetRemoteAddress();
 
@@ -1210,9 +1210,9 @@ CMyHttpModule::OnBeginRequest(IHttpContext* httpContext, IHttpEventProvider* pro
     c->remote_ip = GetIpAddr(r->pool, pAddr);
 #else
     c->client_addr = CopySockAddr(r->pool, pAddr);
-	c->client_ip = GetIpAddr(r->pool, pAddr);
+    c->client_ip = GetIpAddr(r->pool, pAddr);
 #endif
-	c->remote_host = NULL;
+    c->remote_host = NULL;
 
     if (config->config->is_enabled == MODSEC_DETECTION_ONLY)
     {
@@ -1247,60 +1247,60 @@ CMyHttpModule::OnBeginRequest(IHttpContext* httpContext, IHttpEventProvider* pro
         }
     }
 
-	return RQ_NOTIFICATION_CONTINUE;
+    return RQ_NOTIFICATION_CONTINUE;
 }
 
 apr_status_t ReadResponseCallback(request_rec *r, char *buf, unsigned int length, unsigned int *readcnt, int *is_eos)
 {
-	RequestStoredContext* rsc = RetrieveIISContext(r);
+    RequestStoredContext* rsc = RetrieveIISContext(r);
 
-	*readcnt = 0;
+    *readcnt = 0;
 
-	if(rsc == nullptr || rsc->responseBuffer == nullptr)
-	{
-		*is_eos = 1;
-		return APR_SUCCESS;
-	}
+    if(rsc == nullptr || rsc->responseBuffer == nullptr)
+    {
+        *is_eos = 1;
+        return APR_SUCCESS;
+    }
 
-	unsigned int size = length;
+    unsigned int size = length;
 
-	if(size > rsc->responseLength - rsc->responsePosition)
-		size = rsc->responseLength - rsc->responsePosition;
+    if(size > rsc->responseLength - rsc->responsePosition)
+        size = rsc->responseLength - rsc->responsePosition;
 
-	memcpy(buf, rsc->responseBuffer + rsc->responsePosition, size);
+    memcpy(buf, rsc->responseBuffer + rsc->responsePosition, size);
 
-	*readcnt = size;
-	rsc->responsePosition += size;
+    *readcnt = size;
+    rsc->responsePosition += size;
 
-	if(rsc->responsePosition >= rsc->responseLength)
-		*is_eos = 1;
+    if(rsc->responsePosition >= rsc->responseLength)
+        *is_eos = 1;
 
-	return APR_SUCCESS;
+    return APR_SUCCESS;
 }
 
 apr_status_t WriteResponseCallback(request_rec *r, char *buf, unsigned int length)
 {
-	RequestStoredContext* rsc = RetrieveIISContext(r);
+    RequestStoredContext* rsc = RetrieveIISContext(r);
 
-	if(!rsc || !rsc->requestRec || rsc->responseBuffer == nullptr)
-		return APR_SUCCESS;
+    if(!rsc || !rsc->requestRec || rsc->responseBuffer == nullptr)
+        return APR_SUCCESS;
 
-	IHttpContext *pHttpContext = rsc->httpContext;
-	IHttpResponse *pHttpResponse = pHttpContext->GetResponse();
-	HTTP_RESPONSE *pRawHttpResponse = pHttpResponse->GetRawHttpResponse();
-	HTTP_DATA_CHUNK *pDataChunk = (HTTP_DATA_CHUNK *)apr_palloc(rsc->requestRec->pool, sizeof(HTTP_DATA_CHUNK));
+    IHttpContext *pHttpContext = rsc->httpContext;
+    IHttpResponse *pHttpResponse = pHttpContext->GetResponse();
+    HTTP_RESPONSE *pRawHttpResponse = pHttpResponse->GetRawHttpResponse();
+    HTTP_DATA_CHUNK *pDataChunk = (HTTP_DATA_CHUNK *)apr_palloc(rsc->requestRec->pool, sizeof(HTTP_DATA_CHUNK));
 
-	pRawHttpResponse->EntityChunkCount = 0;
+    pRawHttpResponse->EntityChunkCount = 0;
 
-	// since we clean the APR pool at the end of OnSendRequest, we must get IIS-managed memory chunk
-	//
-	void *reqbuf = pHttpContext->AllocateRequestMemory(length);
+    // since we clean the APR pool at the end of OnSendRequest, we must get IIS-managed memory chunk
+    //
+    void *reqbuf = pHttpContext->AllocateRequestMemory(length);
 
-	memcpy(reqbuf, buf, length);
+    memcpy(reqbuf, buf, length);
 
-	pDataChunk->DataChunkType = HttpDataChunkFromMemory;
-	pDataChunk->FromMemory.pBuffer = reqbuf;
-	pDataChunk->FromMemory.BufferLength = length;
+    pDataChunk->DataChunkType = HttpDataChunkFromMemory;
+    pDataChunk->FromMemory.pBuffer = reqbuf;
+    pDataChunk->FromMemory.BufferLength = length;
 
     CHAR szLength[21]; //Max length for a 64 bit int is 20
 
@@ -1313,7 +1313,7 @@ apr_status_t WriteResponseCallback(request_rec *r, char *buf, unsigned int lengt
 
     if(FAILED(hr))
     {
-		// not possible
+        // not possible
     }
 
     hr = pHttpResponse->SetHeader(
@@ -1324,12 +1324,12 @@ apr_status_t WriteResponseCallback(request_rec *r, char *buf, unsigned int lengt
 
     if(FAILED(hr))
     {
-		// possible, but there's nothing we can do
+        // possible, but there's nothing we can do
     }
 
-	pHttpResponse->WriteEntityChunkByReference(pDataChunk);
+    pHttpResponse->WriteEntityChunkByReference(pDataChunk);
 
-	return APR_SUCCESS;
+    return APR_SUCCESS;
 }
 
 CMyHttpModule::CMyHttpModule()
diff --git a/iis/mymodule.def b/iis/mymodule.def
index cb37d10b0a..2bd6d14cdb 100644
--- a/iis/mymodule.def
+++ b/iis/mymodule.def
@@ -1,4 +1,4 @@
-LIBRARY	"ModSecurityIIS"
+LIBRARY    "ModSecurityIIS"
 
 EXPORTS
     RegisterModule
diff --git a/iis/mymodulefactory.h b/iis/mymodulefactory.h
index 1127f0048b..d8c63528e1 100644
--- a/iis/mymodulefactory.h
+++ b/iis/mymodulefactory.h
@@ -27,7 +27,7 @@ class CMyHttpModuleFactory : public IHttpModuleFactory
 
     HRESULT GetHttpModule(CHttpModule** ppModule, IModuleAllocator*) override
     {
-	    if (ppModule == nullptr)
+        if (ppModule == nullptr)
         {
             return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
         }
diff --git a/mlogc/mlogc.c b/mlogc/mlogc.c
index e650452dc4..400f6ec51a 100644
--- a/mlogc/mlogc.c
+++ b/mlogc/mlogc.c
@@ -815,20 +815,20 @@ static void init_configuration(void)
     /* TLS Protocol - TLSv1(0) TLSv1.1(1) TLSv1.2(2) (SSLv3 not supported) */
     s = apr_table_get(conf, "TLSProtocol");
     if (s != NULL) {
-    	int num = atoi(s);
-    	switch (num) {
-    	case 0:
-    		tlsprotocol = 0;
-    		break;
-    	case 1:
-    		tlsprotocol = 1;
-    		break;
-    	case 2:
-    		tlsprotocol = 2;
-    		break;
-    	default:
-    		tlsprotocol = 2; /* Default is TLSv1.2 */
-    	}
+        int num = atoi(s);
+        switch (num) {
+        case 0:
+            tlsprotocol = 0;
+            break;
+        case 1:
+            tlsprotocol = 1;
+            break;
+        case 2:
+            tlsprotocol = 2;
+            break;
+        default:
+            tlsprotocol = 2; /* Default is TLSv1.2 */
+        }
     }
     curlversion = curl_version_info(CURLVERSION_NOW);
 
@@ -1278,24 +1278,24 @@ static void logc_init(void)
          */
         switch (tlsprotocol) {
         case 0:
-        	curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_0);
-        	break;
+            curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_0);
+            break;
         case 1:
-        	curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_1);
-        	break;
+            curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_1);
+            break;
         case 2:
-        	curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2);
-        	break;
+            curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2);
+            break;
         default:
-        	curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2);
-        	break;
+            curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2);
+            break;
         }
         cmaj = curlversion->version_num >> 16;
         cmin = (curlversion->version_num & 0x00ff00) >> 8;
         cpat = (curlversion->version_num & 0x0000ff);
         /* If cURL version < v7.34.0, use TLS v1.x */
         if (cmaj <= 7 && cmin < 34) {
-        	curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1);
+            curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1);
         }
 
         curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 15);
@@ -1308,7 +1308,7 @@ static void logc_init(void)
     }
 
     if (cmaj <= 7 && cmin < 34) {
-    	error_log(LOG_DEBUG2, NULL, "TLSv1.2 is unsupported in cURL %d.%d.%d",  cmaj, cmin, cpat);
+        error_log(LOG_DEBUG2, NULL, "TLSv1.2 is unsupported in cURL %d.%d.%d",  cmaj, cmin, cpat);
     }
 
     logline_regex = pcre_compile(logline_pattern, PCRE_CASELESS,
@@ -2322,12 +2322,12 @@ int main(int argc, const char * const argv[]) {
     logc_pid = getpid();
     apr_pool_create(&pool, NULL);
     apr_pool_create(&recv_pool, NULL);
-	
+    
 #ifndef WIN32
     apr_setup_signal_thread();
 #else
-	apr_signal(SIGINT, handle_signals);
-	apr_signal(SIGTERM, handle_signals);
+    apr_signal(SIGINT, handle_signals);
+    apr_signal(SIGTERM, handle_signals);
 #endif /* WIN32 */
 
     if (argc < 2) {
diff --git a/standalone/api.c b/standalone/api.c
index 389ffb5aba..355fdc6d3d 100755
--- a/standalone/api.c
+++ b/standalone/api.c
@@ -270,43 +270,43 @@ directory_config *modsecGetDefaultConfig()  {
 const char *modsecProcessConfig(directory_config *config, const char *file, const char *dir)  {
     apr_pool_t *ptemp = NULL;
     const char *err;
-	apr_status_t status;
-	const char *rootpath, *incpath;
+    apr_status_t status;
+    const char *rootpath, *incpath;
 
-	if(dir == NULL || strlen(dir) == 0)
-#ifdef	WIN32
-		dir = "\\";
+    if(dir == NULL || strlen(dir) == 0)
+#ifdef    WIN32
+        dir = "\\";
 #else
-		dir = "/";
+        dir = "/";
 #endif
 
-	incpath = file;
+    incpath = file;
 
-	/* locate the start of the directories proper */
-	status = apr_filepath_root(&rootpath, &incpath, APR_FILEPATH_TRUENAME | APR_FILEPATH_NATIVE, config->mp);
+    /* locate the start of the directories proper */
+    status = apr_filepath_root(&rootpath, &incpath, APR_FILEPATH_TRUENAME | APR_FILEPATH_NATIVE, config->mp);
 
-	/* we allow APR_SUCCESS and APR_EINCOMPLETE */
-	if (APR_ERELATIVE == status) {
-		int li = strlen(dir) - 1;
+    /* we allow APR_SUCCESS and APR_EINCOMPLETE */
+    if (APR_ERELATIVE == status) {
+        int li = strlen(dir) - 1;
 
-		if(dir[li] != '/' && dir[li] != '\\')
-#ifdef	WIN32
-			file = apr_pstrcat(config->mp, dir, "\\", file, NULL);
+        if(dir[li] != '/' && dir[li] != '\\')
+#ifdef    WIN32
+            file = apr_pstrcat(config->mp, dir, "\\", file, NULL);
 #else
-			file = apr_pstrcat(config->mp, dir, "/", file, NULL);
+            file = apr_pstrcat(config->mp, dir, "/", file, NULL);
 #endif
-		else
-			file = apr_pstrcat(config->mp, dir, file, NULL);
-	}
-	else if (APR_EBADPATH == status) {
-		return apr_pstrcat(config->mp, "Config file has a bad path, ", file, NULL);
-	}
+        else
+            file = apr_pstrcat(config->mp, dir, file, NULL);
+    }
+    else if (APR_EBADPATH == status) {
+        return apr_pstrcat(config->mp, "Config file has a bad path, ", file, NULL);
+    }
 
-	apr_pool_create(&ptemp, config->mp);
+    apr_pool_create(&ptemp, config->mp);
 
     err = process_command_config(server, config, config->mp, ptemp, file);
 #ifdef MEMORY_DATABASE_ENABLE
-	config->root_config = config;
+    config->root_config = config;
 #endif
     apr_pool_destroy(ptemp);
 
@@ -471,9 +471,9 @@ int modsecProcessRequestBody(request_rec *r) {
 
     ap_remove_input_filter(f);
 
-	if (status != DECLINED) {
-		return status;
-	}
+    if (status != DECLINED) {
+        return status;
+    }
 
     hookfn_insert_filter(r);
 
diff --git a/standalone/api.h b/standalone/api.h
index 86e3c745a8..bcad5230db 100644
--- a/standalone/api.h
+++ b/standalone/api.h
@@ -44,7 +44,7 @@
 #define inline __inline
 #endif
 
-#ifdef	__cplusplus
+#ifdef    __cplusplus
 extern "C"
 {
 #endif
diff --git a/standalone/buckets.c b/standalone/buckets.c
index bf8d9d4959..76a628162e 100644
--- a/standalone/buckets.c
+++ b/standalone/buckets.c
@@ -50,7 +50,7 @@ AP_DECLARE(apr_status_t) ap_get_brigade(ap_filter_t *next,
                                                readbytes);
     }
 
-	return AP_NOBODY_READ;
+    return AP_NOBODY_READ;
 }
 
 AP_DECLARE(apr_status_t) ap_pass_brigade(ap_filter_t *next,
diff --git a/standalone/config.c b/standalone/config.c
index 191123fb83..6ffc6f8950 100644
--- a/standalone/config.c
+++ b/standalone/config.c
@@ -348,12 +348,12 @@ static int cfg_trim_line(char *buf)
 }
 
 AP_DECLARE(apr_status_t) ap_cfg_getline(char *buf, apr_size_t bufsize,
-		ap_configfile_t *cfp)
+        ap_configfile_t *cfp)
 {
-	apr_status_t rc = ap_cfg_getline_core(buf, bufsize, cfp);
-	if (rc == APR_SUCCESS)
-		cfg_trim_line(buf);
-	return rc;
+    apr_status_t rc = ap_cfg_getline_core(buf, bufsize, cfp);
+    if (rc == APR_SUCCESS)
+        cfg_trim_line(buf);
+    return rc;
 }
 #endif
 
@@ -765,7 +765,7 @@ int fnmatch_test(const char *pattern)
             if (*++pattern == '\0') {
                 return 0;
             }
-            break;*/		// this breaks on Windows
+            break;*/        // this breaks on Windows
 
         case '[':         /* '[' is only a glob if it has a matching ']' */
             ++nesting;
@@ -785,7 +785,7 @@ AP_DECLARE(const char *) process_resource_config(const char *fname,
                                                     apr_array_header_t *ari,
                                                     apr_pool_t *ptemp)
 {
-	*(char **)apr_array_push(ari) = (char *)fname;
+    *(char **)apr_array_push(ari) = (char *)fname;
 
     return NULL;
 }
@@ -794,7 +794,7 @@ static const char *process_resource_config_nofnmatch(const char *fname,
                                                      apr_array_header_t *ari,
                                                      apr_pool_t *p,
                                                      apr_pool_t *ptemp,
-													 unsigned depth,
+                                                     unsigned depth,
                                                      int optional)
 {
     const char *error;
@@ -882,10 +882,10 @@ static const char *process_resource_config_fnmatch(const char *path,
     /* find the first part of the filename */
     rest = ap_strchr_c(fname, '/');
 
-	if(rest == NULL)
-		rest = ap_strchr_c(fname, '\\');
+    if(rest == NULL)
+        rest = ap_strchr_c(fname, '\\');
 
-	if (rest) {
+    if (rest) {
         fname = apr_pstrndup(ptemp, fname, rest - fname);
         rest++;
     }
@@ -1007,198 +1007,198 @@ AP_DECLARE(const char *) process_fnmatch_configs(apr_array_header_t *ari,
 
 const char *populate_include_files(apr_pool_t *p, apr_pool_t *ptemp, apr_array_header_t *ari, const char *fname, int optional)
 {
-	return process_fnmatch_configs(ari, fname, p, ptemp, optional);
+    return process_fnmatch_configs(ari, fname, p, ptemp, optional);
 }
 
 const char *process_command_config(server_rec *s,
                                           void *mconfig,
                                           apr_pool_t *p,
                                           apr_pool_t *ptemp,
-										  const char *filename)
+                                          const char *filename)
 {
     const char *errmsg;
     char *l = apr_palloc (ptemp, MAX_STRING_LEN);
     const char *args = l;
     char *cmd_name, *w;
-	const command_rec *cmd;
-	apr_array_header_t *arr = apr_array_make(p, 1, sizeof(cmd_parms));
-	apr_array_header_t *ari = apr_array_make(p, 1, sizeof(char *));
+    const command_rec *cmd;
+    apr_array_header_t *arr = apr_array_make(p, 1, sizeof(cmd_parms));
+    apr_array_header_t *ari = apr_array_make(p, 1, sizeof(char *));
     cmd_parms *parms;
-	apr_status_t status;
-	ap_directive_t *newdir;
-	int optional;
-	char *err = NULL;
-	char *rootpath, *incpath;
-	int li;
-
-	errmsg = populate_include_files(p, ptemp, ari, filename, 0);
-
-	if(errmsg != NULL)
-		goto Exit;
-
-	while(ari->nelts != 0 || arr->nelts != 0)
-	{
-		if(ari->nelts > 0)
-		{
-			char *fn = *(char **)apr_array_pop(ari);
-
-			parms = (cmd_parms *)apr_array_push(arr);
-			*parms = default_parms;
-			parms->pool = p;
-			parms->temp_pool = ptemp;
-			parms->server = s;
-			parms->override = (RSRC_CONF | OR_ALL) & ~(OR_AUTHCFG | OR_LIMIT);
-			parms->override_opts = OPT_ALL | OPT_SYM_OWNER | OPT_MULTI;
-
-			status = ap_pcfg_openfile(&parms->config_file, p, fn);
-
-			if(status != APR_SUCCESS)
-			{
-				apr_array_pop(arr);
-				errmsg = apr_pstrcat(p, "Cannot open config file: ", fn, NULL);
-				goto Exit;
-			}
-		}
-
-		if (arr->nelts > 1024) {
+    apr_status_t status;
+    ap_directive_t *newdir;
+    int optional;
+    char *err = NULL;
+    char *rootpath, *incpath;
+    int li;
+
+    errmsg = populate_include_files(p, ptemp, ari, filename, 0);
+
+    if(errmsg != NULL)
+        goto Exit;
+
+    while(ari->nelts != 0 || arr->nelts != 0)
+    {
+        if(ari->nelts > 0)
+        {
+            char *fn = *(char **)apr_array_pop(ari);
+
+            parms = (cmd_parms *)apr_array_push(arr);
+            *parms = default_parms;
+            parms->pool = p;
+            parms->temp_pool = ptemp;
+            parms->server = s;
+            parms->override = (RSRC_CONF | OR_ALL) & ~(OR_AUTHCFG | OR_LIMIT);
+            parms->override_opts = OPT_ALL | OPT_SYM_OWNER | OPT_MULTI;
+
+            status = ap_pcfg_openfile(&parms->config_file, p, fn);
+
+            if(status != APR_SUCCESS)
+            {
+                apr_array_pop(arr);
+                errmsg = apr_pstrcat(p, "Cannot open config file: ", fn, NULL);
+                goto Exit;
+            }
+        }
+
+        if (arr->nelts > 1024) {
             errmsg = "Exceeded the maximum include directory nesting level. You have "
                                 "probably a recursion somewhere.";
-			goto Exit;
+            goto Exit;
         }
 
-		parms = (cmd_parms *)apr_array_pop(arr);
+        parms = (cmd_parms *)apr_array_pop(arr);
 
-		if(parms == NULL)
-			break;
+        if(parms == NULL)
+            break;
 
-		while (!(ap_cfg_getline(l, MAX_STRING_LEN, parms->config_file))) {
-			if (*l == '#' || *l == '\0')
-				continue;
+        while (!(ap_cfg_getline(l, MAX_STRING_LEN, parms->config_file))) {
+            if (*l == '#' || *l == '\0')
+                continue;
 
-			args = l;
+            args = l;
 
-			cmd_name = ap_getword_conf(p, &args);
+            cmd_name = ap_getword_conf(p, &args);
 
-			if (*cmd_name == '\0')
-				continue;
+            if (*cmd_name == '\0')
+                continue;
 
-			if (!strcasecmp(cmd_name, "IncludeOptional"))
-			{
-				optional = 1;
-				goto ProcessInclude;
-			}
+            if (!strcasecmp(cmd_name, "IncludeOptional"))
+            {
+                optional = 1;
+                goto ProcessInclude;
+            }
 
-			if (!strcasecmp(cmd_name, "Include"))
-			{
-				optional = 0;
+            if (!strcasecmp(cmd_name, "Include"))
+            {
+                optional = 0;
 ProcessInclude:
-				w = ap_getword_conf(parms->pool, &args);
+                w = ap_getword_conf(parms->pool, &args);
 
-				if (*w == '\0' || *args != 0)
-				{
-					ap_cfg_closefile(parms->config_file);
-					errmsg = apr_pstrcat(parms->pool, "Include takes one argument", NULL);
-					goto Exit;
-				}
+                if (*w == '\0' || *args != 0)
+                {
+                    ap_cfg_closefile(parms->config_file);
+                    errmsg = apr_pstrcat(parms->pool, "Include takes one argument", NULL);
+                    goto Exit;
+                }
 
-				incpath = w;
+                incpath = w;
 
-				/* locate the start of the directories proper */
-				status = apr_filepath_root((const char **)&rootpath, (const char **)&incpath, APR_FILEPATH_TRUENAME | APR_FILEPATH_NATIVE, ptemp);
+                /* locate the start of the directories proper */
+                status = apr_filepath_root((const char **)&rootpath, (const char **)&incpath, APR_FILEPATH_TRUENAME | APR_FILEPATH_NATIVE, ptemp);
 
-				/* we allow APR_SUCCESS and APR_EINCOMPLETE */
-				if (APR_ERELATIVE == status) {
-					rootpath = apr_pstrdup(ptemp, parms->config_file->name);
-					li = strlen(rootpath) - 1;
+                /* we allow APR_SUCCESS and APR_EINCOMPLETE */
+                if (APR_ERELATIVE == status) {
+                    rootpath = apr_pstrdup(ptemp, parms->config_file->name);
+                    li = strlen(rootpath) - 1;
 
-					while(li >= 0 && rootpath[li] != '/' && rootpath[li] != '\\')
-						rootpath[li--] = 0;
+                    while(li >= 0 && rootpath[li] != '/' && rootpath[li] != '\\')
+                        rootpath[li--] = 0;
 
-					w = apr_pstrcat(p, rootpath, w, NULL);
-				}
-				else if (APR_EBADPATH == status) {
-					ap_cfg_closefile(parms->config_file);
-					errmsg = apr_pstrcat(p, "Include file has a bad path, ", w, NULL);
-					goto Exit;
-				}
+                    w = apr_pstrcat(p, rootpath, w, NULL);
+                }
+                else if (APR_EBADPATH == status) {
+                    ap_cfg_closefile(parms->config_file);
+                    errmsg = apr_pstrcat(p, "Include file has a bad path, ", w, NULL);
+                    goto Exit;
+                }
 
-				errmsg = populate_include_files(p, ptemp, ari, w, optional);
+                errmsg = populate_include_files(p, ptemp, ari, w, optional);
 
-				*(cmd_parms *)apr_array_push(arr) = *parms;
+                *(cmd_parms *)apr_array_push(arr) = *parms;
 
-				if(errmsg != NULL)
-					goto Exit;
+                if(errmsg != NULL)
+                    goto Exit;
 
-				// we don't want to close the current file yet
-				//
-				parms = NULL;
-				break;
-			}
+                // we don't want to close the current file yet
+                //
+                parms = NULL;
+                break;
+            }
 
-			cmd = ap_find_command(cmd_name, security2_module.cmds);
+            cmd = ap_find_command(cmd_name, security2_module.cmds);
 
-			if(cmd == NULL)
-			{
-				// unknown command, should error
-				//
-				ap_cfg_closefile(parms->config_file);
-				errmsg = apr_pstrcat(p, "Unknown command in config: ", cmd_name, NULL);
-				goto Exit;
-			}
+            if(cmd == NULL)
+            {
+                // unknown command, should error
+                //
+                ap_cfg_closefile(parms->config_file);
+                errmsg = apr_pstrcat(p, "Unknown command in config: ", cmd_name, NULL);
+                goto Exit;
+            }
 
-			newdir = apr_pcalloc(p, sizeof(ap_directive_t));
-			newdir->filename = parms->config_file->name;
-			newdir->line_num = parms->config_file->line_number;
-			newdir->directive = cmd_name;
-			newdir->args = apr_pstrdup(p, args);
+            newdir = apr_pcalloc(p, sizeof(ap_directive_t));
+            newdir->filename = parms->config_file->name;
+            newdir->line_num = parms->config_file->line_number;
+            newdir->directive = cmd_name;
+            newdir->args = apr_pstrdup(p, args);
 
-			parms->directive = newdir;
+            parms->directive = newdir;
 
 #ifdef WIN32
-			// some config commands fail in APR when there are file
-			// permission issues or other OS-specific problems
-			//
-			__try
-			{
+            // some config commands fail in APR when there are file
+            // permission issues or other OS-specific problems
+            //
+            __try
+            {
 #endif
-				errmsg = invoke_cmd(cmd, parms, mconfig, args);
+                errmsg = invoke_cmd(cmd, parms, mconfig, args);
 #ifdef WIN32
-			}
-			__except(EXCEPTION_EXECUTE_HANDLER)
-			{
-				errmsg = "Command failed to execute (check file/folder permissions, syntax, etc.).";
-			}
+            }
+            __except(EXCEPTION_EXECUTE_HANDLER)
+            {
+                errmsg = "Command failed to execute (check file/folder permissions, syntax, etc.).";
+            }
 #endif
 
-			if(errmsg != NULL)
-				break;
-		}
+            if(errmsg != NULL)
+                break;
+        }
 
-		if(parms != NULL)
-			ap_cfg_closefile(parms->config_file);
+        if(parms != NULL)
+            ap_cfg_closefile(parms->config_file);
 
-		if(errmsg != NULL)
-			break;
-	}
+        if(errmsg != NULL)
+            break;
+    }
 
     if (errmsg) {
-		err = (char *)apr_palloc(p, 1024);
+        err = (char *)apr_palloc(p, 1024);
 
-		if(parms != NULL)
-			apr_snprintf(err, 1024, "Syntax error in config file %s, line %d: %s", parms->config_file->name,
-							parms->config_file->line_number, errmsg);
-		else
-			apr_snprintf(err, 1024, "Syntax error in config file: %s", errmsg);
+        if(parms != NULL)
+            apr_snprintf(err, 1024, "Syntax error in config file %s, line %d: %s", parms->config_file->name,
+                            parms->config_file->line_number, errmsg);
+        else
+            apr_snprintf(err, 1024, "Syntax error in config file: %s", errmsg);
     }
 
     errmsg = err;
 
 Exit:
-	while((parms = (cmd_parms *)apr_array_pop(arr)) != NULL)
-	{
-		ap_cfg_closefile(parms->config_file);
-	}
+    while((parms = (cmd_parms *)apr_array_pop(arr)) != NULL)
+    {
+        ap_cfg_closefile(parms->config_file);
+    }
 
-	return errmsg;
+    return errmsg;
 }
 
diff --git a/standalone/filters.c b/standalone/filters.c
index c0c1564868..9d113caa6d 100644
--- a/standalone/filters.c
+++ b/standalone/filters.c
@@ -37,7 +37,7 @@
 #include "ap_config.h"
 #include "http_config.h"
 
-#define	FILTER_POOL	apr_hook_global_pool
+#define    FILTER_POOL    apr_hook_global_pool
 #include "apr_hooks.h"
 
 /*
@@ -56,11 +56,11 @@ apr_table_t *ms_output_filters = NULL;
 
 void init_filter_tables()
 {
-	if(ms_input_filters == NULL)
-	{
-		ms_input_filters = apr_table_make(FILTER_POOL, 10);
-		ms_output_filters = apr_table_make(FILTER_POOL, 10);
-	}
+    if(ms_input_filters == NULL)
+    {
+        ms_input_filters = apr_table_make(FILTER_POOL, 10);
+        ms_output_filters = apr_table_make(FILTER_POOL, 10);
+    }
 }
 
 AP_DECLARE(ap_filter_rec_t *) ap_register_input_filter(const char *name,
@@ -68,20 +68,20 @@ AP_DECLARE(ap_filter_rec_t *) ap_register_input_filter(const char *name,
                                           ap_init_filter_func filter_init,
                                           ap_filter_type ftype)
 {
-	ap_filter_rec_t *f;
+    ap_filter_rec_t *f;
 
-	init_filter_tables();
-	
-	f = apr_palloc(FILTER_POOL, sizeof(ap_filter_rec_t));
+    init_filter_tables();
+    
+    f = apr_palloc(FILTER_POOL, sizeof(ap_filter_rec_t));
 
-	f->filter_func.in_func = filter_func;
-	f->filter_init_func = filter_init;
-	f->ftype = ftype;
-	f->name = name;
+    f->filter_func.in_func = filter_func;
+    f->filter_init_func = filter_init;
+    f->ftype = ftype;
+    f->name = name;
 
-	apr_table_setn(ms_input_filters, name, (const char *)f);
+    apr_table_setn(ms_input_filters, name, (const char *)f);
 
-	return f;
+    return f;
 }
 
 AP_DECLARE(ap_filter_rec_t *) ap_register_output_filter(const char *name,
@@ -89,20 +89,20 @@ AP_DECLARE(ap_filter_rec_t *) ap_register_output_filter(const char *name,
                                             ap_init_filter_func filter_init,
                                             ap_filter_type ftype)
 {
-	ap_filter_rec_t *f;
-	
-	init_filter_tables();
-	
-	f = apr_palloc(FILTER_POOL, sizeof(ap_filter_rec_t));
+    ap_filter_rec_t *f;
+    
+    init_filter_tables();
+    
+    f = apr_palloc(FILTER_POOL, sizeof(ap_filter_rec_t));
 
-	f->filter_func.out_func = filter_func;
-	f->filter_init_func = filter_init;
-	f->ftype = ftype;
-	f->name = name;
+    f->filter_func.out_func = filter_func;
+    f->filter_init_func = filter_init;
+    f->ftype = ftype;
+    f->name = name;
 
-	apr_table_setn(ms_output_filters, name, (const char *)f);
+    apr_table_setn(ms_output_filters, name, (const char *)f);
 
-	return f;
+    return f;
 }
 
 static ap_filter_t *add_any_filter_handle(ap_filter_rec_t *frec, void *ctx,
@@ -187,12 +187,12 @@ static ap_filter_t *add_any_filter_handle(ap_filter_rec_t *frec, void *ctx,
 AP_DECLARE(ap_filter_t *) ap_add_input_filter(const char *name, void *ctx,
                                               request_rec *r, conn_rec *c)
 {
-	ap_filter_rec_t *f = (ap_filter_rec_t *)apr_table_get(ms_input_filters, name);
+    ap_filter_rec_t *f = (ap_filter_rec_t *)apr_table_get(ms_input_filters, name);
 
-	if(f == NULL)
-		return NULL;
+    if(f == NULL)
+        return NULL;
 
-	return add_any_filter_handle(f, ctx, r, c,
+    return add_any_filter_handle(f, ctx, r, c,
                           r ? &r->input_filters : NULL,
                           r ? &r->proto_input_filters : NULL, &c->input_filters);
 }
@@ -200,10 +200,10 @@ AP_DECLARE(ap_filter_t *) ap_add_input_filter(const char *name, void *ctx,
 AP_DECLARE(ap_filter_t *) ap_add_output_filter(const char *name, void *ctx, 
                                                request_rec *r, conn_rec *c)
 {
-	ap_filter_rec_t *f = (ap_filter_rec_t *)apr_table_get(ms_output_filters, name);
+    ap_filter_rec_t *f = (ap_filter_rec_t *)apr_table_get(ms_output_filters, name);
 
-	if(f == NULL)
-		return NULL;
+    if(f == NULL)
+        return NULL;
 
     return add_any_filter_handle(f, ctx, r, c,
                           r ? &r->output_filters : NULL,
diff --git a/standalone/hooks.c b/standalone/hooks.c
index dae77b81bf..0cc8e4c73c 100755
--- a/standalone/hooks.c
+++ b/standalone/hooks.c
@@ -44,11 +44,11 @@ link##_DECLARE(void) ns##_hook_##name(ns##_HOOK_##name##_t *pf, \
                                       const char * const *aszPre, \
                                       const char * const *aszSucc, int nOrder) \
 { \
-	hookfn_##name = pf; \
+    hookfn_##name = pf; \
 }
 
 #define DECLARE_HOOK(ret,name,args) \
-	DECLARE_EXTERNAL_HOOK(ap,AP,ret,name,args)
+    DECLARE_EXTERNAL_HOOK(ap,AP,ret,name,args)
 
 
 DECLARE_HOOK(int,pre_config,(apr_pool_t *pconf,apr_pool_t *plog, apr_pool_t *ptemp))
diff --git a/standalone/server.c b/standalone/server.c
index 31b12a6dbc..ae1a16fc7a 100644
--- a/standalone/server.c
+++ b/standalone/server.c
@@ -250,17 +250,17 @@ AP_DECLARE(char *) ap_escape_html(apr_pool_t *p, const char *s)
 
 AP_DECLARE(const char *) ap_psignature(const char *prefix, request_rec *r)
 {
-	return prefix;
+    return prefix;
 }
 
 AP_DECLARE(const char *) ap_document_root(request_rec *r) /* Don't use this! */
 {
-	return "\\";
+    return "\\";
 }
 
 AP_DECLARE(apr_port_t) ap_get_server_port(const request_rec *r)
 {
-	return 80;
+    return 80;
 }
 
 /////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -269,7 +269,7 @@ AP_DECLARE(apr_port_t) ap_get_server_port(const request_rec *r)
 AP_DECLARE(void) ap_log_error(const char *file, int line, int level, 
                              apr_status_t status, const server_rec *s, 
                              const char *fmt, ...)
-//			    __attribute__((format(printf,6,7)))
+//                __attribute__((format(printf,6,7)))
 #else
 AP_DECLARE(void) ap_log_error_(const char *file, int line, int module_index,
                                int level, apr_status_t status,
@@ -284,10 +284,10 @@ AP_DECLARE(void) ap_log_error_(const char *file, int line, int module_index,
 
     apr_vsnprintf(errstr, MAX_STRING_LEN, fmt, args);
 
-	va_end(args);
+    va_end(args);
 
-	if(modsecLogHook != NULL)
-		modsecLogHook(modsecLogObj, level, errstr);
+    if(modsecLogHook != NULL)
+        modsecLogHook(modsecLogObj, level, errstr);
 }
 
 
@@ -295,7 +295,7 @@ AP_DECLARE(void) ap_log_error_(const char *file, int line, int module_index,
 AP_DECLARE(void) ap_log_cerror(const char *file, int line, int level,
                              apr_status_t status, const conn_rec *r,
                              const char *fmt, ...)
-//			    __attribute__((format(printf,6,7)))
+//                __attribute__((format(printf,6,7)))
 #else
 AP_DECLARE(void) ap_log_cerror_(const char *file, int line, int module_index,
                                 int level, apr_status_t status,
@@ -310,10 +310,10 @@ AP_DECLARE(void) ap_log_cerror_(const char *file, int line, int module_index,
 
     apr_vsnprintf(errstr, MAX_STRING_LEN, fmt, args);
 
-	va_end(args);
+    va_end(args);
 
-	if(modsecLogHook != NULL)
-		modsecLogHook(modsecLogObj, level, errstr);
+    if(modsecLogHook != NULL)
+        modsecLogHook(modsecLogObj, level, errstr);
 }
 
 
@@ -321,7 +321,7 @@ AP_DECLARE(void) ap_log_cerror_(const char *file, int line, int module_index,
 AP_DECLARE(void) ap_log_rerror(const char *file, int line, int level,
                              apr_status_t status, const request_rec *r,
                              const char *fmt, ...)
-//			    __attribute__((format(printf,6,7)))
+//                __attribute__((format(printf,6,7)))
 #else
 AP_DECLARE(void) ap_log_rerror_(const char *file, int line, int module_index,
                                int level, apr_status_t status,
@@ -336,17 +336,17 @@ AP_DECLARE(void) ap_log_rerror_(const char *file, int line, int module_index,
 
     apr_vsnprintf(errstr, MAX_STRING_LEN, fmt, args);
 
-	va_end(args);
+    va_end(args);
 
-	if(modsecLogHook != NULL)
-		modsecLogHook(modsecLogObj, level, errstr);
+    if(modsecLogHook != NULL)
+        modsecLogHook(modsecLogObj, level, errstr);
 }
 
 #if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER < 3
 AP_DECLARE(void) ap_log_perror(const char *file, int line, int level, 
                              apr_status_t status, apr_pool_t *p, 
                              const char *fmt, ...)
-//			    __attribute__((format(printf,6,7)))
+//                __attribute__((format(printf,6,7)))
 #else
 AP_DECLARE(void) ap_log_perror_(const char *file, int line, int module_index,
                                 int level, apr_status_t status, apr_pool_t *p,
@@ -360,28 +360,28 @@ AP_DECLARE(void) ap_log_perror_(const char *file, int line, int module_index,
 
     apr_vsnprintf(errstr, MAX_STRING_LEN, fmt, args);
 
-	va_end(args);
+    va_end(args);
 
-	if(modsecLogHook != NULL)
-		modsecLogHook(modsecLogObj, level, errstr);
+    if(modsecLogHook != NULL)
+        modsecLogHook(modsecLogObj, level, errstr);
 }
 
 AP_DECLARE(module *) ap_find_linked_module(const char *name)
 {
-	// only used for ACTION_PROXY to find mod_proxy.c; see mod_security2.c, perform_interception()
-	//
-	return NULL;
+    // only used for ACTION_PROXY to find mod_proxy.c; see mod_security2.c, perform_interception()
+    //
+    return NULL;
 }
 
 AP_DECLARE(const char *) ap_get_server_name(request_rec *r)
 {
-	return r->server->server_hostname;
+    return r->server->server_hostname;
 }
 
 AP_DECLARE(void) ap_add_version_component(apr_pool_t *pconf, const char *component)
 {
-	// appends string to server description string
-	//
+    // appends string to server description string
+    //
 }
 
 AP_DECLARE(const char *) ap_get_status_line(int status)
@@ -467,7 +467,7 @@ AP_DECLARE(apr_status_t) ap_mpm_query(int query_code, int *result)
 
 AP_DECLARE(const char *) ap_get_server_banner(void)
 {
-	return "ModSecurity Standalone";
+    return "ModSecurity Standalone";
 }
 
 /* Code from Harald Hanche-Olsen <hanche@imf.unit.no> */
@@ -493,7 +493,7 @@ static APR_INLINE void do_double_reverse (conn_rec *conn)
 #if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER < 3
             if (apr_sockaddr_equal(sa, conn->remote_addr)) {
 #else
-	    if (apr_sockaddr_equal(sa, conn->client_addr)) {
+        if (apr_sockaddr_equal(sa, conn->client_addr)) {
 #endif
                 conn->double_reverse = 1;
                 return;
@@ -507,10 +507,10 @@ static APR_INLINE void do_double_reverse (conn_rec *conn)
 }
 
 #ifndef HOSTNAME_LOOKUP_OFF
-#define HOSTNAME_LOOKUP_OFF	0
-#define HOSTNAME_LOOKUP_ON	1
-#define HOSTNAME_LOOKUP_DOUBLE	2
-#define HOSTNAME_LOOKUP_UNSET	3
+#define HOSTNAME_LOOKUP_OFF    0
+#define HOSTNAME_LOOKUP_ON    1
+#define HOSTNAME_LOOKUP_DOUBLE    2
+#define HOSTNAME_LOOKUP_UNSET    3
 #endif
 
 AP_DECLARE(void) ap_str_tolower(char *str)
@@ -593,7 +593,7 @@ AP_DECLARE(const char *) ap_get_remote_host(conn_rec *conn, void *dir_config, in
 #if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER < 3
             return conn->remote_ip;
 #else
-	    return conn->client_ip;
+        return conn->client_ip;
 #endif
         }
     }
@@ -617,7 +617,7 @@ AP_DECLARE(char *) ap_server_root_relative(apr_pool_t *p, const char *file)
 
 AP_DECLARE(piped_log *) ap_open_piped_log(apr_pool_t *p, const char *program)
 {
-	return NULL;
+    return NULL;
 }
 
 #if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER > 3

From 970b5f87f10764ea22304b8467e0e6038e09749e Mon Sep 17 00:00:00 2001
From: Vladimir Krivopalov <vlkrivop@microsoft.com>
Date: Tue, 12 Mar 2019 12:44:19 -0700
Subject: [PATCH 20/58] Update VS project with information about new files and
 dependencies.

Add recently added helper classes to the project-tracked list of files.
Add 'asio' to VS project list of include directories.

Signed-off-by: Vladimir Krivopalov <vlkrivop@microsoft.com>
---
 iis/ModSecurityIIS.vcxproj         | 8 +++++---
 iis/ModSecurityIIS.vcxproj.filters | 2 ++
 2 files changed, 7 insertions(+), 3 deletions(-)

diff --git a/iis/ModSecurityIIS.vcxproj b/iis/ModSecurityIIS.vcxproj
index 7f2822a409..5542559026 100755
--- a/iis/ModSecurityIIS.vcxproj
+++ b/iis/ModSecurityIIS.vcxproj
@@ -120,7 +120,7 @@
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
     <ClCompile>
       <Optimization>Disabled</Optimization>
-      <AdditionalIncludeDirectories>dependencies\build_dir\pcre\include;dependencies\build_dir\pcre;dependencies\build_dir\libxml2\include;dependencies\build_dir\apache24\include;..\apache2;..\standalone;dependencies\build_dir\lloyd-yajl-f4b2b1a\build\yajl-2.0.1\include;</AdditionalIncludeDirectories>
+      <AdditionalIncludeDirectories>dependencies\build_dir\pcre\include;dependencies\build_dir\pcre;dependencies\build_dir\libxml2\include;.\asio\asio\include;dependencies\build_dir\apache24\include;..\apache2;..\standalone;.\asio\asio\include;dependencies\build_dir\lloyd-yajl-f4b2b1a\build\yajl-2.0.1\include</AdditionalIncludeDirectories>
       <PreprocessorDefinitions>_MBCS;%(PreprocessorDefinitions);WIN32;WINNT;inline=APR_INLINE;AP_DECLARE_STATIC;VERSION_IIS</PreprocessorDefinitions>
       <PrecompiledHeader>NotUsing</PrecompiledHeader>
       <PrecompiledHeaderFile>precomp.h</PrecompiledHeaderFile>
@@ -140,7 +140,7 @@
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Custom Debug|Win32'">
     <ClCompile>
       <Optimization>Disabled</Optimization>
-      <AdditionalIncludeDirectories>dependencies\build_dir\pcre\include;dependencies\build_dir\pcre;dependencies\build_dir\libxml2\include;dependencies\build_dir\apache24\include;..\apache2;..\standalone;dependencies\build_dir\lloyd-yajl-f4b2b1a\build\yajl-2.0.1\include;</AdditionalIncludeDirectories>
+      <AdditionalIncludeDirectories>dependencies\build_dir\pcre\include;dependencies\build_dir\pcre;dependencies\build_dir\libxml2\include;.\asio\asio\include;dependencies\build_dir\apache24\include;..\apache2;..\standalone;.\asio\asio\include;dependencies\build_dir\lloyd-yajl-f4b2b1a\build\yajl-2.0.1\include</AdditionalIncludeDirectories>
       <PreprocessorDefinitions>_MBCS;%(PreprocessorDefinitions);WIN32;WINNT;inline=APR_INLINE;AP_DECLARE_STATIC;VERSION_IIS</PreprocessorDefinitions>
       <PrecompiledHeader>NotUsing</PrecompiledHeader>
       <PrecompiledHeaderFile>precomp.h</PrecompiledHeaderFile>
@@ -217,7 +217,7 @@ net start W3SVC /y</Command>
     <ClCompile>
       <PreprocessorDefinitions>_MBCS;%(PreprocessorDefinitions);WIN32;WINNT;inline=APR_INLINE;AP_DECLARE_STATIC;VERSION_IIS</PreprocessorDefinitions>
       <PrecompiledHeader>NotUsing</PrecompiledHeader>
-      <AdditionalIncludeDirectories>dependencies\build_dir\pcre\include;dependencies\build_dir\pcre;dependencies\build_dir\libxml2\include;..\apache2;..\standalone;dependencies\build_dir\lloyd-yajl-f4b2b1a\build\yajl-2.0.1\include;</AdditionalIncludeDirectories>
+      <AdditionalIncludeDirectories>dependencies\build_dir\pcre\include;dependencies\build_dir\pcre;dependencies\build_dir\libxml2\include;.\asio\asio\include;..\apache2;..\standalone;dependencies\build_dir\lloyd-yajl-f4b2b1a\build\yajl-2.0.1\include;</AdditionalIncludeDirectories>
     </ClCompile>
     <Link>
       <ModuleDefinitionFile>mymodule.def</ModuleDefinitionFile>
@@ -325,6 +325,8 @@ net start W3SVC /y</Command>
     <ClInclude Include="..\apache2\re.h" />
     <ClInclude Include="..\apache2\utf8tables.h" />
     <ClInclude Include="..\standalone\api.h" />
+    <ClInclude Include="critical_section.h" />
+    <ClInclude Include="event_logger.h" />
     <ClInclude Include="moduleconfig.h" />
     <ClInclude Include="mymodule.h" />
     <ClInclude Include="mymodulefactory.h" />
diff --git a/iis/ModSecurityIIS.vcxproj.filters b/iis/ModSecurityIIS.vcxproj.filters
index cdc9bb8d90..7d741e9623 100755
--- a/iis/ModSecurityIIS.vcxproj.filters
+++ b/iis/ModSecurityIIS.vcxproj.filters
@@ -201,6 +201,8 @@
     <ClInclude Include="..\apache2\msc_status_engine.h">
       <Filter>ModSecurity</Filter>
     </ClInclude>
+    <ClInclude Include="event_logger.h" />
+    <ClInclude Include="critical_section.h" />
   </ItemGroup>
   <ItemGroup>
     <None Include="ModSecurity.xml" />

From 18e7cd2740043ca4b0a9445a87a62d9febcf0af7 Mon Sep 17 00:00:00 2001
From: Vladimir Krivopalov <vlkrivop@microsoft.com>
Date: Tue, 12 Mar 2019 14:31:32 -0700
Subject: [PATCH 21/58] Make CriticalSection class non-copyable and
 non-moveable.

This aligns with std::mutex and other synchronization primitives.
Also mark non-throwing methods with a /* noexcept */ comment until
'noexcept' keyword support is available with newer VS compiler.

Signed-off-by: Vladimir Krivopalov <vlkrivop@microsoft.com>
---
 iis/critical_section.h | 12 +++++++++---
 1 file changed, 9 insertions(+), 3 deletions(-)

diff --git a/iis/critical_section.h b/iis/critical_section.h
index 14026be180..260e69b51d 100644
--- a/iis/critical_section.h
+++ b/iis/critical_section.h
@@ -21,20 +21,26 @@
 // Implements BasicLockable requirements:
 //      https://en.cppreference.com/w/cpp/named_req/BasicLockable
 //
+// Like std::mutex, CriticalSection is neither Copyable nor Moveable.
 class CriticalSection
 {
 public:
-    CriticalSection()
+    CriticalSection() /* noexcept */
     {
         InitializeCriticalSection(&cs);
     }
 
-    void lock()
+    CriticalSection(const CriticalSection&) = delete;
+    CriticalSection(CriticalSection&&) = delete;
+    CriticalSection& operator=(const CriticalSection&) = delete;
+    CriticalSection& operator=(CriticalSection&&) = delete;
+
+    void lock() /* noexcept */
     {
         EnterCriticalSection(&cs);
     }
 
-    void unlock()
+    void unlock() /* noexcept */
     {
         LeaveCriticalSection(&cs);
     }

From 21baa2b264cf64724e5db22f3e78533c50b8afc6 Mon Sep 17 00:00:00 2001
From: Vladimir Krivopalov <vlkrivop@microsoft.com>
Date: Tue, 12 Mar 2019 14:32:23 -0700
Subject: [PATCH 22/58] Make EventLogger helper non-copyable and properly
 moveable.

Also mark non-throwing methods with a /* noexcept */ comment until
'noexcept' keyword support is available with newer VS compiler.

Signed-off-by: Vladimir Krivopalov <vlkrivop@microsoft.com>
---
 iis/event_logger.h | 24 ++++++++++++++++++++++--
 1 file changed, 22 insertions(+), 2 deletions(-)

diff --git a/iis/event_logger.h b/iis/event_logger.h
index 9eb1b67868..c71a3db7a1 100644
--- a/iis/event_logger.h
+++ b/iis/event_logger.h
@@ -16,12 +16,14 @@
 
 #include <Windows.h>
 
+// A simple class to use to write messages to common Windows event log.
+// The class is Moveable but non-Copyable.
 class EventLogger
 {
 public:
     EventLogger() /* noexcept */
+        : handle{RegisterEventSource(nullptr, "ModSecurity")}
     {
-        handle = RegisterEventSource(nullptr, "ModSecurity");
     }
 
     BOOL Log(const char* message, DWORD category)
@@ -36,9 +38,27 @@ class EventLogger
         return FALSE;
     }
 
+    EventLogger(const EventLogger&) = delete;
+    EventLogger& operator=(const EventLogger&) = delete;
+
+    EventLogger(EventLogger&& rhs) /* noexcept */
+        : handle(rhs.handle)
+    {
+        rhs.handle = nullptr;
+    }
+
+    EventLogger& operator=(EventLogger&& rhs) /* noexcept */
+    {
+        handle = rhs.handle;
+        rhs.handle = nullptr;
+        return *this;
+    }
+
     ~EventLogger()
     {
-        DeregisterEventSource(handle);
+        if (handle) {
+            DeregisterEventSource(handle);
+        }
     }
 
 private:

From e0795b90a14feae0d67ef474f1b315006b4d2895 Mon Sep 17 00:00:00 2001
From: Vladimir Krivopalov <vlkrivop@microsoft.com>
Date: Tue, 12 Mar 2019 16:50:53 -0700
Subject: [PATCH 23/58] Only set APR request body if non-empty.

If we set EOS bucket to the brigade and assign this brigade to APR
request, it causes an error code returned from modsecProcessRequest().
This does not affect detection-only mode because we dismiss the code but
needs to be taken into account for prevention mode.

Signed-off-by: Vladimir Krivopalov <vlkrivop@microsoft.com>
---
 iis/mymodule.cpp | 90 +++++++++++++++++++++++++-----------------------
 1 file changed, 47 insertions(+), 43 deletions(-)

diff --git a/iis/mymodule.cpp b/iis/mymodule.cpp
index fddf37f8ba..b7dd3c8eaf 100644
--- a/iis/mymodule.cpp
+++ b/iis/mymodule.cpp
@@ -448,58 +448,62 @@ static HRESULT SaveRequestBodyToRequestRec(RequestStoredContext* rsc)
         APR_BRIGADE_INSERT_TAIL(brigade, bucket);
     }
 
-    apr_bucket* e = apr_bucket_eos_create(conn->bucket_alloc);
-    if (e == nullptr)
-    {
-        return E_OUTOFMEMORY;
-    }
-    APR_BRIGADE_INSERT_TAIL(brigade, e);
+    if (!APR_BRIGADE_EMPTY(brigade)) {
+        apr_bucket* e = apr_bucket_eos_create(conn->bucket_alloc);
+        if (e == nullptr)
+        {
+            return E_OUTOFMEMORY;
+        }
+        APR_BRIGADE_INSERT_TAIL(brigade, e);
 
-    modsecSetBodyBrigade(aprRequest, brigade);
+        modsecSetBodyBrigade(aprRequest, brigade);
 
-    apr_off_t contentLength = 0;
-    apr_status_t status = apr_brigade_length(brigade, FALSE, &contentLength);
-    if (status != APR_SUCCESS)
-    {
-        return E_FAIL;
-    }
+        apr_off_t contentLength = 0;
+        apr_status_t status = apr_brigade_length(brigade, FALSE, &contentLength);
+        if (status != APR_SUCCESS)
+        {
+            return E_FAIL;
+        }
 
-    // Remove/Modify Transfer-Encoding header if "chunked" Encoding is set in the request. 
-    // This is to avoid sending both Content-Length and Chunked Transfer-Encoding in the request header.
-    static const std::string CHUNKED = "chunked";
-    USHORT encodingLength = 0;
-    const char* transferEncoding = iisRequest->GetHeader(HttpHeaderTransferEncoding, &encodingLength);
-    if (transferEncoding)
-    {
-        if (CHUNKED.size() == encodingLength &&
-            std::equal(CHUNKED.cbegin(), CHUNKED.cend(), transferEncoding,
-                [](char lhs, char rhs) { return std::tolower(lhs) == std::tolower(rhs); }))
+        // Remove/Modify Transfer-Encoding header if "chunked" Encoding is set in the request. 
+        // This is to avoid sending both Content-Length and Chunked Transfer-Encoding in the request header.
+        static const std::string CHUNKED = "chunked";
+        USHORT encodingLength = 0;
+        const char* transferEncoding = iisRequest->GetHeader(HttpHeaderTransferEncoding, &encodingLength);
+        if (transferEncoding)
         {
-            iisRequest->DeleteHeader(HttpHeaderTransferEncoding);
+            if (encodingLength == CHUNKED.size() &&
+                std::equal(CHUNKED.cbegin(), CHUNKED.cend(), transferEncoding,
+                [](char lhs, char rhs) { return std::tolower(lhs) == std::tolower(rhs); }))
+            {
+                iisRequest->DeleteHeader(HttpHeaderTransferEncoding);
+            }
         }
-    }
 
-    auto contentLengthStr = std::to_string(contentLength);
-    HRESULT hr = iisRequest->SetHeader(
-        HttpHeaderContentLength,
-        contentLengthStr.c_str(),
-        contentLengthStr.size(),
-        TRUE);
+        auto contentLengthStr = std::to_string(contentLength);
+        HRESULT hr = iisRequest->SetHeader(
+            HttpHeaderContentLength,
+            contentLengthStr.c_str(),
+            contentLengthStr.size(),
+            TRUE);
 
-    if (FAILED(hr))
-    {
-        return hr;
-    }
+        if (FAILED(hr))
+        {
+            return hr;
+        }
 
-    // since we clean the APR pool at the end of OnSendRequest, we must get IIS-managed memory chunk
-    //
-    char* requestBuffer = static_cast<char*>(rsc->httpContext->AllocateRequestMemory(contentLength));
-    status = apr_brigade_flatten(brigade, requestBuffer, reinterpret_cast<apr_size_t*>(&contentLength));
-    if (status != APR_SUCCESS)
-    {
-        return E_FAIL;
+        // since we clean the APR pool at the end of OnSendRequest, we must get IIS-managed memory chunk
+        //
+        char* requestBuffer = static_cast<char*>(rsc->httpContext->AllocateRequestMemory(contentLength));
+        status = apr_brigade_flatten(brigade, requestBuffer, reinterpret_cast<apr_size_t*>(&contentLength));
+        if (status != APR_SUCCESS)
+        {
+            return E_FAIL;
+        }
+        return iisRequest->InsertEntityBody(requestBuffer, contentLength);
     }
-    return iisRequest->InsertEntityBody(requestBuffer, contentLength);
+
+    return S_OK;
 }
 
 

From 3fa2caceb958eef57661a06120a2741272adf5ea Mon Sep 17 00:00:00 2001
From: Vladimir Krivopalov <vlkrivop@microsoft.com>
Date: Tue, 12 Mar 2019 16:55:00 -0700
Subject: [PATCH 24/58] Explicitly copy request body into Apache structures for
 any mode.

Use the same helper that has been previously only called for
detection-only mode when prevention mode is enabled.

Signed-off-by: Vladimir Krivopalov <vlkrivop@microsoft.com>
---
 iis/mymodule.cpp | 22 ++++++----------------
 1 file changed, 6 insertions(+), 16 deletions(-)

diff --git a/iis/mymodule.cpp b/iis/mymodule.cpp
index b7dd3c8eaf..1bb2c400d5 100644
--- a/iis/mymodule.cpp
+++ b/iis/mymodule.cpp
@@ -957,17 +957,6 @@ CMyHttpModule::OnBeginRequest(IHttpContext* httpContext, IHttpEventProvider* pro
 
         delete apppath;
         delete path;
-
-        if (config->config->is_enabled == MODSEC_DETECTION_ONLY)
-        {
-            modsecSetReadBody(nullptr);
-            modsecSetWriteBody(nullptr);
-        }
-        else
-        {
-            modsecSetReadBody(ReadBodyCallback);
-            modsecSetWriteBody(WriteBodyCallback);
-        }
     }
 
     ConnRecPtr connRec = MakeConnReq();
@@ -1218,13 +1207,14 @@ CMyHttpModule::OnBeginRequest(IHttpContext* httpContext, IHttpEventProvider* pro
 #endif
     c->remote_host = NULL;
 
+    hr = SaveRequestBodyToRequestRec(context);
+    if (FAILED(hr)) {
+        context->provider->SetErrorStatus(hr);
+        return RQ_NOTIFICATION_FINISH_REQUEST;
+    }
+
     if (config->config->is_enabled == MODSEC_DETECTION_ONLY)
     {
-        hr = SaveRequestBodyToRequestRec(context);
-        if (FAILED(hr)) {
-            context->provider->SetErrorStatus(hr);
-            return RQ_NOTIFICATION_FINISH_REQUEST;
-        }
         // We post the processing task to the thread pool to happen in the background.
         // We store the future to track and wait for this processing in case if we also
         // need to process the response because we need request processing to finish

From 87bd3ad69cdcc3b1bba650f885d4277fe3fbe861 Mon Sep 17 00:00:00 2001
From: Vladimir Krivopalov <vlkrivop@microsoft.com>
Date: Tue, 12 Mar 2019 16:56:36 -0700
Subject: [PATCH 25/58] Do not enforce stream in-body inspection flag for IIS.

Signed-off-by: Vladimir Krivopalov <vlkrivop@microsoft.com>
---
 iis/mymodule.cpp | 5 -----
 1 file changed, 5 deletions(-)

diff --git a/iis/mymodule.cpp b/iis/mymodule.cpp
index 1bb2c400d5..071a6ec914 100644
--- a/iis/mymodule.cpp
+++ b/iis/mymodule.cpp
@@ -972,11 +972,6 @@ CMyHttpModule::OnBeginRequest(IHttpContext* httpContext, IHttpEventProvider* pro
     rsc->responseProcessingEnabled = (config->config->resbody_access == 1);
     RequestStoredContext* context = rsc.get();
 
-    // on IIS we force input stream inspection flag, because its absence does not add any performance gain
-    // it's because on IIS request body must be restored each time it was read
-    //
-    modsecSetConfigForIISRequestBody(r);
-
     StoreIISContext(r, rsc.get());
 
     httpContext->GetModuleContextContainer()->SetModuleContext(rsc.release(), g_pModuleContext);

From 5c892d321762f11d4531e11bb9435de25f40315c Mon Sep 17 00:00:00 2001
From: Yanshu <yanshu.zhao7@gmail.com>
Date: Thu, 28 Mar 2019 15:20:05 -0700
Subject: [PATCH 26/58] fix non waf json log mode compilation (#106)

---
 nginx/modsecurity/ngx_http_modsecurity.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/nginx/modsecurity/ngx_http_modsecurity.c b/nginx/modsecurity/ngx_http_modsecurity.c
index d132564d53..0f2602fa3a 100644
--- a/nginx/modsecurity/ngx_http_modsecurity.c
+++ b/nginx/modsecurity/ngx_http_modsecurity.c
@@ -22,7 +22,9 @@
 #undef CRLF
 
 #include "api.h"
+#ifdef WAF_JSON_LOGGING_ENABLE
 #include <waf_log_util_external.h>
+#endif
 
 #define NOTE_NGINX_REQUEST_CTX "nginx-ctx"
 
@@ -561,7 +563,9 @@ ngx_http_modsecurity_init(ngx_conf_t *cf)
     extern pthread_mutex_t msc_pregcomp_ex_mtx;
     pthread_mutex_init(&msc_pregcomp_ex_mtx, NULL);
 
+#ifdef WAF_JSON_LOGGING_ENABLE
     init_appgw_rules_id_hash();
+#endif    
 
     return NGX_OK;
 }

From 1b92b933b8cc60685f1158f2d42580a8493591ce Mon Sep 17 00:00:00 2001
From: Allan Boll <allanbo@microsoft.com>
Date: Fri, 29 Mar 2019 17:51:09 -0700
Subject: [PATCH 27/58] Static linking of libprotobuf (#105)

* Static linking of libprotobuf


* adding known test failures
---
 nginx/modsecurity/config.in | 5 ++++-
 tests/config.py             | 2 +-
 2 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/nginx/modsecurity/config.in b/nginx/modsecurity/config.in
index 64cf14b5b9..1498f95a18 100644
--- a/nginx/modsecurity/config.in
+++ b/nginx/modsecurity/config.in
@@ -24,7 +24,10 @@ CORE_LIBS="$CORE_LIBS \
     @YAJL_LIBS@ \
     @SSDEEP_LDFLAGS@ \
     -lstdc++ \
-    -lprotobuf"
+    -Wl,-Bstatic
+    -lprotobuf
+    -Wl,-Bdynamic"
+
 
 ngx_addon_name=ngx_http_modsecurity
 
diff --git a/tests/config.py b/tests/config.py
index be06412a0f..5b93eb99fa 100644
--- a/tests/config.py
+++ b/tests/config.py
@@ -23,4 +23,4 @@
 #
 # Reverse format: (example: see above)
 #log_date_format = "%Y-%m-%d %H:%M:%S.%f"
-failing_tests = ['920100-10', '920100-12', '920100-14', '920100-2', '920100-4', '920100-6', '920100-8', '920160-4', '920170-5', '920170-6', '920180-1', '920180-3', '920200-3', '920200-4', '920200-7', '920200-9', '920210-5', '920220-2', '920240-2', '920260-2', '920270-6', '920271-5', '920271-6', '920272-4', '920273-2', '920273-4', '920274-5', '920290-1', '920310-2', '920310-5', '920311-2', '920320-2', '920330-2', '920350-2', '920420-9', '920430-8', '920450-5', '920450-8', '920470-4', '920470-5', '932100-3', '933110-11', '933110-19', '933130-3', '933130-6', '933151-3', '933151-5', '933160-22', '933161-5', '941100-4', '941120-1', '941160-1FN', '941310-1', '942420-1', '943110-4', '944100-11', '944100-12', '944100-15', '944100-16', '944110-11', '944110-12', '944110-15', '944110-16', '944120-107', '944120-108', '944120-124', '944120-125', '944120-22', '944120-23', '944120-39', '944120-40', '944120-5', '944120-56', '944120-57', '944120-6', '944120-73', '944120-74', '944120-90', '944120-91', '944210-22', '944210-23', '944210-39', '944210-40', '944210-5', '944210-6', '920200-10', '920240-3', '920270-7', '920310-3', '920310-6', '920470-6', '942480-2', '920220-3', '941100-5FN', '941110-2', '933160-21', '920311-3']
+failing_tests = ['920100-10', '920100-12', '920100-14', '920100-2', '920100-4', '920100-6', '920100-8', '920160-4', '920170-5', '920170-6', '920180-1', '920180-3', '920200-3', '920200-4', '920200-7', '920200-9', '920210-5', '920220-2', '920240-2', '920260-2', '920270-6', '920271-5', '920271-6', '920272-4', '920273-2', '920273-4', '920274-5', '920290-1', '920310-2', '920310-5', '920311-2', '920320-2', '920330-2', '920350-2', '920420-9', '920430-8', '920450-5', '920450-8', '920470-4', '920470-5', '932100-3', '933110-11', '933110-19', '933130-3', '933130-6', '933151-3', '933151-5', '933160-22', '933161-5', '941100-4', '941120-1', '941160-1FN', '941310-1', '942420-1', '943110-4', '944100-11', '944100-12', '944100-15', '944100-16', '944110-11', '944110-12', '944110-15', '944110-16', '944120-107', '944120-108', '944120-124', '944120-125', '944120-22', '944120-23', '944120-39', '944120-40', '944120-5', '944120-56', '944120-57', '944120-6', '944120-73', '944120-74', '944120-90', '944120-91', '944210-22', '944210-23', '944210-39', '944210-40', '944210-5', '944210-6', '920200-10', '920240-3', '920270-7', '920310-3', '920310-6', '920470-6', '942480-2', '920220-3', '941100-5FN', '941110-2', '933160-21', '920311-3', '921110-5', '942500-1']

From b3ed662e1b91dd3fa2234b039dd2f1e5bafbbd11 Mon Sep 17 00:00:00 2001
From: Vladimir Krivopalov <vladimir.krivopalov@gmail.com>
Date: Fri, 29 Mar 2019 20:08:11 -0700
Subject: [PATCH 28/58] Revert "Make detection mode run fully in background and
 not block Nginx requests (#97)" (#107)

This reverts commit 2b70b76c7e702f20212c1618261e3aa653ebd235.
---
 nginx/modsecurity/apr_bucket_nginx.c     |  10 +-
 nginx/modsecurity/apr_bucket_nginx.h     |   9 +-
 nginx/modsecurity/ngx_http_modsecurity.c | 213 +++++------------------
 3 files changed, 59 insertions(+), 173 deletions(-)

diff --git a/nginx/modsecurity/apr_bucket_nginx.c b/nginx/modsecurity/apr_bucket_nginx.c
index 9ed7cbbbcb..17906fe355 100644
--- a/nginx/modsecurity/apr_bucket_nginx.c
+++ b/nginx/modsecurity/apr_bucket_nginx.c
@@ -22,6 +22,7 @@ typedef struct apr_bucket_nginx {
 
 /* ngx_buf_t to apr_bucket */
 apr_bucket * apr_bucket_nginx_create(ngx_buf_t *buf,
+                                     apr_pool_t *p,
                                      apr_bucket_alloc_t *list)
 {
 
@@ -30,10 +31,11 @@ apr_bucket * apr_bucket_nginx_create(ngx_buf_t *buf,
     APR_BUCKET_INIT(b); /* link */
     b->free = apr_bucket_free;
     b->list = list;
-    return apr_bucket_nginx_make(b, buf);
+    return apr_bucket_nginx_make(b, buf, p);
 }
 
-apr_bucket * apr_bucket_nginx_make(apr_bucket *b, ngx_buf_t *buf)
+apr_bucket * apr_bucket_nginx_make(apr_bucket *b, ngx_buf_t *buf,
+                                   apr_pool_t *pool)
 {
     apr_bucket_nginx *n;
 
@@ -91,11 +93,11 @@ static void nginx_bucket_destroy(void *data)
 
 
 ngx_int_t
-copy_chain_to_brigade(ngx_chain_t *chain, apr_bucket_brigade *bb, ngx_int_t last_buf) {
+copy_chain_to_brigade(ngx_chain_t *chain, apr_bucket_brigade *bb, ngx_pool_t *pool, ngx_int_t last_buf) {
     apr_bucket         *e;
 
     while (chain) {
-        e = ngx_buf_to_apr_bucket(chain->buf, bb->bucket_alloc);
+        e = ngx_buf_to_apr_bucket(chain->buf, bb->p, bb->bucket_alloc);
         if (e == NULL) {
             return NGX_ERROR;
         }
diff --git a/nginx/modsecurity/apr_bucket_nginx.h b/nginx/modsecurity/apr_bucket_nginx.h
index b6b5762770..a4ce631389 100644
--- a/nginx/modsecurity/apr_bucket_nginx.h
+++ b/nginx/modsecurity/apr_bucket_nginx.h
@@ -2,10 +2,13 @@
 #include <ngx_core.h>
 #include "apr_buckets.h"
 
-apr_bucket * apr_bucket_nginx_create(ngx_buf_t *buf, apr_bucket_alloc_t *list);
+apr_bucket * apr_bucket_nginx_create(ngx_buf_t *buf,
+                                     apr_pool_t *p,
+                                     apr_bucket_alloc_t *list);
 
-apr_bucket * apr_bucket_nginx_make(apr_bucket *e, ngx_buf_t *buf);
+apr_bucket * apr_bucket_nginx_make(apr_bucket *e, ngx_buf_t *buf,
+                                   apr_pool_t *pool);
 
 #define ngx_buf_to_apr_bucket apr_bucket_nginx_create
 
-ngx_int_t copy_chain_to_brigade(ngx_chain_t *chain, apr_bucket_brigade *bb, ngx_int_t last_buf);
+ngx_int_t copy_chain_to_brigade(ngx_chain_t *chain, apr_bucket_brigade *bb, ngx_pool_t *pool, ngx_int_t last_buf);
diff --git a/nginx/modsecurity/ngx_http_modsecurity.c b/nginx/modsecurity/ngx_http_modsecurity.c
index 0f2602fa3a..2736390595 100644
--- a/nginx/modsecurity/ngx_http_modsecurity.c
+++ b/nginx/modsecurity/ngx_http_modsecurity.c
@@ -52,14 +52,8 @@ typedef struct {
 
 typedef struct {
     ngx_http_request_t *r;
-} ngx_http_modsecurity_prevention_thread_ctx_t;
+} ngx_http_modsecurity_thread_ctx_t;
 
-typedef struct {
-    conn_rec            *connection;
-    request_rec         *req;
-
-    apr_bucket_brigade  *brigade;
-} ngx_http_modsecurity_detection_thread_ctx_t;
 
 /*
 ** Module's registred function/handlers.
@@ -138,32 +132,23 @@ ngx_module_t ngx_http_modsecurity = {
 
 static ngx_http_upstream_t ngx_http_modsecurity_upstream;
 
-static inline char *
-dup_ngx_str_to_apr(apr_pool_t *pool, ngx_str_t *src)
-{
-    return apr_pstrmemdup(pool, (char *)src->data, src->len);
-}
-
-/*
- * Helper to allocate a thread task using an Apache pool.
- * This is useful when the background task can outlive the Nginx request
- * it is initiated for.
- */
-ngx_thread_task_t *
-apr_thread_task_alloc(apr_pool_t *pool, size_t size)
+static inline u_char *
+ngx_pstrdup0(ngx_pool_t *pool, ngx_str_t *src)
 {
-    ngx_thread_task_t  *task;
+    u_char  *dst;
 
-    task = apr_palloc(pool, sizeof(ngx_thread_task_t) + size);
-    if (task == NULL) {
+    dst = ngx_pnalloc(pool, src->len + 1);
+    if (dst == NULL) {
         return NULL;
     }
 
-    task->ctx = task + 1;
+    ngx_memcpy(dst, src->data, src->len);
+    dst[src->len] = '\0';
 
-    return task;
+    return dst;
 }
 
+
 static inline int
 ngx_http_modsecurity_method_number(unsigned int nginx)
 {
@@ -208,11 +193,6 @@ ngx_http_modsecurity_method_number(unsigned int nginx)
     return MultiplyDeBruijnBitPosition[((uint32_t)((nginx & -nginx) * 0x077CB531U)) >> 27];
 }
 
-/*
- * Use APR pool for all allocations because they should not depend on Nginx request pool.
- * In case of detection mode, processing will take place entirely in background and may last
- * longer than the original request lives.
- */
 static ngx_inline ngx_int_t
 ngx_http_modsecurity_load_request(ngx_http_request_t *r)
 {
@@ -230,7 +210,7 @@ ngx_http_modsecurity_load_request(ngx_http_request_t *r)
     req = ctx->req;
 
     /* request line */
-    req->method = dup_ngx_str_to_apr(req->pool, &r->method_name);
+    req->method = (char *)ngx_pstrdup0(r->pool, &r->method_name);
 
     /* TODO: how to use ap_method_number_of ?
      * req->method_number = ap_method_number_of(req->method);
@@ -243,18 +223,18 @@ ngx_http_modsecurity_load_request(ngx_http_request_t *r)
         return NGX_ERROR;
     }
 
-    req->filename = dup_ngx_str_to_apr(req->pool, &path);
+    req->filename = (char *) path.data;
     req->path_info = req->filename;
 
-    req->args = dup_ngx_str_to_apr(req->pool, &r->args);
+    req->args = (char *)ngx_pstrdup0(r->pool, &r->args);
 
     req->proto_num = r->http_major *1000 + r->http_minor;
-    req->protocol = dup_ngx_str_to_apr(req->pool, &r->http_protocol);
+    req->protocol = (char *)ngx_pstrdup0(r->pool, &r->http_protocol);
     req->request_time = apr_time_make(r->start_sec, r->start_msec);
-    req->the_request = dup_ngx_str_to_apr(req->pool, &r->request_line);
+    req->the_request = (char *)ngx_pstrdup0(r->pool, &r->request_line);
 
-    req->unparsed_uri = dup_ngx_str_to_apr(req->pool, &r->unparsed_uri);
-    req->uri = dup_ngx_str_to_apr(req->pool, &r->uri);
+    req->unparsed_uri = (char *)ngx_pstrdup0(r->pool, &r->unparsed_uri);
+    req->uri = (char *)ngx_pstrdup0(r->pool, &r->uri);
 
     req->parsed_uri.scheme = "http";
 
@@ -264,7 +244,7 @@ ngx_http_modsecurity_load_request(ngx_http_request_t *r)
     }
 #endif
 
-    req->parsed_uri.path = dup_ngx_str_to_apr(req->pool, &r->uri);
+    req->parsed_uri.path = (char *)ngx_pstrdup0(r->pool, &r->uri);
     req->parsed_uri.is_initialized = 1;
 
     switch (r->connection->local_sockaddr->sa_family) {
@@ -289,16 +269,18 @@ ngx_http_modsecurity_load_request(ngx_http_request_t *r)
     }
 
     req->parsed_uri.port = port;
-    req->parsed_uri.port_str = apr_palloc(req->pool, sizeof("65535"));
+    req->parsed_uri.port_str = ngx_pnalloc(r->pool, sizeof("65535"));
     (void) ngx_sprintf((u_char *)req->parsed_uri.port_str, "%ui%c", port, '\0');
 
     req->parsed_uri.query = r->args.len ? req->args : NULL;
     req->parsed_uri.dns_looked_up = 0;
     req->parsed_uri.dns_resolved = 0;
 
-    req->parsed_uri.fragment = dup_ngx_str_to_apr(req->pool, &r->exten);
+    // req->parsed_uri.password = (char *)ngx_pstrdup0(r->pool, &r->headers_in.passwd);
+    // req->parsed_uri.user = (char *)ngx_pstrdup0(r->pool, &r->headers_in.user);
+    req->parsed_uri.fragment = (char *)ngx_pstrdup0(r->pool, &r->exten);
 
-    req->hostname = dup_ngx_str_to_apr(req->pool, (ngx_str_t *)&ngx_cycle->hostname);
+    req->hostname = (char *)ngx_pstrdup0(r->pool, (ngx_str_t *)&ngx_cycle->hostname);
 
     req->header_only = r->header_only ? r->header_only : (r->method == NGX_HTTP_HEAD);
 
@@ -337,15 +319,7 @@ ngx_http_modsecurity_load_headers_in(ngx_http_request_t *r)
             i = 0;
         }
 
-        const char *key = dup_ngx_str_to_apr(req->pool, &h[i].key);
-        if (key == NULL) {
-            return NGX_ERROR;
-        }
-        const char *value = dup_ngx_str_to_apr(req->pool, &h[i].value);
-        if (value == NULL) {
-            return NGX_ERROR;
-        }
-        apr_table_setn(req->headers_in, key, value);
+        apr_table_setn(req->headers_in, (char *)h[i].key.data, (char *)h[i].value.data);
         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                        "ModSecurity: load headers in: \"%V: %V\"",
                        &h[i].key, &h[i].value);
@@ -361,14 +335,14 @@ ngx_http_modsecurity_load_headers_in(ngx_http_request_t *r)
     lang = apr_table_get(ctx->req->headers_in, "Content-Languages");
     if(lang != NULL)
     {
-        ctx->req->content_languages = apr_array_make(req->pool, 1, sizeof(const char *));
+        ctx->req->content_languages = apr_array_make(ctx->req->pool, 1, sizeof(const char *));
 
-        *(const char **)apr_array_push(req->content_languages) = lang;
+        *(const char **)apr_array_push(ctx->req->content_languages) = lang;
     }
 
     req->ap_auth_type = (char *)apr_table_get(req->headers_in, "Authorization");
 
-    req->user = dup_ngx_str_to_apr(req->pool, &r->headers_in.user);
+    req->user = (char *)ngx_pstrdup0(r->pool, &r->headers_in.user);
 
 
 
@@ -389,10 +363,10 @@ ngx_http_modsecurity_load_request_body(ngx_http_request_t *r)
 
     if (r->request_body == NULL || r->request_body->bufs == NULL) {
 
-        return copy_chain_to_brigade(NULL, ctx->brigade, 1);
+        return copy_chain_to_brigade(NULL, ctx->brigade, r->pool, 1);
     }
 
-    if (copy_chain_to_brigade(r->request_body->bufs, ctx->brigade, 1) != NGX_OK) {
+    if (copy_chain_to_brigade(r->request_body->bufs, ctx->brigade, r->pool, 1) != NGX_OK) {
         return NGX_ERROR;
     }
 
@@ -400,8 +374,10 @@ ngx_http_modsecurity_load_request_body(ngx_http_request_t *r)
 }
 
 static ngx_inline ngx_int_t
-ngx_http_modsecurity_status(int status)
+ngx_http_modsecurity_status(ngx_http_request_t *r, int status)
 {
+    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "ModSecurity: status %d", status);
+
     if (status == DECLINED || status == APR_SUCCESS) {
         return NGX_DECLINED;
     }
@@ -582,11 +558,11 @@ ngx_http_modsecurity_init_process(ngx_cycle_t *cycle)
 
 
 static void
-ngx_http_modsecurity_prevention_thread_func(void *data, ngx_log_t *log)
+ngx_http_modsecurity_thread_func(void *data, ngx_log_t *log)
 {
     // Executed in a separate thread
 
-    ngx_http_modsecurity_prevention_thread_ctx_t *thread_ctx = data;
+    ngx_http_modsecurity_thread_ctx_t *thread_ctx = data;
     ngx_http_request_t *r = thread_ctx->r;
 
     ngx_http_modsecurity_ctx_t* mod_ctx = ngx_http_get_module_ctx(r, ngx_http_modsecurity);
@@ -600,9 +576,7 @@ ngx_http_modsecurity_prevention_thread_func(void *data, ngx_log_t *log)
     }
 
     // Processing request headers
-    ngx_int_t rc = modsecProcessRequestHeaders(mod_ctx->req);
-    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "ModSecurity process headers: status %d", rc);
-    rc = ngx_http_modsecurity_status(rc);
+    ngx_int_t rc = ngx_http_modsecurity_status(r, modsecProcessRequestHeaders(mod_ctx->req));
 
     if (rc != NGX_DECLINED) {
         mod_ctx->status_code = rc;
@@ -622,14 +596,13 @@ ngx_http_modsecurity_prevention_thread_func(void *data, ngx_log_t *log)
     }
 
     // The name of modsecProcessRequestBody is a bit misleading. This function call is needed even to just process GET args.
-    rc = modsecProcessRequestBody(mod_ctx->req);
-    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "ModSecurity process body: status %d", rc);
-    mod_ctx->status_code = ngx_http_modsecurity_status(rc);
+    rc = ngx_http_modsecurity_status(r, modsecProcessRequestBody(mod_ctx->req));
+    mod_ctx->status_code = rc;
 }
 
 
 static void
-ngx_http_modsecurity_prevention_thread_completion(ngx_event_t *ev)
+ngx_http_modsecurity_thread_completion(ngx_event_t *ev)
 {
     // executed in nginx event loop after thread task is done, in order to pick up and continue processing request
 
@@ -646,52 +619,13 @@ ngx_http_modsecurity_prevention_thread_completion(ngx_event_t *ev)
 }
 
 
-static void
-ngx_http_modsecurity_detection_thread_func(void *data, ngx_log_t *log)
-{
-    // Executed in a separate thread
-    ngx_http_modsecurity_detection_thread_ctx_t *thread_ctx = data;
-
-    // Processing request headers
-    ngx_int_t rc = ngx_http_modsecurity_status(modsecProcessRequestHeaders(thread_ctx->req));
-    if (rc != NGX_DECLINED) {
-        return;
-    }
-
-    if (modsecContextState(thread_ctx->req) == MODSEC_DISABLED) {
-        return;
-    }
-
-    // The name of modsecProcessRequestBody is a bit misleading. This function call is needed even to just process GET args.
-    modsecProcessRequestBody(thread_ctx->req);
-}
-
-
-static void
-ngx_http_modsecurity_detection_thread_completion(ngx_event_t *ev)
-{
-    // executed in nginx event loop after thread task is done, in order to pick up and continue processing request
-    ngx_http_modsecurity_detection_thread_ctx_t *ctx = ev->data;
-
-    request_rec *req = ctx->req;
-    conn_rec *connection = ctx->connection;
-
-    if (req != NULL) {
-        modsecFinishRequest(req);
-    }
-    if (connection != NULL) {
-        modsecFinishConnection(connection);
-    }
-}
-
-
 static ngx_int_t
-ngx_http_modsecurity_prevention_task_offload(ngx_http_request_t *r)
+ngx_http_modsecurity_task_offload(ngx_http_request_t *r)
 {
-    ngx_http_modsecurity_prevention_thread_ctx_t *thread_ctx;
+    ngx_http_modsecurity_thread_ctx_t *thread_ctx;
     ngx_thread_task_t *task;
 
-    task = ngx_thread_task_alloc(r->pool, sizeof(ngx_http_modsecurity_prevention_thread_ctx_t));
+    task = ngx_thread_task_alloc(r->pool, sizeof(ngx_http_modsecurity_thread_ctx_t));
     if (task == NULL) {
         return NGX_ERROR;
     }
@@ -699,8 +633,8 @@ ngx_http_modsecurity_prevention_task_offload(ngx_http_request_t *r)
     thread_ctx = task->ctx;
     thread_ctx->r = r;
 
-    task->handler = ngx_http_modsecurity_prevention_thread_func;
-    task->event.handler = ngx_http_modsecurity_prevention_thread_completion;
+    task->handler = ngx_http_modsecurity_thread_func;
+    task->event.handler = ngx_http_modsecurity_thread_completion;
     task->event.data = r;
 
     ngx_thread_pool_t* thread_pool = ngx_thread_pool_get((ngx_cycle_t *)ngx_cycle, &thread_pool_name);
@@ -714,48 +648,6 @@ ngx_http_modsecurity_prevention_task_offload(ngx_http_request_t *r)
     return NGX_OK;
 }
 
-static ngx_int_t
-ngx_http_modsecurity_detection_task_offload(ngx_http_request_t *r)
-{
-    ngx_http_modsecurity_ctx_t *ctx = ngx_http_get_module_ctx(r, ngx_http_modsecurity);
-    request_rec *req = ctx->req;
-
-    // Load request to request rec
-    if (ngx_http_modsecurity_load_request(r) != NGX_OK ||
-            ngx_http_modsecurity_load_headers_in(r) != NGX_OK) {
-        return NGX_ERROR;
-    }
-
-    if (modsecIsRequestBodyAccessEnabled(req) && (r->headers_in.content_length || r->headers_in.chunked)) {
-        if (ngx_http_modsecurity_load_request_body(r) != NGX_OK) {
-            return NGX_ERROR;
-        }
-    }
-
-    ngx_thread_task_t *task = apr_thread_task_alloc(req->pool, sizeof(ngx_http_modsecurity_detection_thread_ctx_t));
-    if (task == NULL) {
-        return NGX_ERROR;
-    }
-
-    ngx_http_modsecurity_detection_thread_ctx_t *thread_ctx = task->ctx;
-    thread_ctx->connection = ctx->connection;
-    ctx->connection = NULL;
-    thread_ctx->req = ctx->req;
-    ctx->req = NULL;
-    thread_ctx->brigade = ctx->brigade;
-    ctx->brigade = NULL;
-
-    task->handler = ngx_http_modsecurity_detection_thread_func;
-    task->event.handler = ngx_http_modsecurity_detection_thread_completion;
-    task->event.data = thread_ctx;
-
-    ngx_thread_pool_t* thread_pool = ngx_thread_pool_get((ngx_cycle_t *)ngx_cycle, &thread_pool_name);
-    if (ngx_thread_task_post(thread_pool, task) != NGX_OK) {
-        return NGX_ERROR;
-    }
-
-    return NGX_OK;
-}
 
 static void
 ngx_http_modsecurity_body_handler(ngx_http_request_t *r)
@@ -820,17 +712,8 @@ ngx_http_modsecurity_handler(ngx_http_request_t *r)
         return NGX_DECLINED;
     }
 
-    /* When in detection mode, don't wait for background task to complete because it won't affect the request status */
-    if (cf->config->is_enabled == MODSEC_DETECTION_ONLY) {
-        if (ngx_http_modsecurity_detection_task_offload(r) != NGX_OK) {
-            return NGX_ERROR;
-        }
-
-        return NGX_DECLINED;
-    }
-
     ctx->thread_running = 1;
-    if (ngx_http_modsecurity_prevention_task_offload(r) != NGX_OK) {
+    if (ngx_http_modsecurity_task_offload(r) != NGX_OK) {
         return NGX_ERROR;
     }
 
@@ -877,9 +760,9 @@ ngx_http_modsecurity_create_ctx(ngx_http_request_t *r)
         ctx->connection = modsecNewConnection();
 
         /* fill apr_sockaddr_t */
-        asa = apr_palloc(ctx->connection->pool, sizeof(apr_sockaddr_t));
+        asa = ngx_palloc(r->pool, sizeof(apr_sockaddr_t));
         asa->pool = ctx->connection->pool;
-        asa->hostname = dup_ngx_str_to_apr(asa->pool, &r->connection->addr_text);
+        asa->hostname = (char *)ngx_pstrdup0(r->pool, &r->connection->addr_text);
         asa->servname = asa->hostname;
         asa->next = NULL;
         asa->salen = r->connection->socklen;
@@ -923,9 +806,7 @@ ngx_http_modsecurity_create_ctx(ngx_http_request_t *r)
 
     ctx->req = modsecNewRequest(ctx->connection, cf->config);
 
-    if (cf->config->is_enabled != MODSEC_DETECTION_ONLY) {
-        apr_table_setn(ctx->req->notes, NOTE_NGINX_REQUEST_CTX, (const char *)ctx);
-    }
+    apr_table_setn(ctx->req->notes, NOTE_NGINX_REQUEST_CTX, (const char *) ctx);
     apr_generate_random_bytes(salt, TXID_SIZE);
 
     txid = apr_pcalloc (ctx->req->pool, TXID_SIZE);

From 7526371c17f87ff75463e345311bf4a4bc450670 Mon Sep 17 00:00:00 2001
From: Vladimir Krivopalov <vladimir.krivopalov@gmail.com>
Date: Tue, 2 Apr 2019 14:47:09 -0700
Subject: [PATCH 29/58] Revert "Process request in background when in detection
 mode." (#108)

Let's give it more testing before rolling the fix out in production as
we've been hit badly with a bug in a similar fix for Nginx.

This reverts commit 2aa9412ae490d1f9b195ba2c150deeaa689a5514.
---
 iis/Makefile.win |   3 +-
 iis/mymodule.cpp | 154 ++++++-----------------------------------------
 iis/mymodule.h   |   8 +--
 3 files changed, 21 insertions(+), 144 deletions(-)

diff --git a/iis/Makefile.win b/iis/Makefile.win
index 740021d3e3..1e198f65c3 100644
--- a/iis/Makefile.win
+++ b/iis/Makefile.win
@@ -37,8 +37,7 @@ INCLUDES = -I. -I.. \
            -I..\apache2 \
            -I..\standalone \
            -I..\apache2\ag_mdb \
-           -I..\apache2\waf_lock \
-           -Iasio\asio\include
+           -I..\apache2\waf_lock
 
 # Enables support for SecRemoteRules and external resources.
 DEFS=$(DEFS) -DWITH_CURL -DWITH_REMOTE_RULES
diff --git a/iis/mymodule.cpp b/iis/mymodule.cpp
index 071a6ec914..6fbac98666 100644
--- a/iis/mymodule.cpp
+++ b/iis/mymodule.cpp
@@ -19,7 +19,6 @@
 #include <string>
 #include <cctype>
 #include <memory>
-#include <future>
 
 //  IIS7 Server API header file
 #include <Windows.h>
@@ -36,9 +35,6 @@
 
 #include "winsock2.h"
 
-#include "asio/packaged_task.hpp"
-#include "asio/post.hpp"
-
 // These helpers make sure that the underlying structures
 // are correctly released on any exit path due to RAII.
 using ConnRecPtr = std::shared_ptr<conn_rec>;
@@ -66,8 +62,6 @@ struct RequestStoredContext
     char* responseBuffer = nullptr;
     ULONGLONG responseLength = 0;
     ULONGLONG responsePosition = 0;
-    bool responseProcessingEnabled = false;
-    std::future<int> detectionProcessing;
 
     void CleanupStoredContext() override
     {
@@ -506,97 +500,6 @@ static HRESULT SaveRequestBodyToRequestRec(RequestStoredContext* rsc)
     return S_OK;
 }
 
-
-static apr_status_t ReadBodyCallback(request_rec *r, char *buf, unsigned int length, unsigned int *readcnt, int *is_eos)
-{
-    RequestStoredContext *rsc = RetrieveIISContext(r);
-
-    *readcnt = 0;
-
-    if (rsc == NULL)
-    {
-        *is_eos = 1;
-        return APR_SUCCESS;
-    }
-
-    IHttpContext *pHttpContext = rsc->httpContext;
-    IHttpRequest *pRequest = pHttpContext->GetRequest();
-
-    if (pRequest->GetRemainingEntityBytes() == 0)
-    {
-        *is_eos = 1;
-        return APR_SUCCESS;
-    }
-
-    HRESULT hr = pRequest->ReadEntityBody(buf, length, false, (DWORD *)readcnt, NULL);
-
-    if (FAILED(hr))
-    {
-        // End of data is okay.
-        if (ERROR_HANDLE_EOF != (hr & 0x0000FFFF))
-        {
-            // Set the error status.
-            rsc->provider->SetErrorStatus(hr);
-        }
-
-        *is_eos = 1;
-    }
-
-    return APR_SUCCESS;
-}
-
-static apr_status_t WriteBodyCallback(request_rec *r, char *buf, unsigned int length)
-{
-    RequestStoredContext *rsc = RetrieveIISContext(r);
-
-    if (!rsc || !rsc->requestRec)
-        return APR_SUCCESS;
-
-    IHttpContext *pHttpContext = rsc->httpContext;
-    IHttpRequest *pHttpRequest = pHttpContext->GetRequest();
-
-    auto lengthStr = std::to_string(length);
-
-    // Remove/Modify Transfer-Encoding header if "chunked" Encoding is set in the request. 
-    // This is to avoid sending both Content-Length and Chunked Transfer-Encoding in the request header.
-
-    USHORT ctcch = 0;
-    char *ct = (char *)pHttpRequest->GetHeader(HttpHeaderTransferEncoding, &ctcch);
-    if (ct)
-    {
-        char *ctz = ZeroTerminate(ct, ctcch, r->pool);
-        if (ctcch != 0)
-        {
-            if (0 == stricmp(ctz, "chunked"))
-            {
-                pHttpRequest->DeleteHeader(HttpHeaderTransferEncoding);
-            }
-        }
-    }
-
-    HRESULT hr = pHttpRequest->SetHeader(
-        HttpHeaderContentLength,
-        lengthStr.c_str(),
-        (USHORT)lengthStr.size(),
-        TRUE);
-
-    if (FAILED(hr))
-    {
-        // possible, but there's nothing we can do
-    }
-
-    // since we clean the APR pool at the end of OnSendRequest, we must get IIS-managed memory chunk
-    //
-    void *reqbuf = pHttpContext->AllocateRequestMemory(length);
-
-    memcpy(reqbuf, buf, length);
-
-    pHttpRequest->InsertEntityBody(reqbuf, length);
-
-    return APR_SUCCESS;
-}
-
-
 REQUEST_NOTIFICATION_STATUS
 CMyHttpModule::OnSendResponse(
     IN IHttpContext * pHttpContext,
@@ -606,18 +509,12 @@ CMyHttpModule::OnSendResponse(
     RequestStoredContext* rsc = dynamic_cast<RequestStoredContext*>(pHttpContext->GetModuleContextContainer()->GetModuleContext(g_pModuleContext));
 
     CriticalSectionLock lock{cs};
-    // here we must check if response body processing is enabled
-    //
-    if (!rsc || !rsc->requestRec || rsc->responseBuffer != nullptr || !rsc->responseProcessingEnabled)
-    {
-        goto Exit;
-    }
-
-    // If we have offloaded request processing to the thread pool
-    // we need to wait for its completion before we can proceed
-    if (rsc->detectionProcessing.valid()) {
-        rsc->detectionProcessing.get();
-    }
+	// here we must check if response body processing is enabled
+	//
+	if(!rsc || !rsc->requestRec || rsc->responseBuffer != nullptr || !modsecIsResponseBodyAccessEnabled(rsc->requestRec.get()))
+	{
+		goto Exit;
+	}
 
     HRESULT hr = S_OK;
     IHttpResponse *pHttpResponse = NULL;
@@ -968,8 +865,7 @@ CMyHttpModule::OnBeginRequest(IHttpContext* httpContext, IHttpEventProvider* pro
     rsc->connRec = connRec;
     rsc->requestRec = requestRec;
     rsc->httpContext = httpContext;
-    rsc->provider = provider;
-    rsc->responseProcessingEnabled = (config->config->resbody_access == 1);
+    rsc->provider = provider;	
     RequestStoredContext* context = rsc.get();
 
     StoreIISContext(r, rsc.get());
@@ -1208,35 +1104,19 @@ CMyHttpModule::OnBeginRequest(IHttpContext* httpContext, IHttpEventProvider* pro
         return RQ_NOTIFICATION_FINISH_REQUEST;
     }
 
-    if (config->config->is_enabled == MODSEC_DETECTION_ONLY)
-    {
-        // We post the processing task to the thread pool to happen in the background.
-        // We store the future to track and wait for this processing in case if we also
-        // need to process the response because we need request processing to finish
-        // before we can start with the response.
-        context->detectionProcessing = asio::post(threadPool,
-            std::packaged_task<int()> {
-            [connRec, requestRec] {
-                return modsecProcessRequest(requestRec.get());
-            }
-        });
-    }
-    else
-    {
-        lock.unlock();
-        int status = modsecProcessRequest(r);
-        lock.lock();
+    lock.unlock();
+    int status = modsecProcessRequest(r);
+    lock.lock();
 
-        if (status != DECLINED)
-        {
-            httpContext->GetResponse()->SetStatus(status, "ModSecurity Action");
-            httpContext->SetRequestHandled();
+	if(status != DECLINED)
+	{
+		httpContext->GetResponse()->SetStatus(status, "ModSecurity Action");
+		httpContext->SetRequestHandled();
 
-            return RQ_NOTIFICATION_FINISH_REQUEST;
-        }
-    }
+        return RQ_NOTIFICATION_FINISH_REQUEST;
+	}
 
-    return RQ_NOTIFICATION_CONTINUE;
+	return RQ_NOTIFICATION_CONTINUE;
 }
 
 apr_status_t ReadResponseCallback(request_rec *r, char *buf, unsigned int length, unsigned int *readcnt, int *is_eos)
diff --git a/iis/mymodule.h b/iis/mymodule.h
index 83d7adb697..c14180965c 100644
--- a/iis/mymodule.h
+++ b/iis/mymodule.h
@@ -12,10 +12,8 @@
 * directly using the email address security@modsecurity.org.
 */
 
-#pragma once
-
-#define ASIO_STANDALONE
-#include "asio/thread_pool.hpp"
+#ifndef __MY_MODULE_H__
+#define __MY_MODULE_H__
 
 #include "critical_section.h"
 #include "event_logger.h"
@@ -48,8 +46,8 @@ class CMyHttpModule
 private:
     CriticalSection cs;
     EventLogger logger;
-    asio::thread_pool threadPool;
     DWORD pageSize = 0;
     bool statusCallAlreadySent = false;
 };
 
+#endif

From bd2a25cd8e116f5982d21071e5941fd8b1232439 Mon Sep 17 00:00:00 2001
From: Vladimir Krivopalov <vladimir.krivopalov@gmail.com>
Date: Wed, 30 Jan 2019 18:34:26 -0800
Subject: [PATCH 30/58] Make detection mode run fully in background and not
 block Nginx requests

When ModSecurity runs in the detection-only mode, a request does not
have to be blocked awaiting to be processed and can be transmitted
immediately because the result of executing rules on it does not affect
its status.
This allows to minimize the latency overhead.

To achieve this, the processing is offloaded to a thread pool and runs
independently from the main request processing by Nginx.

Signed-off-by: Vladimir Krivopalov <vlkrivop@microsoft.com>
---
 nginx/modsecurity/apr_bucket_nginx.c     |  10 +-
 nginx/modsecurity/apr_bucket_nginx.h     |   9 +-
 nginx/modsecurity/ngx_http_modsecurity.c | 218 +++++++++++++++++++----
 3 files changed, 187 insertions(+), 50 deletions(-)

diff --git a/nginx/modsecurity/apr_bucket_nginx.c b/nginx/modsecurity/apr_bucket_nginx.c
index 17906fe355..9ed7cbbbcb 100644
--- a/nginx/modsecurity/apr_bucket_nginx.c
+++ b/nginx/modsecurity/apr_bucket_nginx.c
@@ -22,7 +22,6 @@ typedef struct apr_bucket_nginx {
 
 /* ngx_buf_t to apr_bucket */
 apr_bucket * apr_bucket_nginx_create(ngx_buf_t *buf,
-                                     apr_pool_t *p,
                                      apr_bucket_alloc_t *list)
 {
 
@@ -31,11 +30,10 @@ apr_bucket * apr_bucket_nginx_create(ngx_buf_t *buf,
     APR_BUCKET_INIT(b); /* link */
     b->free = apr_bucket_free;
     b->list = list;
-    return apr_bucket_nginx_make(b, buf, p);
+    return apr_bucket_nginx_make(b, buf);
 }
 
-apr_bucket * apr_bucket_nginx_make(apr_bucket *b, ngx_buf_t *buf,
-                                   apr_pool_t *pool)
+apr_bucket * apr_bucket_nginx_make(apr_bucket *b, ngx_buf_t *buf)
 {
     apr_bucket_nginx *n;
 
@@ -93,11 +91,11 @@ static void nginx_bucket_destroy(void *data)
 
 
 ngx_int_t
-copy_chain_to_brigade(ngx_chain_t *chain, apr_bucket_brigade *bb, ngx_pool_t *pool, ngx_int_t last_buf) {
+copy_chain_to_brigade(ngx_chain_t *chain, apr_bucket_brigade *bb, ngx_int_t last_buf) {
     apr_bucket         *e;
 
     while (chain) {
-        e = ngx_buf_to_apr_bucket(chain->buf, bb->p, bb->bucket_alloc);
+        e = ngx_buf_to_apr_bucket(chain->buf, bb->bucket_alloc);
         if (e == NULL) {
             return NGX_ERROR;
         }
diff --git a/nginx/modsecurity/apr_bucket_nginx.h b/nginx/modsecurity/apr_bucket_nginx.h
index a4ce631389..b6b5762770 100644
--- a/nginx/modsecurity/apr_bucket_nginx.h
+++ b/nginx/modsecurity/apr_bucket_nginx.h
@@ -2,13 +2,10 @@
 #include <ngx_core.h>
 #include "apr_buckets.h"
 
-apr_bucket * apr_bucket_nginx_create(ngx_buf_t *buf,
-                                     apr_pool_t *p,
-                                     apr_bucket_alloc_t *list);
+apr_bucket * apr_bucket_nginx_create(ngx_buf_t *buf, apr_bucket_alloc_t *list);
 
-apr_bucket * apr_bucket_nginx_make(apr_bucket *e, ngx_buf_t *buf,
-                                   apr_pool_t *pool);
+apr_bucket * apr_bucket_nginx_make(apr_bucket *e, ngx_buf_t *buf);
 
 #define ngx_buf_to_apr_bucket apr_bucket_nginx_create
 
-ngx_int_t copy_chain_to_brigade(ngx_chain_t *chain, apr_bucket_brigade *bb, ngx_pool_t *pool, ngx_int_t last_buf);
+ngx_int_t copy_chain_to_brigade(ngx_chain_t *chain, apr_bucket_brigade *bb, ngx_int_t last_buf);
diff --git a/nginx/modsecurity/ngx_http_modsecurity.c b/nginx/modsecurity/ngx_http_modsecurity.c
index 2736390595..7efcf0527b 100644
--- a/nginx/modsecurity/ngx_http_modsecurity.c
+++ b/nginx/modsecurity/ngx_http_modsecurity.c
@@ -52,8 +52,14 @@ typedef struct {
 
 typedef struct {
     ngx_http_request_t *r;
-} ngx_http_modsecurity_thread_ctx_t;
+} ngx_http_modsecurity_prevention_thread_ctx_t;
 
+typedef struct {
+    conn_rec            *connection;
+    request_rec         *req;
+
+    apr_bucket_brigade  *brigade;
+} ngx_http_modsecurity_detection_thread_ctx_t;
 
 /*
 ** Module's registred function/handlers.
@@ -149,6 +155,34 @@ ngx_pstrdup0(ngx_pool_t *pool, ngx_str_t *src)
 }
 
 
+static inline char *
+dup_ngx_str_to_apr(apr_pool_t *pool, ngx_str_t *src)
+{
+    return apr_pstrmemdup(pool, (char *)src->data, src->len);
+}
+
+/*
+ * Helper to allocate a thread task using an Apache pool.
+ * This is useful when the background task can outlive the Nginx request
+ * it is initiated for.
+ */
+ngx_thread_task_t *
+apr_thread_task_alloc(apr_pool_t *pool, size_t size)
+{
+    ngx_thread_task_t  *task;
+
+    // The logic of ngx_thread_task_post relies on the task to be zero-initialized.
+    // That is why we use apr_pcalloc here.
+    task = apr_pcalloc(pool, sizeof(ngx_thread_task_t) + size);
+    if (task == NULL) {
+        return NULL;
+    }
+
+    task->ctx = task + 1;
+
+    return task;
+}
+
 static inline int
 ngx_http_modsecurity_method_number(unsigned int nginx)
 {
@@ -193,6 +227,11 @@ ngx_http_modsecurity_method_number(unsigned int nginx)
     return MultiplyDeBruijnBitPosition[((uint32_t)((nginx & -nginx) * 0x077CB531U)) >> 27];
 }
 
+/*
+ * Use APR pool for all allocations because they should not depend on Nginx request pool.
+ * In case of detection mode, processing will take place entirely in background and may last
+ * longer than the original request lives.
+ */
 static ngx_inline ngx_int_t
 ngx_http_modsecurity_load_request(ngx_http_request_t *r)
 {
@@ -210,7 +249,7 @@ ngx_http_modsecurity_load_request(ngx_http_request_t *r)
     req = ctx->req;
 
     /* request line */
-    req->method = (char *)ngx_pstrdup0(r->pool, &r->method_name);
+    req->method = dup_ngx_str_to_apr(req->pool, &r->method_name);
 
     /* TODO: how to use ap_method_number_of ?
      * req->method_number = ap_method_number_of(req->method);
@@ -223,18 +262,18 @@ ngx_http_modsecurity_load_request(ngx_http_request_t *r)
         return NGX_ERROR;
     }
 
-    req->filename = (char *) path.data;
+    req->filename = dup_ngx_str_to_apr(req->pool, &path);
     req->path_info = req->filename;
 
-    req->args = (char *)ngx_pstrdup0(r->pool, &r->args);
+    req->args = dup_ngx_str_to_apr(req->pool, &r->args);
 
     req->proto_num = r->http_major *1000 + r->http_minor;
-    req->protocol = (char *)ngx_pstrdup0(r->pool, &r->http_protocol);
+    req->protocol = dup_ngx_str_to_apr(req->pool, &r->http_protocol);
     req->request_time = apr_time_make(r->start_sec, r->start_msec);
-    req->the_request = (char *)ngx_pstrdup0(r->pool, &r->request_line);
+    req->the_request = dup_ngx_str_to_apr(req->pool, &r->request_line);
 
-    req->unparsed_uri = (char *)ngx_pstrdup0(r->pool, &r->unparsed_uri);
-    req->uri = (char *)ngx_pstrdup0(r->pool, &r->uri);
+    req->unparsed_uri = dup_ngx_str_to_apr(req->pool, &r->unparsed_uri);
+    req->uri = dup_ngx_str_to_apr(req->pool, &r->uri);
 
     req->parsed_uri.scheme = "http";
 
@@ -244,7 +283,7 @@ ngx_http_modsecurity_load_request(ngx_http_request_t *r)
     }
 #endif
 
-    req->parsed_uri.path = (char *)ngx_pstrdup0(r->pool, &r->uri);
+    req->parsed_uri.path = dup_ngx_str_to_apr(req->pool, &r->uri);
     req->parsed_uri.is_initialized = 1;
 
     switch (r->connection->local_sockaddr->sa_family) {
@@ -269,18 +308,16 @@ ngx_http_modsecurity_load_request(ngx_http_request_t *r)
     }
 
     req->parsed_uri.port = port;
-    req->parsed_uri.port_str = ngx_pnalloc(r->pool, sizeof("65535"));
+    req->parsed_uri.port_str = apr_palloc(req->pool, sizeof("65535"));
     (void) ngx_sprintf((u_char *)req->parsed_uri.port_str, "%ui%c", port, '\0');
 
     req->parsed_uri.query = r->args.len ? req->args : NULL;
     req->parsed_uri.dns_looked_up = 0;
     req->parsed_uri.dns_resolved = 0;
 
-    // req->parsed_uri.password = (char *)ngx_pstrdup0(r->pool, &r->headers_in.passwd);
-    // req->parsed_uri.user = (char *)ngx_pstrdup0(r->pool, &r->headers_in.user);
-    req->parsed_uri.fragment = (char *)ngx_pstrdup0(r->pool, &r->exten);
+    req->parsed_uri.fragment = dup_ngx_str_to_apr(req->pool, &r->exten);
 
-    req->hostname = (char *)ngx_pstrdup0(r->pool, (ngx_str_t *)&ngx_cycle->hostname);
+    req->hostname = dup_ngx_str_to_apr(req->pool, (ngx_str_t *)&ngx_cycle->hostname);
 
     req->header_only = r->header_only ? r->header_only : (r->method == NGX_HTTP_HEAD);
 
@@ -319,7 +356,15 @@ ngx_http_modsecurity_load_headers_in(ngx_http_request_t *r)
             i = 0;
         }
 
-        apr_table_setn(req->headers_in, (char *)h[i].key.data, (char *)h[i].value.data);
+        const char *key = dup_ngx_str_to_apr(req->pool, &h[i].key);
+        if (key == NULL) {
+            return NGX_ERROR;
+        }
+        const char *value = dup_ngx_str_to_apr(req->pool, &h[i].value);
+        if (value == NULL) {
+            return NGX_ERROR;
+        }
+        apr_table_setn(req->headers_in, key, value);
         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                        "ModSecurity: load headers in: \"%V: %V\"",
                        &h[i].key, &h[i].value);
@@ -335,14 +380,14 @@ ngx_http_modsecurity_load_headers_in(ngx_http_request_t *r)
     lang = apr_table_get(ctx->req->headers_in, "Content-Languages");
     if(lang != NULL)
     {
-        ctx->req->content_languages = apr_array_make(ctx->req->pool, 1, sizeof(const char *));
+        ctx->req->content_languages = apr_array_make(req->pool, 1, sizeof(const char *));
 
-        *(const char **)apr_array_push(ctx->req->content_languages) = lang;
+        *(const char **)apr_array_push(req->content_languages) = lang;
     }
 
     req->ap_auth_type = (char *)apr_table_get(req->headers_in, "Authorization");
 
-    req->user = (char *)ngx_pstrdup0(r->pool, &r->headers_in.user);
+    req->user = dup_ngx_str_to_apr(req->pool, &r->headers_in.user);
 
 
 
@@ -363,10 +408,10 @@ ngx_http_modsecurity_load_request_body(ngx_http_request_t *r)
 
     if (r->request_body == NULL || r->request_body->bufs == NULL) {
 
-        return copy_chain_to_brigade(NULL, ctx->brigade, r->pool, 1);
+        return copy_chain_to_brigade(NULL, ctx->brigade, 1);
     }
 
-    if (copy_chain_to_brigade(r->request_body->bufs, ctx->brigade, r->pool, 1) != NGX_OK) {
+    if (copy_chain_to_brigade(r->request_body->bufs, ctx->brigade, 1) != NGX_OK) {
         return NGX_ERROR;
     }
 
@@ -374,10 +419,8 @@ ngx_http_modsecurity_load_request_body(ngx_http_request_t *r)
 }
 
 static ngx_inline ngx_int_t
-ngx_http_modsecurity_status(ngx_http_request_t *r, int status)
+ngx_http_modsecurity_status(int status)
 {
-    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "ModSecurity: status %d", status);
-
     if (status == DECLINED || status == APR_SUCCESS) {
         return NGX_DECLINED;
     }
@@ -558,11 +601,11 @@ ngx_http_modsecurity_init_process(ngx_cycle_t *cycle)
 
 
 static void
-ngx_http_modsecurity_thread_func(void *data, ngx_log_t *log)
+ngx_http_modsecurity_prevention_thread_func(void *data, ngx_log_t *log)
 {
     // Executed in a separate thread
 
-    ngx_http_modsecurity_thread_ctx_t *thread_ctx = data;
+    ngx_http_modsecurity_prevention_thread_ctx_t *thread_ctx = data;
     ngx_http_request_t *r = thread_ctx->r;
 
     ngx_http_modsecurity_ctx_t* mod_ctx = ngx_http_get_module_ctx(r, ngx_http_modsecurity);
@@ -576,7 +619,9 @@ ngx_http_modsecurity_thread_func(void *data, ngx_log_t *log)
     }
 
     // Processing request headers
-    ngx_int_t rc = ngx_http_modsecurity_status(r, modsecProcessRequestHeaders(mod_ctx->req));
+    ngx_int_t rc = modsecProcessRequestHeaders(mod_ctx->req);
+    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "ModSecurity process headers: status %d", rc);
+    rc = ngx_http_modsecurity_status(rc);
 
     if (rc != NGX_DECLINED) {
         mod_ctx->status_code = rc;
@@ -596,13 +641,14 @@ ngx_http_modsecurity_thread_func(void *data, ngx_log_t *log)
     }
 
     // The name of modsecProcessRequestBody is a bit misleading. This function call is needed even to just process GET args.
-    rc = ngx_http_modsecurity_status(r, modsecProcessRequestBody(mod_ctx->req));
-    mod_ctx->status_code = rc;
+    rc = modsecProcessRequestBody(mod_ctx->req);
+    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "ModSecurity process body: status %d", rc);
+    mod_ctx->status_code = ngx_http_modsecurity_status(rc);
 }
 
 
 static void
-ngx_http_modsecurity_thread_completion(ngx_event_t *ev)
+ngx_http_modsecurity_prevention_thread_completion(ngx_event_t *ev)
 {
     // executed in nginx event loop after thread task is done, in order to pick up and continue processing request
 
@@ -619,13 +665,52 @@ ngx_http_modsecurity_thread_completion(ngx_event_t *ev)
 }
 
 
+static void
+ngx_http_modsecurity_detection_thread_func(void *data, ngx_log_t *log)
+{
+    // Executed in a separate thread
+    ngx_http_modsecurity_detection_thread_ctx_t *thread_ctx = data;
+
+    // Processing request headers
+    ngx_int_t rc = ngx_http_modsecurity_status(modsecProcessRequestHeaders(thread_ctx->req));
+    if (rc != NGX_DECLINED) {
+        return;
+    }
+
+    if (modsecContextState(thread_ctx->req) == MODSEC_DISABLED) {
+        return;
+    }
+
+    // The name of modsecProcessRequestBody is a bit misleading. This function call is needed even to just process GET args.
+    modsecProcessRequestBody(thread_ctx->req);
+}
+
+
+static void
+ngx_http_modsecurity_detection_thread_completion(ngx_event_t *ev)
+{
+    // executed in nginx event loop after thread task is done, in order to pick up and continue processing request
+    ngx_http_modsecurity_detection_thread_ctx_t *ctx = ev->data;
+
+    request_rec *req = ctx->req;
+    conn_rec *connection = ctx->connection;
+
+    if (req != NULL) {
+        modsecFinishRequest(req);
+    }
+    if (connection != NULL) {
+        modsecFinishConnection(connection);
+    }
+}
+
+
 static ngx_int_t
-ngx_http_modsecurity_task_offload(ngx_http_request_t *r)
+ngx_http_modsecurity_prevention_task_offload(ngx_http_request_t *r)
 {
-    ngx_http_modsecurity_thread_ctx_t *thread_ctx;
+    ngx_http_modsecurity_prevention_thread_ctx_t *thread_ctx;
     ngx_thread_task_t *task;
 
-    task = ngx_thread_task_alloc(r->pool, sizeof(ngx_http_modsecurity_thread_ctx_t));
+    task = ngx_thread_task_alloc(r->pool, sizeof(ngx_http_modsecurity_prevention_thread_ctx_t));
     if (task == NULL) {
         return NGX_ERROR;
     }
@@ -633,8 +718,8 @@ ngx_http_modsecurity_task_offload(ngx_http_request_t *r)
     thread_ctx = task->ctx;
     thread_ctx->r = r;
 
-    task->handler = ngx_http_modsecurity_thread_func;
-    task->event.handler = ngx_http_modsecurity_thread_completion;
+    task->handler = ngx_http_modsecurity_prevention_thread_func;
+    task->event.handler = ngx_http_modsecurity_prevention_thread_completion;
     task->event.data = r;
 
     ngx_thread_pool_t* thread_pool = ngx_thread_pool_get((ngx_cycle_t *)ngx_cycle, &thread_pool_name);
@@ -648,6 +733,52 @@ ngx_http_modsecurity_task_offload(ngx_http_request_t *r)
     return NGX_OK;
 }
 
+static ngx_int_t
+ngx_http_modsecurity_detection_task_offload(ngx_http_request_t *r)
+{
+    ngx_http_modsecurity_ctx_t *ctx = ngx_http_get_module_ctx(r, ngx_http_modsecurity);
+    request_rec *req = ctx->req;
+
+    // Load request to request rec
+    if (ngx_http_modsecurity_load_request(r) != NGX_OK ||
+            ngx_http_modsecurity_load_headers_in(r) != NGX_OK) {
+        return NGX_ERROR;
+    }
+
+    if (modsecIsRequestBodyAccessEnabled(req) && (r->headers_in.content_length || r->headers_in.chunked)) {
+        if (ngx_http_modsecurity_load_request_body(r) != NGX_OK) {
+            return NGX_ERROR;
+        }
+    }
+
+    ngx_thread_task_t *task = apr_thread_task_alloc(req->pool, sizeof(ngx_http_modsecurity_detection_thread_ctx_t));
+    if (task == NULL) {
+        return NGX_ERROR;
+    }
+
+    ngx_http_modsecurity_detection_thread_ctx_t *thread_ctx = task->ctx;
+    thread_ctx->connection = ctx->connection;
+    thread_ctx->req = ctx->req;
+    thread_ctx->brigade = ctx->brigade;
+
+    task->handler = ngx_http_modsecurity_detection_thread_func;
+    task->event.handler = ngx_http_modsecurity_detection_thread_completion;
+    task->event.data = thread_ctx;
+
+    ngx_thread_pool_t* thread_pool = ngx_thread_pool_get((ngx_cycle_t *)ngx_cycle, &thread_pool_name);
+    if (ngx_thread_task_post(thread_pool, task) != NGX_OK) {
+        return NGX_ERROR;
+    }
+
+    // We need to reset these so they don't get cleaned up when the request is complete.
+    // This is important as the background task can outlive the request and we need to
+    // make sure the memory it uses is still alive.
+    ctx->connection = NULL;
+    ctx->req = NULL;
+    ctx->brigade = NULL;
+
+    return NGX_OK;
+}
 
 static void
 ngx_http_modsecurity_body_handler(ngx_http_request_t *r)
@@ -712,8 +843,17 @@ ngx_http_modsecurity_handler(ngx_http_request_t *r)
         return NGX_DECLINED;
     }
 
+    /* When in detection mode, don't wait for background task to complete because it won't affect the request status */
+    if (cf->config->is_enabled == MODSEC_DETECTION_ONLY) {
+        if (ngx_http_modsecurity_detection_task_offload(r) != NGX_OK) {
+            return NGX_ERROR;
+        }
+
+        return NGX_DECLINED;
+    }
+
     ctx->thread_running = 1;
-    if (ngx_http_modsecurity_task_offload(r) != NGX_OK) {
+    if (ngx_http_modsecurity_prevention_task_offload(r) != NGX_OK) {
         return NGX_ERROR;
     }
 
@@ -760,9 +900,9 @@ ngx_http_modsecurity_create_ctx(ngx_http_request_t *r)
         ctx->connection = modsecNewConnection();
 
         /* fill apr_sockaddr_t */
-        asa = ngx_palloc(r->pool, sizeof(apr_sockaddr_t));
+        asa = apr_palloc(ctx->connection->pool, sizeof(apr_sockaddr_t));
         asa->pool = ctx->connection->pool;
-        asa->hostname = (char *)ngx_pstrdup0(r->pool, &r->connection->addr_text);
+        asa->hostname = dup_ngx_str_to_apr(asa->pool, &r->connection->addr_text);
         asa->servname = asa->hostname;
         asa->next = NULL;
         asa->salen = r->connection->socklen;
@@ -806,7 +946,9 @@ ngx_http_modsecurity_create_ctx(ngx_http_request_t *r)
 
     ctx->req = modsecNewRequest(ctx->connection, cf->config);
 
-    apr_table_setn(ctx->req->notes, NOTE_NGINX_REQUEST_CTX, (const char *) ctx);
+    if (cf->config->is_enabled != MODSEC_DETECTION_ONLY) {
+        apr_table_setn(ctx->req->notes, NOTE_NGINX_REQUEST_CTX, (const char *)ctx);
+    }
     apr_generate_random_bytes(salt, TXID_SIZE);
 
     txid = apr_pcalloc (ctx->req->pool, TXID_SIZE);

From 7f0eced5bc2e83bf2c0adbf935004a8c4e5cc5af Mon Sep 17 00:00:00 2001
From: Allan Boll <allanbo@microsoft.com>
Date: Tue, 16 Apr 2019 14:19:57 -0700
Subject: [PATCH 31/58] ModSec on IIS: Block on bad config (#111)

* ModSec on IIS: Block on bad config
---
 iis/moduleconfig.h |  2 ++
 iis/mymodule.cpp   | 23 +++++++++++++++++++----
 2 files changed, 21 insertions(+), 4 deletions(-)

diff --git a/iis/moduleconfig.h b/iis/moduleconfig.h
index e4f149b347..e7da87a4e6 100644
--- a/iis/moduleconfig.h
+++ b/iis/moduleconfig.h
@@ -71,6 +71,8 @@ class MODSECURITY_STORED_CONTEXT : public IHttpStoredContext
 
     directory_config* config = nullptr;
 
+    bool configLoadingFailed = false;
+
 private:
     HRESULT 
     GetBooleanPropertyValue( 
diff --git a/iis/mymodule.cpp b/iis/mymodule.cpp
index 6fbac98666..8b8901cb35 100644
--- a/iis/mymodule.cpp
+++ b/iis/mymodule.cpp
@@ -798,7 +798,9 @@ CMyHttpModule::OnBeginRequest(IHttpContext* httpContext, IHttpEventProvider* pro
     HRESULT hr = MODSECURITY_STORED_CONTEXT::GetConfig(httpContext, &config);
     if (FAILED(hr))
     {
-        return RQ_NOTIFICATION_CONTINUE;
+        httpContext->GetResponse()->SetStatus(500, "WAF internal error. Unable to get config.");
+        httpContext->SetRequestHandled();
+        return RQ_NOTIFICATION_FINISH_REQUEST;
     }
 
     // If module is disabled, don't go any further
@@ -808,6 +810,19 @@ CMyHttpModule::OnBeginRequest(IHttpContext* httpContext, IHttpEventProvider* pro
         return RQ_NOTIFICATION_CONTINUE;
     }
 
+    auto reportConfigurationError = [config, httpContext] {
+        config->configLoadingFailed = true;
+        httpContext->GetResponse()->SetStatus(500, "WAF internal error. Invalid configuration.");
+        httpContext->SetRequestHandled();
+        return RQ_NOTIFICATION_FINISH_REQUEST;
+    };
+
+    // If we previously failed to load the config, don't spam the event log by trying and failing again
+    if (config->configLoadingFailed)
+    {
+        return reportConfigurationError();
+    }
+
     if (config->config == nullptr)
     {
         char *path;
@@ -816,7 +831,7 @@ CMyHttpModule::OnBeginRequest(IHttpContext* httpContext, IHttpEventProvider* pro
         hr = config->GlobalWideCharToMultiByte(config->GetPath(), wcslen(config->GetPath()), &path, &pathlen);
         if (FAILED(hr))
         {
-            return RQ_NOTIFICATION_FINISH_REQUEST;
+            return reportConfigurationError();
         }
 
         config->config = modsecGetDefaultConfig();
@@ -829,7 +844,7 @@ CMyHttpModule::OnBeginRequest(IHttpContext* httpContext, IHttpEventProvider* pro
         if (FAILED(hr))
         {
             delete path;
-            return RQ_NOTIFICATION_FINISH_REQUEST;
+            return reportConfigurationError();
         }
 
         if (path[0] != 0)
@@ -841,7 +856,7 @@ CMyHttpModule::OnBeginRequest(IHttpContext* httpContext, IHttpEventProvider* pro
                 WriteEventViewerLog(err, EVENTLOG_ERROR_TYPE);
                 delete apppath;
                 delete path;
-                return RQ_NOTIFICATION_CONTINUE;
+                return reportConfigurationError();
             }
 
             modsecReportRemoteLoadedRules();

From 5f57ea44dcf3d99954d60dbb6f540dbcb8804c3c Mon Sep 17 00:00:00 2001
From: Yanshu <yanshu.zhao7@gmail.com>
Date: Thu, 18 Apr 2019 16:03:48 -0700
Subject: [PATCH 32/58] replace protobuf with jsoncons, and print pretty json
 (#110)

---
 apache2/Makefile.am                         |  13 ---
 apache2/re_operators.c                      |   5 +-
 apache2/waf_logging/waf_format.proto        |  38 -------
 apache2/waf_logging/waf_log_util.cc         | 104 ++++----------------
 apache2/waf_logging/waf_log_util_internal.h |  57 ++++++++++-
 configure.ac                                |  16 ---
 docker/Dockerfile                           |  13 +--
 nginx/modsecurity/config.in                 |   6 +-
 standalone/Makefile.am                      |   1 -
 9 files changed, 84 insertions(+), 169 deletions(-)
 mode change 100644 => 100755 apache2/re_operators.c
 delete mode 100755 apache2/waf_logging/waf_format.proto
 mode change 100644 => 100755 apache2/waf_logging/waf_log_util_internal.h
 mode change 100644 => 100755 docker/Dockerfile

diff --git a/apache2/Makefile.am b/apache2/Makefile.am
index 9c3de4c515..cdedd86e46 100644
--- a/apache2/Makefile.am
+++ b/apache2/Makefile.am
@@ -1,17 +1,9 @@
 pkglibdir = $(prefix)/lib
 pkglib_LTLIBRARIES = mod_security2.la
 
-PROTOS         = $(waf_logging/waf_format.proto)
-PROTO_OBJS     = $(PROTOS:.proto=.pb.o)
-
-PBSRCS   = $(waf_logging/waf_format.proto)
-PBOBJS   = $(PROTOS:.proto=.pb.o)
-PBGENS   = $(PROTOS:.proto=.pb.cc) $(PROTOS:.proto=.pb.h)
-
 mod_security2_la_SOURCES = acmp.c \
     ag_mdb/murmur3.c \
     ag_mdb/ag_mdb.cpp \
-    waf_logging/waf_format.pb.cc \
     waf_logging/waf_log_util.cc \
     waf_lock/waf_lock.cpp \
     apache2_config.c \
@@ -203,8 +195,3 @@ install-exec-hook: $(pkglib_LTLIBRARIES)
 	done
 endif
 
-%.pb.cc: %.proto
-	protoc --cpp_out=. $<
-
-%.pb.o : %.pb.cc
-	$(CXX) $(CXX_FLAGS) -c -o $@ $<
\ No newline at end of file
diff --git a/apache2/re_operators.c b/apache2/re_operators.c
old mode 100644
new mode 100755
index b6d1c03c94..521dcfc044
--- a/apache2/re_operators.c
+++ b/apache2/re_operators.c
@@ -1178,8 +1178,11 @@ static int msre_op_rx_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, c
 
     if (rc != PCRE_ERROR_NOMATCH) { /* Match. */
         /* We no longer escape the pattern here as it is done when logging */
+#ifdef WAF_JSON_LOGGING_ENABLE
+        char *pattern = apr_pstrdup(msr->mp, regex->pattern ? regex->pattern : "<Unknown Match>");
+#else
         char *pattern = apr_pstrdup(msr->mp, log_escape(msr->mp, regex->pattern ? regex->pattern : "<Unknown Match>"));
-
+#endif
         /* This message will be logged. */
         if (strlen(pattern) > 252) {
             *error_msg = apr_psprintf(msr->mp, "Pattern match \"%.252s ...\" at %s.",
diff --git a/apache2/waf_logging/waf_format.proto b/apache2/waf_logging/waf_format.proto
deleted file mode 100755
index bb01e531b0..0000000000
--- a/apache2/waf_logging/waf_format.proto
+++ /dev/null
@@ -1,38 +0,0 @@
-syntax = "proto2";
-
-package waf_format;
-
-message Details {
-  optional string message = 1;
-  optional string data = 2;
-  optional string file = 3;
-  optional string line = 4;
-}
-
-
-message Properties {
-  optional string instanceId = 1;
-  optional string clientIp = 2;
-  optional string clientPort = 3;
-  optional string requestUri = 4;
-  optional string ruleSetType = 5;
-  optional string ruleSetVersion = 6;
-  optional string ruleId = 7;
-  optional string message = 8;
-  optional string action = 9;
-
-  enum SiteType {
-    Global = 0;
-  }
-  optional SiteType site = 10;
-  optional Details details = 11;
-  optional string hostname = 12;
-  optional string transactionId = 13;
-}
-
-message Waf_Format {
-  optional string resourceId = 1;
-  optional string operationName = 2;
-  optional string category = 3;
-  optional Properties properties = 4;
-}
diff --git a/apache2/waf_logging/waf_log_util.cc b/apache2/waf_logging/waf_log_util.cc
index c0a78246d5..3423c4d24a 100755
--- a/apache2/waf_logging/waf_log_util.cc
+++ b/apache2/waf_logging/waf_log_util.cc
@@ -5,52 +5,13 @@ using namespace std;
 unordered_map<int, bool> appgw_ruleid_hash;
 
 // This function fills in a waf format message based on modsec input.
-void set_waf_format(waf_format::Waf_Format* waf_format, char* resourceId, char* operationName, char* category, char* instanceId, char* clientIP, char* clientPort, const char* requestUri, char* ruleSetType, char* ruleSetVersion, char* ruleId, char* messages, int action, int site, char* details_messages, char* details_data, char* details_file, char* details_line, const char* hostname, char* waf_unique_id) {
-    waf_format::Properties *properties;
-    waf_format::Details *details;
+string get_json_log_message(char* resourceId, char* operationName, char* category, char* instanceId, char* clientIP, char* clientPort, const char* requestUri, char* ruleSetType, char* ruleSetVersion, char* ruleId, char* messages, int action, int site, char* details_messages, char* details_data, char* details_file, char* details_line, const char* hostname, char* waf_unique_id) {
+    string action_str;
+    string message_str;
+    string site_str;
 
-    properties = waf_format->mutable_properties();
-    details = properties->mutable_details();
-
-    if (resourceId != NULL) {
-        waf_format->set_resourceid(resourceId);
-    }
-
-    if (operationName != NULL) {
-        waf_format->set_operationname(operationName);
-    }
-
-    if (category != NULL) {
-        waf_format->set_category(category);
-    }
-
-    if (instanceId != NULL) {
-        properties->set_instanceid(instanceId);
-    }
-
-    if (clientIP != NULL) {
-        properties->set_clientip(clientIP);
-    }
-    
-    if (clientPort != NULL) {
-        properties->set_clientport(clientPort);
-    }
-    
-    if (requestUri != NULL) {
-        properties->set_requesturi(requestUri);
-    }
-    
-    if (ruleSetType != NULL) {
-        properties->set_rulesettype(ruleSetType);
-    }
-    
-    if (ruleSetVersion != NULL) {
-        properties->set_rulesetversion(ruleSetVersion);
-    }
-    
     if (ruleId != NULL) {
 		ruleId[strlen(ruleId) - 1] = '\0';
-		properties->set_ruleid(ruleId+1);
     }
     
 	bool is_mandatory = false;
@@ -59,14 +20,14 @@ void set_waf_format(waf_format::Waf_Format* waf_format, char* resourceId, char*
 		is_mandatory = rule_is_mandatory(tmpid);
 
 		if (ruleSetVersion[0] != '2' && !is_mandatory)
-			properties->set_action(WAF_ACTION_MATCHED);
+			action_str = WAF_ACTION_MATCHED;
 		else {
 			switch (action) {
 			case MODSEC_MODE_DETECT:
-				properties->set_action(WAF_ACTION_DETECTED);
+				action_str = WAF_ACTION_DETECTED;
 				break;
 			case MODSEC_MODE_PREVENT:
-				properties->set_action(WAF_ACTION_BLOCKED);
+				action_str = WAF_ACTION_BLOCKED;
 				break;
 			default:
 				break;
@@ -74,7 +35,7 @@ void set_waf_format(waf_format::Waf_Format* waf_format, char* resourceId, char*
 		}
 	}
     catch (...) {
-		properties->set_action("");
+		action_str = "";
 	}
     
 	if (messages != NULL) {
@@ -91,77 +52,50 @@ void set_waf_format(waf_format::Waf_Format* waf_format, char* resourceId, char*
 				}
 			}
 			mandatory_message[ind + i] = '\0';
-			properties->set_message(mandatory_message);
+			message_str = mandatory_message;
 		}
 		else {
 			messages[strlen(messages) - 1] = '\0';
-			properties->set_message(messages+1);
+			message_str = messages+1;
 		}		
 	}
 
 	if (site == 0) {
-        properties->set_site(waf_format::Properties::Global);
+        site_str = "Global";
     }
-    
-    if (details_messages != NULL) {
-        details->set_message(details_messages);
+
+    if (details_file != NULL) {
+		details_file[strlen(details_file) - 1] = '\0';
     }
-    
+
     if (details_data != NULL) {
 		details_data[strlen(details_data) - 1] = '\0';
-        details->set_data(details_data+1);
-    }
-    
-    if (details_file != NULL) {
-        details->set_file(details_file);
     }
     
     if (details_line != NULL) {
 		details_line[strlen(details_line) - 1] = '\0';
-        details->set_line(details_line+1);
     }
-    
-	if (hostname != NULL) {
-		properties->set_hostname(hostname);
-	}
 
 	if (waf_unique_id != NULL) {
 		waf_unique_id[strlen(waf_unique_id) - 1] = '\0';
-		properties->set_transactionid(waf_unique_id+1);
 	}
+
+    return to_json_string({resourceId, operationName, category, waf_logging::property{ instanceId, clientIP, clientPort, requestUri, ruleSetType, ruleSetVersion, ruleId+1, message_str, action_str, site_str, waf_logging::detail{ details_messages, details_data+1, details_file+1, details_line+1 }, hostname, waf_unique_id+1}});
 }
 
 // Main function:  get fields from modsec, set the protobuf object and write to file in json.
 int generate_json(char** result_json, char* resourceId, char* operationName, char* category, char* instanceId, char* clientIP, char* clientPort, const char* requestUri, char* ruleSetType, char* ruleSetVersion, char* ruleId, char* messages, int action, int site, char* details_messages, char* details_data, char* details_file, char* details_line, const char* hostname, char* waf_unique_id) {
-    waf_format::Waf_Format waf_format;
     string json_string;
-    google::protobuf::util::JsonPrintOptions options;
-    google::protobuf::util::Status convert_result;
     char* json_str;
     
     try {
-        // Verify that the version of the library that we linked against is
-        // compatible with the version of the headers we compiled against.
-        GOOGLE_PROTOBUF_VERIFY_VERSION;
-        
         // Set Waf format.
-        set_waf_format(&waf_format, resourceId, operationName, category, instanceId, clientIP, clientPort, requestUri, ruleSetType, ruleSetVersion, ruleId, messages, action, site, details_messages, details_data, details_file, details_line, hostname, waf_unique_id); 
-        
-        options.add_whitespace = false;
-        options.always_print_primitive_fields = true;
-        options.preserve_proto_field_names = true;
-        
-        convert_result = MessageToJsonString(waf_format, &json_string, options);
-        
-        if (!convert_result.ok()) {
-            return WAF_LOG_UTIL_FAILED;
-        }
+        json_string = get_json_log_message(resourceId, operationName, category, instanceId, clientIP, clientPort, requestUri, ruleSetType, ruleSetVersion, ruleId, messages, action, site, details_messages, details_data, details_file, details_line, hostname, waf_unique_id); 
     }
     catch (...) {
         return WAF_LOG_UTIL_FAILED;
     }
-    
-    // Write the waf json string to disk.
+
     *result_json = strdup((json_string + "\n").c_str());
     return WAF_LOG_UTIL_SUCCESS; 
 }
diff --git a/apache2/waf_logging/waf_log_util_internal.h b/apache2/waf_logging/waf_log_util_internal.h
old mode 100644
new mode 100755
index e265d2c7c8..70e475f709
--- a/apache2/waf_logging/waf_log_util_internal.h
+++ b/apache2/waf_logging/waf_log_util_internal.h
@@ -1,9 +1,62 @@
 #ifndef _WAF_LOG_UTIL_INTERNAL_HEADER
 #define _WAF_LOG_UTIL_INTERNAL_HEADER
 
-#include <google/protobuf/util/json_util.h>
-#include"waf_format.pb.h"
 #include <fstream>
+#include <unordered_map>
 #include <exception>
+#include <jsoncons/json.hpp>
+#include <jsoncons/json_options.hpp>
+
+// For convenience
+using jsoncons::ojson;
+using jsoncons::json_options;
+using jsoncons::line_split_kind;
+
+namespace waf_logging {
+
+    struct detail
+    {
+        std::string message;
+        std::string data;
+        std::string file;
+        std::string line;
+    };
+
+    struct property
+    {
+        std::string instanceId;
+        std::string clientIp;
+        std::string clientPort;
+        std::string requestUri;
+        std::string ruleSetType;
+        std::string ruleSetVersion;
+        std::string ruleId;
+        std::string message;
+        std::string action;
+        std::string site;
+        detail details;
+        std::string hostname;
+        std::string transactionId;
+    };
+
+    struct waf_log
+    {
+        std::string resourceId;
+        std::string operationName;
+        std::string category;
+        property properties;
+    };
+}
+
+JSONCONS_TYPE_TRAITS_DECL(waf_logging::detail, message, data, file, line);
+JSONCONS_TYPE_TRAITS_DECL(waf_logging::property, instanceId, clientIp, clientPort, requestUri, ruleSetType, ruleSetVersion, ruleId, message, action, site, details, hostname, transactionId);
+JSONCONS_TYPE_TRAITS_DECL(waf_logging::waf_log, resourceId, operationName, category, properties);
+
+std::string to_json_string(const waf_logging::waf_log& log) {
+    json_options options;
+    std::string json_output;
+    encode_json(ojson{}, log, json_output, options, jsoncons::indenting::indent);
+    return json_output;
+};
 
 #endif 
diff --git a/configure.ac b/configure.ac
index eb3a09e1fb..e80472e404 100644
--- a/configure.ac
+++ b/configure.ac
@@ -580,22 +580,6 @@ AC_ARG_ENABLE(collection-memory-database,
   collection_memory_database="-I"`pwd`"/apache2/ag_mdb -DMEMORY_DATABASE_ENABLE"
 ])
 
-# ProtoBuf compiler.
-# First, specify with --with-protoc=/path/of/protoc.
-# Or, specify with env variable PROTOC.
-# If neither of the above, find it in the path.
-#AC_MSG_CHECKING([for ProtoBuf compiler protoc])
-AC_ARG_WITH([protoc],
-    [AS_HELP_STRING([--with-protoc=/path/of/protoc],
-        [Location of the protocol buffers compiler protoc. Defaults to looking on path.])],
-    [PROTOC="$withval"],
-    [ AS_IF([test "x${PROTOC}" == "x"],
-        [AC_PATH_PROG([PROTOC], [protoc], [no])])
-    ]
-)
-#AC_MSG_RESULT([${PROTOC}])
-AS_IF([test "${PROTOC}" == "no"], [AC_MSG_ERROR([ProtoBuf compiler "protoc" not found.])])
-
 # Enable json waf logging support
 AC_ARG_ENABLE(waf_json_logging,
               AS_HELP_STRING([--enable-waf_json_logging],
diff --git a/docker/Dockerfile b/docker/Dockerfile
old mode 100644
new mode 100755
index 357e0fd276..dc3350d74a
--- a/docker/Dockerfile
+++ b/docker/Dockerfile
@@ -9,14 +9,11 @@ RUN apt-get install -y  \
     m4 \
     libtool
 
-# Install google protobuf 3.5.1
-RUN mkdir -p /tmp/protobuf/
-RUN curl -o /tmp/protobuf/protobuf-3.5.1.zip -OL https://github.com/google/protobuf/releases/download/v3.5.1/protobuf-cpp-3.5.1.zip
-RUN unzip /tmp/protobuf/protobuf-3.5.1.zip -d /tmp/protobuf/
-WORKDIR /tmp/protobuf/protobuf-3.5.1
-RUN ./autogen.sh
-RUN ./configure --prefix=/usr
-RUN  make && make install
+# Install jsoncons 
+RUN mkdir -p /tmp/jsoncons/
+RUN curl -o /tmp/jsoncons/jsoncons-0.122.0.zip -OL https://github.com/danielaparker/jsoncons/archive/v0.122.0.zip
+RUN unzip /tmp/jsoncons/jsoncons-0.122.0.zip -d /tmp/jsoncons
+RUN cp -r /tmp/jsoncons/jsoncons-0.122.0/include/jsoncons /usr/include/
 
 RUN apt-get install -y \
         apache2-dev \
diff --git a/nginx/modsecurity/config.in b/nginx/modsecurity/config.in
index 1498f95a18..6a3926f052 100644
--- a/nginx/modsecurity/config.in
+++ b/nginx/modsecurity/config.in
@@ -23,11 +23,7 @@ CORE_LIBS="$CORE_LIBS \
     @APXS_LIBS@ \
     @YAJL_LIBS@ \
     @SSDEEP_LDFLAGS@ \
-    -lstdc++ \
-    -Wl,-Bstatic
-    -lprotobuf
-    -Wl,-Bdynamic"
-
+    -lstdc++"
 
 ngx_addon_name=ngx_http_modsecurity
 
diff --git a/standalone/Makefile.am b/standalone/Makefile.am
index 33afd377e4..d3623db6ce 100644
--- a/standalone/Makefile.am
+++ b/standalone/Makefile.am
@@ -5,7 +5,6 @@ pkglib_LTLIBRARIES = standalone.la
 standalone_la_SOURCES = ../apache2/acmp.c \
     ../apache2/ag_mdb/murmur3.c \
     ../apache2/ag_mdb/ag_mdb.cpp \
-    ../apache2/waf_logging/waf_format.pb.cc \
     ../apache2/waf_logging/waf_log_util.cc \
     ../apache2/waf_lock/waf_lock.cpp \
     ../apache2/apache2_config.c \

From 24783aacdf265789c6316e4ad8a2fcfd6cdebbe0 Mon Sep 17 00:00:00 2001
From: Vladimir Krivopalov <vlkrivop@microsoft.com>
Date: Fri, 19 Apr 2019 16:45:39 -0700
Subject: [PATCH 33/58] Skip reading request body when body processing is
 disabled.

We have encountered an issue when SetRequestBodyAccess is turned off for
the code would still read the body into Apache brigades and that would
later cause processing to fail because it did not expect any body data
to be present.
Besides, that would allocate twice as much memory for body handling for
no good reason.

With this fix, we only copy the body over from IIS into Apache
structures if we are going to process it.

Signed-off-by: Vladimir Krivopalov <vlkrivop@microsoft.com>
---
 iis/mymodule.cpp | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/iis/mymodule.cpp b/iis/mymodule.cpp
index 8b8901cb35..d9c5a8027e 100644
--- a/iis/mymodule.cpp
+++ b/iis/mymodule.cpp
@@ -1113,10 +1113,12 @@ CMyHttpModule::OnBeginRequest(IHttpContext* httpContext, IHttpEventProvider* pro
 #endif
     c->remote_host = NULL;
 
-    hr = SaveRequestBodyToRequestRec(context);
-    if (FAILED(hr)) {
-        context->provider->SetErrorStatus(hr);
-        return RQ_NOTIFICATION_FINISH_REQUEST;
+    if (config->config->reqbody_access) {
+        hr = SaveRequestBodyToRequestRec(context);
+        if (FAILED(hr)) {
+            context->provider->SetErrorStatus(hr);
+            return RQ_NOTIFICATION_FINISH_REQUEST;
+        }
     }
 
     lock.unlock();

From 5b1ede40581aa3b25514515d1eec8b45f66a8acf Mon Sep 17 00:00:00 2001
From: Vladimir Krivopalov <vlkrivop@microsoft.com>
Date: Wed, 17 Apr 2019 15:51:13 -0700
Subject: [PATCH 34/58] Add BUILD.md file explaining branches management and
 build process.

Signed-off-by: Vladimir Krivopalov <vlkrivop@microsoft.com>
---
 BUILD.md | 98 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 98 insertions(+)
 create mode 100644 BUILD.md

diff --git a/BUILD.md b/BUILD.md
new file mode 100644
index 0000000000..14e7420765
--- /dev/null
+++ b/BUILD.md
@@ -0,0 +1,98 @@
+# Building ModSecurity
+
+## Branches
+Two branches currently used for ModSecurity development and sustaining are `v2/master` and `iis_maintenance`. 
+All new fixes go to `v2/master` and so pull requests should be opened for this branch. 
+General changes and changes that are specific to ModSecurity for IIS are merged from `v2/master` to `iis_maintenance`. Fixes specific to ModSecurity for Nginx are not propagated from `v2/master`.
+
+## Building ModSecurity For IIS
+
+Open a `PowerShell` command line to follow the steps below.
+
+ 1. Clone ModSecurity repository along with all registered submodules:
+    ```bash
+    git clone --recursive https://github.com/Microsoft/ModSecurity
+    ```
+ 2. Switch to `iis_maintenance` branch:
+     ```bash
+    git checkout --recurse-submodules iis_maintenance
+    ```
+ 3.  Change to the `iis` subdirectory:
+     ```bash
+     cd iis
+     ```
+ 4. Download dependencies using helper PowerShell script:
+     ```bash
+     .\getModSecurityPkgs.ps1 https://modsecurity.blob.core.windows.net/windows-artifacts
+     ```
+ 5. Open Visual Studio 2015 x64 Native Tools Command Prompt, change to `iis` subdirectory and start the build:
+     ```bash
+     cd iis
+     .\build_release_amd64.bat
+     ```
+ 
+ This will produce the binaries and place them into `ModSecurity\iis\release\amd64` directory.
+
+If you only make changes to ModSecurity and not to any of its dependencies, you can later only rebuild it with `build_modsecurity.bat`. You still have to use `build_release_amd64` for the first time to get all the dependencies built.
+
+## Building ModSecurity For Nginx
+The steps below are for Ubuntu 16.04 LTS.
+
+ 1. Install required dependencies:
+	 ```
+	 apt-get update && apt-get install -y  \
+    vim \
+    curl \
+    apt-transport-https \
+    build-essential \
+    wget \
+    automake\
+    unzip\
+    m4 \
+    git \
+    libtool \
+    cmake \
+    apache2-dev \
+    g++-4.8 \
+    libaprutil1 \
+    libazurepal-dev \
+    libazurepal \
+    libcurl4-openssl-dev \
+    libexpat-dev\
+    libgd2-xpm-dev \
+    liblua5.1-dev \
+    libluajit-5.1-dev \
+    libpcre3-dev \
+    libperl-dev \
+    libunwind8 \
+    libyajl-dev \
+    libxml2\
+    libxml2-dev\
+    metricsext \
+    unzip \
+    uuid-dev \
+    openssh-server \
+    unzip \
+    uuid-runtime \
+    gdb
+    # Install jsoncons 0.122
+    mkdir -p /tmp/jsoncons/
+    curl -o /tmp/jsoncons/jsoncons-0.122.0.zip -OL https://github.com/danielaparker/jsoncons/archive/v0.122.0.zip
+    unzip /tmp/jsoncons/jsoncons-0.122.0.zip -d /tmp/jsoncons
+    cp -r /tmp/jsoncons/jsoncons-0.122.0/include/jsoncons /usr/include/
+	```
+
+ 3. Clone ModSecurity repository along with all registered submodules:
+    ```bash
+    git clone --recursive https://github.com/Microsoft/ModSecurity
+    ```
+ 4. Make sure you're in `v2/master` branch:
+     ```bash
+    git status
+    ```
+ 5.  Configure and build ModSecurity:
+	 ```bash
+	 ./autogen.sh
+	 ./configure LDFLAGS=-g  CXXFLAGS="-std=c++11 " CFLAGS="-fPIC " --enable-standalone-module --disable-mlogc --enable-waf_json_logging
+	 make
+	 ```

From 95badb229523ceb6a29bcb3b3e16fe628c9bab04 Mon Sep 17 00:00:00 2001
From: Vladimir Krivopalov <vlkrivop@microsoft.com>
Date: Mon, 29 Apr 2019 09:37:38 -0700
Subject: [PATCH 35/58] Add ModSecurity configuration cache.

The cache is implemented as a balanced tree that maps configuration file
paths to respective objects.
This allows re-using existing configuration blocks instead of allocating
new identical ones if the same ModSecurity configuration is used in
multiple different contexts.

Signed-off-by: Vladimir Krivopalov <vlkrivop@microsoft.com>
---
 .../ngx_http_modsecurity_config_cache.c       | 126 ++++++++++++++++++
 .../ngx_http_modsecurity_config_cache.h       |  36 +++++
 2 files changed, 162 insertions(+)
 create mode 100644 nginx/modsecurity/ngx_http_modsecurity_config_cache.c
 create mode 100644 nginx/modsecurity/ngx_http_modsecurity_config_cache.h

diff --git a/nginx/modsecurity/ngx_http_modsecurity_config_cache.c b/nginx/modsecurity/ngx_http_modsecurity_config_cache.c
new file mode 100644
index 0000000000..040c85a3e5
--- /dev/null
+++ b/nginx/modsecurity/ngx_http_modsecurity_config_cache.c
@@ -0,0 +1,126 @@
+#include "ngx_http_modsecurity_config_cache.h"
+
+typedef struct {
+    // Must be the first member of the structure because of pointer casts 
+    // used by insert/lookup routines.
+    ngx_rbtree_node_t         rbnode;
+
+    ngx_str_t                 path;
+    directory_config          *config;
+} ngx_http_modsecurity_config_cache_node_t;
+
+/*
+ * Implemented similarly to ngx_string.c#ngx_str_rbtree_insert_value()
+ */
+static void
+ngx_http_modsecurity_config_cache_rbtree_insert_value(ngx_rbtree_node_t *temp,
+    ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel)
+{
+    ngx_rbtree_node_t  **p = NULL;
+    for ( ;; ) {
+
+        ngx_http_modsecurity_config_cache_node_t *n = (ngx_http_modsecurity_config_cache_node_t*) node;
+        ngx_http_modsecurity_config_cache_node_t *t = (ngx_http_modsecurity_config_cache_node_t*) temp;
+
+        if (node->key != temp->key) {
+
+            p = (node->key < temp->key) ? &temp->left : &temp->right;
+
+        } else if (n->path.len != t->path.len) {
+
+            p = (n->path.len < t->path.len) ? &temp->left : &temp->right;
+
+        } else {
+            p = (ngx_strncasecmp(n->path.data, t->path.data, n->path.len) < 0)
+                 ? &temp->left : &temp->right;
+        }
+
+        if (*p == sentinel) {
+            break;
+        }
+
+        temp = *p;
+    }
+
+    *p = node;
+    node->parent = temp;
+    node->left = sentinel;
+    node->right = sentinel;
+    ngx_rbt_red(node);
+}
+
+ngx_http_modsecurity_config_cache_t *ngx_http_modsecurity_config_cache_init(ngx_conf_t *cf)
+{
+    ngx_rbtree_node_t *sentinel = ngx_pcalloc(cf->pool, sizeof(ngx_rbtree_node_t));
+    if (sentinel == NULL) {
+        return NULL;
+    }
+
+    ngx_http_modsecurity_config_cache_t *cache = ngx_pcalloc(cf->pool, sizeof(ngx_http_modsecurity_config_cache_t));
+    if (cache == NULL) {
+        return NULL;
+    }
+
+    ngx_rbtree_init(&cache->rbtree, sentinel, ngx_http_modsecurity_config_cache_rbtree_insert_value);
+    return cache;
+}
+
+ngx_int_t ngx_http_modsecurity_config_cache_insert(
+    ngx_http_modsecurity_config_cache_t* cache, ngx_conf_t *cf,
+    ngx_str_t *path, directory_config *config)
+{
+    ngx_http_modsecurity_config_cache_node_t *node = ngx_pcalloc(cf->pool, sizeof(ngx_http_modsecurity_config_cache_node_t));
+    if (node == NULL) {
+        return NGX_ERROR;
+    }
+
+    node->path.data = ngx_pstrdup(cf->pool, path);
+    node->path.len = path->len;
+    node->rbnode.key = ngx_crc32_long(path->data, path->len);
+    node->config = config;
+
+    ngx_rbtree_insert(&cache->rbtree, &node->rbnode);
+    return NGX_OK;
+}
+
+/*
+ * Implemented similarly to ngx_string.c#ngx_str_rbtree_lookup()
+ */
+directory_config *ngx_http_modsecurity_config_cache_lookup(
+    ngx_http_modsecurity_config_cache_t *cache, ngx_str_t *path)
+{
+    ngx_uint_t hash = ngx_crc32_long(path->data, path->len);
+    ngx_rbtree_node_t *node = cache->rbtree.root;
+    ngx_rbtree_node_t *sentinel = cache->rbtree.sentinel;
+
+    while (node != sentinel) {
+        ngx_http_modsecurity_config_cache_node_t *n = (ngx_http_modsecurity_config_cache_node_t *) node;
+
+        if (hash != node->key) {
+            node = (hash < node->key) ? node->left : node->right;
+            continue;
+        }
+
+        if (path->len != n->path.len) {
+            node = (path->len < n->path.len) ? node->left : node->right;
+            continue;
+        }
+
+        ngx_int_t rc = ngx_memcmp(path->data, n->path.data, path->len);
+
+        if (rc < 0) {
+            node = node->left;
+            continue;
+        }
+
+        if (rc > 0) {
+            node = node->right;
+            continue;
+        }
+
+        return n->config;
+    }
+
+    return NULL;
+
+}
diff --git a/nginx/modsecurity/ngx_http_modsecurity_config_cache.h b/nginx/modsecurity/ngx_http_modsecurity_config_cache.h
new file mode 100644
index 0000000000..7102198914
--- /dev/null
+++ b/nginx/modsecurity/ngx_http_modsecurity_config_cache.h
@@ -0,0 +1,36 @@
+#pragma once
+
+#include <ngx_core.h>
+#include <ngx_string.h>
+
+/*
+ * ModSecurity configuration cache is used to prevent loading configuration
+ * multiple times if one and the same configuration file is applied in multiple
+ * different contexts.
+ *
+ * The main problem with loading ModSecurity configuration independently for each 
+ * context is that the allocated memory block can be quite large (10-20 Mb) so if, 
+ * for example, the same configuration is used for 10-20 listeners it will cause 
+ * significant memory overuse for no good reason.
+ *
+ * The cache helps alleviate this by storing pointers to configuration objects created
+ * from ModSecurity configuration files and re-using existing objects when the same path
+ * occurs several times during Nginx configuration loading.
+ */
+
+typedef struct directory_config directory_config;
+
+typedef struct {
+    ngx_rbtree_t              rbtree;
+} ngx_http_modsecurity_config_cache_t;
+
+/* Create configuration cache */
+ngx_http_modsecurity_config_cache_t *ngx_http_modsecurity_config_cache_init(ngx_conf_t *cf);
+
+/* Add configuration block for the respective file path into configuration cache */
+ngx_int_t ngx_http_modsecurity_config_cache_insert(ngx_http_modsecurity_config_cache_t *cache,
+    ngx_conf_t *cf, ngx_str_t *path, directory_config *config);
+
+/* Look up configuration block for the respective file path in configuration cache */
+directory_config *ngx_http_modsecurity_config_cache_lookup(ngx_http_modsecurity_config_cache_t *cache,
+    ngx_str_t *path);

From 783b6f82169b01671298bf261a2b22dac8e600f0 Mon Sep 17 00:00:00 2001
From: Vladimir Krivopalov <vlkrivop@microsoft.com>
Date: Mon, 29 Apr 2019 13:05:33 -0700
Subject: [PATCH 36/58] Use configuration cache when loading ModSecurity
 config.

Before this change, for each context where a particular ModSecurity
configuration file is applied, a block of memory with the same contents
would be created and initialized.

Now, if the path is the same, we re-use the previously created object
instead to reduce memory consumption.

Signed-off-by: Vladimir Krivopalov <vlkrivop@microsoft.com>
---
 nginx/modsecurity/config.in              |  2 ++
 nginx/modsecurity/ngx_http_modsecurity.c | 22 ++++++++++++++++++++++
 2 files changed, 24 insertions(+)

diff --git a/nginx/modsecurity/config.in b/nginx/modsecurity/config.in
index 6a3926f052..f77d4f7ca8 100644
--- a/nginx/modsecurity/config.in
+++ b/nginx/modsecurity/config.in
@@ -33,9 +33,11 @@ HTTP_AUX_FILTER_MODULES="ngx_http_modsecurity $HTTP_AUX_FILTER_MODULES"
 
 NGX_ADDON_SRCS="$NGX_ADDON_SRCS \
 		$ngx_addon_dir/ngx_http_modsecurity.c \
+		$ngx_addon_dir/ngx_http_modsecurity_config_cache.c \
 		$ngx_addon_dir/apr_bucket_nginx.c"
 
 NGX_ADDON_DEPS="$NGX_ADDON_DEPS \
+		$ngx_addon_dir/ngx_http_modsecurity_config_cache.h \
 		$ngx_addon_dir/apr_bucket_nginx.h"
 
 CORE_LIBS="$ngx_addon_dir/../../standalone/.libs/standalone.a $CORE_LIBS"
diff --git a/nginx/modsecurity/ngx_http_modsecurity.c b/nginx/modsecurity/ngx_http_modsecurity.c
index 7efcf0527b..d0192ce739 100644
--- a/nginx/modsecurity/ngx_http_modsecurity.c
+++ b/nginx/modsecurity/ngx_http_modsecurity.c
@@ -13,6 +13,7 @@
 */
 
 #include <ngx_http.h>
+#include <ngx_http_modsecurity_config_cache.h>
 #include <apr_bucket_nginx.h>
 
 #include <apr_base64.h>
@@ -511,6 +512,7 @@ modsec_pcre_free(void *ptr)
 }
 
 static server_rec *modsec_server = NULL;
+static ngx_http_modsecurity_config_cache_t *config_cache = NULL;
 
 static ngx_int_t
 ngx_http_modsecurity_preconfiguration(ngx_conf_t *cf)
@@ -537,6 +539,12 @@ ngx_http_modsecurity_preconfiguration(ngx_conf_t *cf)
     modsec_server->server_hostname[ ngx_cycle->hostname.len] = '\0';
 
     modsecStartConfig();
+
+    config_cache = ngx_http_modsecurity_config_cache_init(cf);
+    if (config_cache == NULL) {
+        return NGX_ERROR;
+    }
+
     return NGX_OK;
 }
 
@@ -548,6 +556,9 @@ ngx_http_modsecurity_terminate(ngx_cycle_t *cycle)
         modsecTerminate();
         modsec_server = NULL;
     }
+
+    /* Configuration cache is allocated from a pool and does not need explicit freeing */
+    config_cache = NULL;
 }
 
 
@@ -1012,6 +1023,11 @@ ngx_http_modsecurity_config(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
         return NGX_CONF_ERROR;
     }
 
+    mscf->config = ngx_http_modsecurity_config_cache_lookup(config_cache, &value[1]);
+    if (mscf->config != NULL) {
+        return NGX_CONF_OK;
+    }
+
     mscf->config = modsecGetDefaultConfig();
 
     if (mscf->config == NULL) {
@@ -1025,6 +1041,12 @@ ngx_http_modsecurity_config(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
         return NGX_CONF_ERROR;
     }
 
+    ngx_int_t result = ngx_http_modsecurity_config_cache_insert(config_cache, cf, &value[1], mscf->config);
+    if (result != NGX_OK) {
+        ngx_log_error(NGX_LOG_WARN, cf->log, 0, "Couldn't cache config in %s:%ui: %s",
+                cf->conf_file->file.name.data, cf->conf_file->line, msg);
+    }
+
     return NGX_CONF_OK;
 }
 

From bc9d2d1fc7d13f5d548cff617381dbee9d98664f Mon Sep 17 00:00:00 2001
From: Vladimir Krivopalov <vlkrivop@microsoft.com>
Date: Mon, 29 Apr 2019 17:18:37 -0700
Subject: [PATCH 37/58] Process request in background when in detection mode.

We don't have to block until request processing is completed when in
detection mode because we are not going to block request based on
processing result.
To speed up processing and improve latencies, we offload processing to a
background thread.

This reverts commit 7526371c17f87ff75463e345311bf4a4bc450670.

Signed-off-by: Vladimir Krivopalov <vlkrivop@microsoft.com>
---
 iis/Makefile.win |   3 +-
 iis/mymodule.cpp | 154 +++++++++++++++++++++++++++++++++++++++++------
 iis/mymodule.h   |   8 ++-
 3 files changed, 144 insertions(+), 21 deletions(-)

diff --git a/iis/Makefile.win b/iis/Makefile.win
index 1e198f65c3..740021d3e3 100644
--- a/iis/Makefile.win
+++ b/iis/Makefile.win
@@ -37,7 +37,8 @@ INCLUDES = -I. -I.. \
            -I..\apache2 \
            -I..\standalone \
            -I..\apache2\ag_mdb \
-           -I..\apache2\waf_lock
+           -I..\apache2\waf_lock \
+           -Iasio\asio\include
 
 # Enables support for SecRemoteRules and external resources.
 DEFS=$(DEFS) -DWITH_CURL -DWITH_REMOTE_RULES
diff --git a/iis/mymodule.cpp b/iis/mymodule.cpp
index d9c5a8027e..a292d31473 100644
--- a/iis/mymodule.cpp
+++ b/iis/mymodule.cpp
@@ -19,6 +19,7 @@
 #include <string>
 #include <cctype>
 #include <memory>
+#include <future>
 
 //  IIS7 Server API header file
 #include <Windows.h>
@@ -35,6 +36,9 @@
 
 #include "winsock2.h"
 
+#include "asio/packaged_task.hpp"
+#include "asio/post.hpp"
+
 // These helpers make sure that the underlying structures
 // are correctly released on any exit path due to RAII.
 using ConnRecPtr = std::shared_ptr<conn_rec>;
@@ -62,6 +66,8 @@ struct RequestStoredContext
     char* responseBuffer = nullptr;
     ULONGLONG responseLength = 0;
     ULONGLONG responsePosition = 0;
+    bool responseProcessingEnabled = false;
+    std::future<int> detectionProcessing;
 
     void CleanupStoredContext() override
     {
@@ -500,6 +506,97 @@ static HRESULT SaveRequestBodyToRequestRec(RequestStoredContext* rsc)
     return S_OK;
 }
 
+
+static apr_status_t ReadBodyCallback(request_rec *r, char *buf, unsigned int length, unsigned int *readcnt, int *is_eos)
+{
+    RequestStoredContext *rsc = RetrieveIISContext(r);
+
+    *readcnt = 0;
+
+    if (rsc == NULL)
+    {
+        *is_eos = 1;
+        return APR_SUCCESS;
+    }
+
+    IHttpContext *pHttpContext = rsc->httpContext;
+    IHttpRequest *pRequest = pHttpContext->GetRequest();
+
+    if (pRequest->GetRemainingEntityBytes() == 0)
+    {
+        *is_eos = 1;
+        return APR_SUCCESS;
+    }
+
+    HRESULT hr = pRequest->ReadEntityBody(buf, length, false, (DWORD *)readcnt, NULL);
+
+    if (FAILED(hr))
+    {
+        // End of data is okay.
+        if (ERROR_HANDLE_EOF != (hr & 0x0000FFFF))
+        {
+            // Set the error status.
+            rsc->provider->SetErrorStatus(hr);
+        }
+
+        *is_eos = 1;
+    }
+
+    return APR_SUCCESS;
+}
+
+static apr_status_t WriteBodyCallback(request_rec *r, char *buf, unsigned int length)
+{
+    RequestStoredContext *rsc = RetrieveIISContext(r);
+
+    if (!rsc || !rsc->requestRec)
+        return APR_SUCCESS;
+
+    IHttpContext *pHttpContext = rsc->httpContext;
+    IHttpRequest *pHttpRequest = pHttpContext->GetRequest();
+
+    auto lengthStr = std::to_string(length);
+
+    // Remove/Modify Transfer-Encoding header if "chunked" Encoding is set in the request. 
+    // This is to avoid sending both Content-Length and Chunked Transfer-Encoding in the request header.
+
+    USHORT ctcch = 0;
+    char *ct = (char *)pHttpRequest->GetHeader(HttpHeaderTransferEncoding, &ctcch);
+    if (ct)
+    {
+        char *ctz = ZeroTerminate(ct, ctcch, r->pool);
+        if (ctcch != 0)
+        {
+            if (0 == stricmp(ctz, "chunked"))
+            {
+                pHttpRequest->DeleteHeader(HttpHeaderTransferEncoding);
+            }
+        }
+    }
+
+    HRESULT hr = pHttpRequest->SetHeader(
+        HttpHeaderContentLength,
+        lengthStr.c_str(),
+        (USHORT)lengthStr.size(),
+        TRUE);
+
+    if (FAILED(hr))
+    {
+        // possible, but there's nothing we can do
+    }
+
+    // since we clean the APR pool at the end of OnSendRequest, we must get IIS-managed memory chunk
+    //
+    void *reqbuf = pHttpContext->AllocateRequestMemory(length);
+
+    memcpy(reqbuf, buf, length);
+
+    pHttpRequest->InsertEntityBody(reqbuf, length);
+
+    return APR_SUCCESS;
+}
+
+
 REQUEST_NOTIFICATION_STATUS
 CMyHttpModule::OnSendResponse(
     IN IHttpContext * pHttpContext,
@@ -509,12 +606,18 @@ CMyHttpModule::OnSendResponse(
     RequestStoredContext* rsc = dynamic_cast<RequestStoredContext*>(pHttpContext->GetModuleContextContainer()->GetModuleContext(g_pModuleContext));
 
     CriticalSectionLock lock{cs};
-	// here we must check if response body processing is enabled
-	//
-	if(!rsc || !rsc->requestRec || rsc->responseBuffer != nullptr || !modsecIsResponseBodyAccessEnabled(rsc->requestRec.get()))
-	{
-		goto Exit;
-	}
+    // here we must check if response body processing is enabled
+    //
+    if (!rsc || !rsc->requestRec || rsc->responseBuffer != nullptr || !rsc->responseProcessingEnabled)
+    {
+        goto Exit;
+    }
+
+    // If we have offloaded request processing to the thread pool
+    // we need to wait for its completion before we can proceed
+    if (rsc->detectionProcessing.valid()) {
+        rsc->detectionProcessing.get();
+    }
 
     HRESULT hr = S_OK;
     IHttpResponse *pHttpResponse = NULL;
@@ -880,7 +983,8 @@ CMyHttpModule::OnBeginRequest(IHttpContext* httpContext, IHttpEventProvider* pro
     rsc->connRec = connRec;
     rsc->requestRec = requestRec;
     rsc->httpContext = httpContext;
-    rsc->provider = provider;	
+    rsc->provider = provider;
+    rsc->responseProcessingEnabled = (config->config->resbody_access == 1);
     RequestStoredContext* context = rsc.get();
 
     StoreIISContext(r, rsc.get());
@@ -1121,19 +1225,35 @@ CMyHttpModule::OnBeginRequest(IHttpContext* httpContext, IHttpEventProvider* pro
         }
     }
 
-    lock.unlock();
-    int status = modsecProcessRequest(r);
-    lock.lock();
+    if (config->config->is_enabled == MODSEC_DETECTION_ONLY)
+    {
+        // We post the processing task to the thread pool to happen in the background.
+        // We store the future to track and wait for this processing in case if we also
+        // need to process the response because we need request processing to finish
+        // before we can start with the response.
+        context->detectionProcessing = asio::post(threadPool,
+            std::packaged_task<int()> {
+            [connRec, requestRec] {
+                return modsecProcessRequest(requestRec.get());
+            }
+        });
+    }
+    else
+    {
+        lock.unlock();
+        int status = modsecProcessRequest(r);
+        lock.lock();
 
-	if(status != DECLINED)
-	{
-		httpContext->GetResponse()->SetStatus(status, "ModSecurity Action");
-		httpContext->SetRequestHandled();
+        if (status != DECLINED)
+        {
+            httpContext->GetResponse()->SetStatus(status, "ModSecurity Action");
+            httpContext->SetRequestHandled();
 
-        return RQ_NOTIFICATION_FINISH_REQUEST;
-	}
+            return RQ_NOTIFICATION_FINISH_REQUEST;
+        }
+    }
 
-	return RQ_NOTIFICATION_CONTINUE;
+    return RQ_NOTIFICATION_CONTINUE;
 }
 
 apr_status_t ReadResponseCallback(request_rec *r, char *buf, unsigned int length, unsigned int *readcnt, int *is_eos)
diff --git a/iis/mymodule.h b/iis/mymodule.h
index c14180965c..83d7adb697 100644
--- a/iis/mymodule.h
+++ b/iis/mymodule.h
@@ -12,8 +12,10 @@
 * directly using the email address security@modsecurity.org.
 */
 
-#ifndef __MY_MODULE_H__
-#define __MY_MODULE_H__
+#pragma once
+
+#define ASIO_STANDALONE
+#include "asio/thread_pool.hpp"
 
 #include "critical_section.h"
 #include "event_logger.h"
@@ -46,8 +48,8 @@ class CMyHttpModule
 private:
     CriticalSection cs;
     EventLogger logger;
+    asio::thread_pool threadPool;
     DWORD pageSize = 0;
     bool statusCallAlreadySent = false;
 };
 
-#endif

From 84b78778495ecc7b52870a470321066a4f8cfbf8 Mon Sep 17 00:00:00 2001
From: Vladimir Krivopalov <vlkrivop@microsoft.com>
Date: Mon, 18 Mar 2019 12:38:27 -0700
Subject: [PATCH 38/58] Remove unused ReadBodyCallback and WriteBodyCallback.

Signed-off-by: Vladimir Krivopalov <vlkrivop@microsoft.com>
---
 iis/mymodule.cpp | 91 ------------------------------------------------
 1 file changed, 91 deletions(-)

diff --git a/iis/mymodule.cpp b/iis/mymodule.cpp
index a292d31473..851af3eebd 100644
--- a/iis/mymodule.cpp
+++ b/iis/mymodule.cpp
@@ -506,97 +506,6 @@ static HRESULT SaveRequestBodyToRequestRec(RequestStoredContext* rsc)
     return S_OK;
 }
 
-
-static apr_status_t ReadBodyCallback(request_rec *r, char *buf, unsigned int length, unsigned int *readcnt, int *is_eos)
-{
-    RequestStoredContext *rsc = RetrieveIISContext(r);
-
-    *readcnt = 0;
-
-    if (rsc == NULL)
-    {
-        *is_eos = 1;
-        return APR_SUCCESS;
-    }
-
-    IHttpContext *pHttpContext = rsc->httpContext;
-    IHttpRequest *pRequest = pHttpContext->GetRequest();
-
-    if (pRequest->GetRemainingEntityBytes() == 0)
-    {
-        *is_eos = 1;
-        return APR_SUCCESS;
-    }
-
-    HRESULT hr = pRequest->ReadEntityBody(buf, length, false, (DWORD *)readcnt, NULL);
-
-    if (FAILED(hr))
-    {
-        // End of data is okay.
-        if (ERROR_HANDLE_EOF != (hr & 0x0000FFFF))
-        {
-            // Set the error status.
-            rsc->provider->SetErrorStatus(hr);
-        }
-
-        *is_eos = 1;
-    }
-
-    return APR_SUCCESS;
-}
-
-static apr_status_t WriteBodyCallback(request_rec *r, char *buf, unsigned int length)
-{
-    RequestStoredContext *rsc = RetrieveIISContext(r);
-
-    if (!rsc || !rsc->requestRec)
-        return APR_SUCCESS;
-
-    IHttpContext *pHttpContext = rsc->httpContext;
-    IHttpRequest *pHttpRequest = pHttpContext->GetRequest();
-
-    auto lengthStr = std::to_string(length);
-
-    // Remove/Modify Transfer-Encoding header if "chunked" Encoding is set in the request. 
-    // This is to avoid sending both Content-Length and Chunked Transfer-Encoding in the request header.
-
-    USHORT ctcch = 0;
-    char *ct = (char *)pHttpRequest->GetHeader(HttpHeaderTransferEncoding, &ctcch);
-    if (ct)
-    {
-        char *ctz = ZeroTerminate(ct, ctcch, r->pool);
-        if (ctcch != 0)
-        {
-            if (0 == stricmp(ctz, "chunked"))
-            {
-                pHttpRequest->DeleteHeader(HttpHeaderTransferEncoding);
-            }
-        }
-    }
-
-    HRESULT hr = pHttpRequest->SetHeader(
-        HttpHeaderContentLength,
-        lengthStr.c_str(),
-        (USHORT)lengthStr.size(),
-        TRUE);
-
-    if (FAILED(hr))
-    {
-        // possible, but there's nothing we can do
-    }
-
-    // since we clean the APR pool at the end of OnSendRequest, we must get IIS-managed memory chunk
-    //
-    void *reqbuf = pHttpContext->AllocateRequestMemory(length);
-
-    memcpy(reqbuf, buf, length);
-
-    pHttpRequest->InsertEntityBody(reqbuf, length);
-
-    return APR_SUCCESS;
-}
-
-
 REQUEST_NOTIFICATION_STATUS
 CMyHttpModule::OnSendResponse(
     IN IHttpContext * pHttpContext,

From 808585fc35fbbf6a5ab47a4745c30c5171417351 Mon Sep 17 00:00:00 2001
From: Vladimir Krivopalov <vlkrivop@microsoft.com>
Date: Mon, 18 Mar 2019 16:16:19 -0700
Subject: [PATCH 39/58] Remove response handling.

This is not used by MS WAF and allows to both avoid extra allocations
and locking.

Signed-off-by: Vladimir Krivopalov <vlkrivop@microsoft.com>
---
 iis/main.cpp     |  18 +-
 iis/mymodule.cpp | 501 -----------------------------------------------
 iis/mymodule.h   |   8 -
 3 files changed, 3 insertions(+), 524 deletions(-)

diff --git a/iis/main.cpp b/iis/main.cpp
index db7451eea1..570c2d49c4 100644
--- a/iis/main.cpp
+++ b/iis/main.cpp
@@ -56,22 +56,10 @@ RegisterModule(DWORD, IHttpModuleRegistrationInfo* moduleInfo, IHttpServer * htt
 
         // step 3: register for server events
         //
-        auto result = moduleInfo->SetRequestNotifications(
+        return moduleInfo->SetRequestNotifications(
             factory.release(), /* module factory */
-            RQ_BEGIN_REQUEST | RQ_SEND_RESPONSE /* server event mask */,
-            RQ_END_REQUEST /* server post event mask */);
-        if (FAILED(result))
-        {
-            return result;
-        }
-
-        result = moduleInfo->SetPriorityForRequestNotification(RQ_BEGIN_REQUEST, PRIORITY_ALIAS_FIRST);
-        if (FAILED(result))
-        {
-            return result;
-        }
-
-        return moduleInfo->SetPriorityForRequestNotification(RQ_SEND_RESPONSE, PRIORITY_ALIAS_LAST);
+            RQ_BEGIN_REQUEST /* server event mask */,
+            0 /* server post event mask */);
     }
     catch (const std::bad_alloc&)
     {
diff --git a/iis/mymodule.cpp b/iis/mymodule.cpp
index 851af3eebd..3b225ea5e9 100644
--- a/iis/mymodule.cpp
+++ b/iis/mymodule.cpp
@@ -281,132 +281,6 @@ RequestStoredContext *RetrieveIISContext(request_rec *r)
     return NULL;
 }
 
-
-HRESULT CMyHttpModule::ReadFileChunk(HTTP_DATA_CHUNK *chunk, char *buf)
-{
-    OVERLAPPED ovl;
-    DWORD dwDataStartOffset;
-    ULONGLONG bytesTotal = 0;
-    BYTE *    pIoBuffer = NULL;
-    HANDLE    hIoEvent = INVALID_HANDLE_VALUE;
-    HRESULT hr = S_OK;
-
-    pIoBuffer = (BYTE *)VirtualAlloc(NULL,
-                                        1,
-                                        MEM_COMMIT | MEM_RESERVE,
-                                        PAGE_READWRITE);
-    if (pIoBuffer == NULL)
-    {
-        hr = HRESULT_FROM_WIN32(GetLastError());
-        goto Done;
-    }
-
-    hIoEvent = CreateEvent(NULL,  // security attr
-                                FALSE, // manual reset
-                                FALSE, // initial state
-                                NULL); // name
-    if (hIoEvent == NULL)
-    {
-        hr = HRESULT_FROM_WIN32(GetLastError());
-        goto Done;
-    }
-
-    while(bytesTotal < chunk->FromFileHandle.ByteRange.Length.QuadPart)
-    {
-        DWORD bytesRead = 0;
-        int was_eof = 0;
-        ULONGLONG offset = chunk->FromFileHandle.ByteRange.StartingOffset.QuadPart + bytesTotal;
-
-        ZeroMemory(&ovl, sizeof ovl);
-        ovl.hEvent     = hIoEvent;
-        ovl.Offset = (DWORD)offset;
-        dwDataStartOffset = ovl.Offset & (pageSize - 1);
-        ovl.Offset &= ~(pageSize - 1);
-        ovl.OffsetHigh = offset >> 32;
-
-        if (!ReadFile(chunk->FromFileHandle.FileHandle,
-                      pIoBuffer,
-                      pageSize,
-                      &bytesRead,
-                      &ovl))
-        {
-            DWORD dwErr = GetLastError();
-
-            switch (dwErr)
-            {
-            case ERROR_IO_PENDING:
-                //
-                // GetOverlappedResult can return without waiting for the
-                // event thus leaving it signalled and causing problems
-                // with future use of that event handle, so just wait ourselves
-                //
-                WaitForSingleObject(ovl.hEvent, INFINITE); // == WAIT_OBJECT_0);
-
-                if (!GetOverlappedResult(
-                         chunk->FromFileHandle.FileHandle,
-                         &ovl,
-                         &bytesRead,
-                         TRUE))
-                {
-                    dwErr = GetLastError();
-
-                    switch(dwErr)
-                    {
-                    case ERROR_HANDLE_EOF:
-                        was_eof = 1;
-                        break;
-
-                    default:
-                        hr = HRESULT_FROM_WIN32(dwErr);
-                        goto Done;
-                    }
-                }
-                break;
-
-            case ERROR_HANDLE_EOF:
-                was_eof = 1;
-                break;
-
-            default:
-                hr = HRESULT_FROM_WIN32(dwErr);
-                goto Done;
-            }
-        }
-
-        bytesRead -= dwDataStartOffset;
-
-        if (bytesRead > chunk->FromFileHandle.ByteRange.Length.QuadPart)
-        {
-            bytesRead = (DWORD)chunk->FromFileHandle.ByteRange.Length.QuadPart;
-        }
-        if ((bytesTotal + bytesRead) > chunk->FromFileHandle.ByteRange.Length.QuadPart)
-        { 
-            bytesRead = chunk->FromFileHandle.ByteRange.Length.QuadPart - bytesTotal; 
-        }
-
-        memcpy(buf, pIoBuffer + dwDataStartOffset, bytesRead);
-
-        buf += bytesRead;
-        bytesTotal += bytesRead;
-
-        if(was_eof != 0)
-            chunk->FromFileHandle.ByteRange.Length.QuadPart = bytesTotal;
-    }
-
-Done:
-    if(NULL != pIoBuffer)
-    {
-        VirtualFree(pIoBuffer, 0, MEM_RELEASE);
-    }
-
-    if(INVALID_HANDLE_VALUE != hIoEvent)
-    {
-        CloseHandle(hIoEvent);
-    }
-
-    return hr;
-}
-
 /*
  * Read request body from IIS structures, copy it over into
  * Apache buckets and then assign back the entire flatten body
@@ -506,297 +380,6 @@ static HRESULT SaveRequestBodyToRequestRec(RequestStoredContext* rsc)
     return S_OK;
 }
 
-REQUEST_NOTIFICATION_STATUS
-CMyHttpModule::OnSendResponse(
-    IN IHttpContext * pHttpContext,
-    IN ISendResponseProvider * pResponseProvider
-)
-{
-    RequestStoredContext* rsc = dynamic_cast<RequestStoredContext*>(pHttpContext->GetModuleContextContainer()->GetModuleContext(g_pModuleContext));
-
-    CriticalSectionLock lock{cs};
-    // here we must check if response body processing is enabled
-    //
-    if (!rsc || !rsc->requestRec || rsc->responseBuffer != nullptr || !rsc->responseProcessingEnabled)
-    {
-        goto Exit;
-    }
-
-    // If we have offloaded request processing to the thread pool
-    // we need to wait for its completion before we can proceed
-    if (rsc->detectionProcessing.valid()) {
-        rsc->detectionProcessing.get();
-    }
-
-    HRESULT hr = S_OK;
-    IHttpResponse *pHttpResponse = NULL;
-    HTTP_RESPONSE *pRawHttpResponse = NULL;
-    HTTP_BYTE_RANGE *pFileByteRange = NULL;
-    HTTP_DATA_CHUNK *pSourceDataChunk = NULL;
-    LARGE_INTEGER  lFileSize;
-    REQUEST_NOTIFICATION_STATUS ret = RQ_NOTIFICATION_CONTINUE;
-    ULONGLONG ulTotalLength = 0;
-    DWORD c;
-    request_rec *r = rsc->requestRec.get();
-
-    pHttpResponse = pHttpContext->GetResponse();
-    pRawHttpResponse = pHttpResponse->GetRawHttpResponse();
-
-    // here we must add handling of chunked response
-    // apparently IIS 7 calls this handler once per chunk
-    // see: http://stackoverflow.com/questions/4385249/how-to-buffer-and-process-chunked-data-before-sending-headers-in-iis7-native-mod
-
-    if(pRawHttpResponse->EntityChunkCount == 0)
-        goto Exit;
-
-    // here we must transfer response headers
-    //
-    USHORT ctcch = 0;
-    char *ct = (char *)pHttpResponse->GetHeader(HttpHeaderContentType, &ctcch);
-    char *ctz = ZeroTerminate(ct, ctcch, r->pool);
-
-    // assume HTML if content type not set
-    // without this output filter would not buffer response and processing would hang
-    //
-    if(ctz[0] == 0)
-        ctz = "text/html";
-
-    r->content_type = ctz;
-
-#define _TRANSHEADER(id,str) if(pRawHttpResponse->Headers.KnownHeaders[id].pRawValue != NULL) \
-    {\
-        apr_table_setn(r->headers_out, str, \
-            ZeroTerminate(pRawHttpResponse->Headers.KnownHeaders[id].pRawValue, pRawHttpResponse->Headers.KnownHeaders[id].RawValueLength, r->pool)); \
-    }
-
-    _TRANSHEADER(HttpHeaderCacheControl, "Cache-Control");
-    _TRANSHEADER(HttpHeaderConnection, "Connection");
-    _TRANSHEADER(HttpHeaderDate, "Date");
-    _TRANSHEADER(HttpHeaderKeepAlive, "Keep-Alive");             
-    _TRANSHEADER(HttpHeaderPragma, "Pragma");                
-    _TRANSHEADER(HttpHeaderTrailer, "Trailer");               
-    _TRANSHEADER(HttpHeaderTransferEncoding, "Transfer-Encoding");      
-    _TRANSHEADER(HttpHeaderUpgrade, "Upgrade");               
-    _TRANSHEADER(HttpHeaderVia, "Via");                   
-    _TRANSHEADER(HttpHeaderWarning, "Warning");               
-    _TRANSHEADER(HttpHeaderAllow, "Allow");                 
-    _TRANSHEADER(HttpHeaderContentLength, "Content-Length");         
-    _TRANSHEADER(HttpHeaderContentType, "Content-Type");           
-    _TRANSHEADER(HttpHeaderContentEncoding, "Content-Encoding");       
-    _TRANSHEADER(HttpHeaderContentLanguage, "Content-Language");       
-    _TRANSHEADER(HttpHeaderContentLocation, "Content-Location");       
-    _TRANSHEADER(HttpHeaderContentMd5, "Content-Md5");            
-    _TRANSHEADER(HttpHeaderContentRange, "Content-Range");          
-    _TRANSHEADER(HttpHeaderExpires, "Expires");               
-    _TRANSHEADER(HttpHeaderLastModified, "Last-Modified");          
-    _TRANSHEADER(HttpHeaderAcceptRanges, "Accept-Ranges");
-    _TRANSHEADER(HttpHeaderAge, "Age");                   
-    _TRANSHEADER(HttpHeaderEtag, "Etag");                  
-    _TRANSHEADER(HttpHeaderLocation, "Location");              
-    _TRANSHEADER(HttpHeaderProxyAuthenticate, "Proxy-Authenticate");     
-    _TRANSHEADER(HttpHeaderRetryAfter, "Retry-After");            
-    _TRANSHEADER(HttpHeaderServer, "Server");                
-    _TRANSHEADER(HttpHeaderSetCookie, "Set-Cookie");             
-    _TRANSHEADER(HttpHeaderVary, "Vary");                  
-    _TRANSHEADER(HttpHeaderWwwAuthenticate, "Www-Authenticate");
-
-#undef    _TRANSHEADER
-
-    for(int i = 0; i < pRawHttpResponse->Headers.UnknownHeaderCount; i++)
-    {
-        apr_table_setn(r->headers_out, 
-            ZeroTerminate(pRawHttpResponse->Headers.pUnknownHeaders[i].pName, pRawHttpResponse->Headers.pUnknownHeaders[i].NameLength, r->pool), 
-            ZeroTerminate(pRawHttpResponse->Headers.pUnknownHeaders[i].pRawValue, pRawHttpResponse->Headers.pUnknownHeaders[i].RawValueLength, r->pool));
-    }
-
-    r->content_encoding = apr_table_get(r->headers_out, "Content-Encoding");
-    //r->content_type = apr_table_get(r->headers_out, "Content-Type");        -- already set above
-
-    const char *lng = apr_table_get(r->headers_out, "Content-Languages");
-
-    if(lng != NULL)
-    {
-        r->content_languages = apr_array_make(r->pool, 1, sizeof(const char *));
-
-        *(const char **)apr_array_push(r->content_languages) = lng;
-    }
-
-    // Disable kernel caching for this response
-    // Probably we don't have to do it for ModSecurity
-
-    //pHttpContext->GetResponse()->DisableKernelCache(
-    //        IISCacheEvents::HTTPSYS_CACHEABLE::HANDLER_HTTPSYS_UNFRIENDLY);
-
-    for(c = 0; c < pRawHttpResponse->EntityChunkCount; c++ )
-    {
-        pSourceDataChunk = &pRawHttpResponse->pEntityChunks[ c ];
-
-        switch( pSourceDataChunk->DataChunkType )
-        {
-            case HttpDataChunkFromMemory:
-                ulTotalLength += pSourceDataChunk->FromMemory.BufferLength;
-                break;
-            case HttpDataChunkFromFileHandle:
-                pFileByteRange = &pSourceDataChunk->FromFileHandle.ByteRange;
-                //
-                // File chunks may contain by ranges with unspecified length 
-                // (HTTP_BYTE_RANGE_TO_EOF).  In order to send parts of such a chunk, 
-                // its necessary to know when the chunk is finished, and
-                // we need to move to the next chunk.
-                //              
-                if ( pFileByteRange->Length.QuadPart == HTTP_BYTE_RANGE_TO_EOF)
-                {
-                    if ( GetFileType( pSourceDataChunk->FromFileHandle.FileHandle ) == 
-                                    FILE_TYPE_DISK )
-                    {
-                        if ( !GetFileSizeEx( pSourceDataChunk->FromFileHandle.FileHandle,
-                                             &lFileSize ) )
-                        {
-                            DWORD dwError = GetLastError();
-                            hr = HRESULT_FROM_WIN32(dwError);
-                            goto Finished;
-                        }
-
-                        // put the resolved file length in the chunk, replacing 
-                        // HTTP_BYTE_RANGE_TO_EOF
-                        pFileByteRange->Length.QuadPart = 
-                              lFileSize.QuadPart - pFileByteRange->StartingOffset.QuadPart;
-                    }
-                    else
-                    {
-                        hr = HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
-                        goto Finished;                        
-                    }
-                }  
-
-                ulTotalLength += pFileByteRange->Length.QuadPart;
-                break;
-            default:
-                // TBD: consider implementing HttpDataChunkFromFragmentCache, 
-                // and HttpDataChunkFromFragmentCacheEx
-                hr = HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
-                goto Finished;                        
-        }
-    }
-
-    rsc->responseBuffer = (char *)apr_palloc(rsc->requestRec->pool, ulTotalLength);
-
-    ulTotalLength = 0;
-
-    for(c = 0; c < pRawHttpResponse->EntityChunkCount; c++ )
-    {
-        pSourceDataChunk = &pRawHttpResponse->pEntityChunks[ c ];
-
-        switch( pSourceDataChunk->DataChunkType )
-        {
-            case HttpDataChunkFromMemory:
-                memcpy(rsc->responseBuffer + ulTotalLength, pSourceDataChunk->FromMemory.pBuffer, pSourceDataChunk->FromMemory.BufferLength);
-                ulTotalLength += pSourceDataChunk->FromMemory.BufferLength;
-                break;
-            case HttpDataChunkFromFileHandle:
-                pFileByteRange = &pSourceDataChunk->FromFileHandle.ByteRange;
-
-                if(ReadFileChunk(pSourceDataChunk, rsc->responseBuffer + ulTotalLength) != S_OK)
-                {
-                    DWORD dwErr = GetLastError();
-
-                    hr = HRESULT_FROM_WIN32(dwErr);
-                    goto Finished;
-                }
-
-                ulTotalLength += pFileByteRange->Length.QuadPart;
-                break;
-            default:
-                // TBD: consider implementing HttpDataChunkFromFragmentCache, 
-                // and HttpDataChunkFromFragmentCacheEx
-                hr = HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
-                goto Finished;                        
-        }
-    }
-
-    rsc->responseLength = ulTotalLength;
-
-    //
-    // If there's no content-length set, we need to set it to avoid chunked transfer mode
-    // We can only do it if there is it's the only response to be sent.
-    //
-
-    DWORD dwFlags = pResponseProvider->GetFlags();
-
-    if (pResponseProvider->GetHeadersBeingSent() && 
-         (dwFlags & HTTP_SEND_RESPONSE_FLAG_MORE_DATA) == 0 &&
-         pHttpContext->GetResponse()->GetHeader(HttpHeaderContentLength) == NULL)    
-    {
-        CHAR szLength[21]; //Max length for a 64 bit int is 20
-
-         ZeroMemory(szLength, sizeof(szLength));
-
-         hr = StringCchPrintfA(
-                    szLength, 
-                    sizeof(szLength) / sizeof(CHAR) - 1, "%d", 
-                    ulTotalLength);
-
-        if(FAILED(hr))
-        {
-            goto Finished;      
-        }
-
-         hr = pHttpContext->GetResponse()->SetHeader(
-                    HttpHeaderContentLength, 
-                    szLength, 
-                    (USHORT)strlen(szLength),
-                    TRUE);
-
-        if(FAILED(hr))
-        {
-            goto Finished;      
-        }
-    }
-
-Finished:
-
-    int status = modsecProcessResponse(r);
-
-    // the logic here is temporary, needs clarification
-    //
-    if(status != 0 && status != -1)
-    {
-        pHttpContext->GetResponse()->Clear();
-        pHttpContext->GetResponse()->SetStatus(status, "ModSecurity Action");
-        pHttpContext->SetRequestHandled();
-
-        rsc->FinishRequest();
-        
-        return RQ_NOTIFICATION_FINISH_REQUEST;
-    }
-Exit:
-    // temporary hack, in reality OnSendRequest theoretically could possibly come before OnEndRequest
-    //
-    if(rsc != NULL)
-        rsc->FinishRequest();
-        
-    return RQ_NOTIFICATION_CONTINUE;
-}
-
-REQUEST_NOTIFICATION_STATUS
-CMyHttpModule::OnPostEndRequest(
-    IN IHttpContext * pHttpContext,
-    IN IHttpEventProvider * pProvider
-)
-{
-    RequestStoredContext* rsc = dynamic_cast<RequestStoredContext*>(pHttpContext->GetModuleContextContainer()->GetModuleContext(g_pModuleContext));
-
-    // only finish request if OnSendResponse have been called already
-    //
-    if(rsc != nullptr && rsc->responseBuffer != nullptr)
-    {
-        CriticalSectionLock lock{cs};
-        rsc->FinishRequest();
-    }
-
-    return RQ_NOTIFICATION_CONTINUE;
-}
-
 REQUEST_NOTIFICATION_STATUS
 CMyHttpModule::OnBeginRequest(IHttpContext* httpContext, IHttpEventProvider* provider)
 {
@@ -1165,93 +748,9 @@ CMyHttpModule::OnBeginRequest(IHttpContext* httpContext, IHttpEventProvider* pro
     return RQ_NOTIFICATION_CONTINUE;
 }
 
-apr_status_t ReadResponseCallback(request_rec *r, char *buf, unsigned int length, unsigned int *readcnt, int *is_eos)
-{
-    RequestStoredContext* rsc = RetrieveIISContext(r);
-
-    *readcnt = 0;
-
-    if(rsc == nullptr || rsc->responseBuffer == nullptr)
-    {
-        *is_eos = 1;
-        return APR_SUCCESS;
-    }
-
-    unsigned int size = length;
-
-    if(size > rsc->responseLength - rsc->responsePosition)
-        size = rsc->responseLength - rsc->responsePosition;
-
-    memcpy(buf, rsc->responseBuffer + rsc->responsePosition, size);
-
-    *readcnt = size;
-    rsc->responsePosition += size;
-
-    if(rsc->responsePosition >= rsc->responseLength)
-        *is_eos = 1;
-
-    return APR_SUCCESS;
-}
-
-apr_status_t WriteResponseCallback(request_rec *r, char *buf, unsigned int length)
-{
-    RequestStoredContext* rsc = RetrieveIISContext(r);
-
-    if(!rsc || !rsc->requestRec || rsc->responseBuffer == nullptr)
-        return APR_SUCCESS;
-
-    IHttpContext *pHttpContext = rsc->httpContext;
-    IHttpResponse *pHttpResponse = pHttpContext->GetResponse();
-    HTTP_RESPONSE *pRawHttpResponse = pHttpResponse->GetRawHttpResponse();
-    HTTP_DATA_CHUNK *pDataChunk = (HTTP_DATA_CHUNK *)apr_palloc(rsc->requestRec->pool, sizeof(HTTP_DATA_CHUNK));
-
-    pRawHttpResponse->EntityChunkCount = 0;
-
-    // since we clean the APR pool at the end of OnSendRequest, we must get IIS-managed memory chunk
-    //
-    void *reqbuf = pHttpContext->AllocateRequestMemory(length);
-
-    memcpy(reqbuf, buf, length);
-
-    pDataChunk->DataChunkType = HttpDataChunkFromMemory;
-    pDataChunk->FromMemory.pBuffer = reqbuf;
-    pDataChunk->FromMemory.BufferLength = length;
-
-    CHAR szLength[21]; //Max length for a 64 bit int is 20
-
-    ZeroMemory(szLength, sizeof(szLength));
-
-    HRESULT hr = StringCchPrintfA(
-            szLength, 
-            sizeof(szLength) / sizeof(CHAR) - 1, "%d", 
-            length);
-
-    if(FAILED(hr))
-    {
-        // not possible
-    }
-
-    hr = pHttpResponse->SetHeader(
-            HttpHeaderContentLength, 
-            szLength, 
-            (USHORT)strlen(szLength),
-            TRUE);
-
-    if(FAILED(hr))
-    {
-        // possible, but there's nothing we can do
-    }
-
-    pHttpResponse->WriteEntityChunkByReference(pDataChunk);
-
-    return APR_SUCCESS;
-}
-
 CMyHttpModule::CMyHttpModule()
 {
     modsecSetLogHook(this, Log);
-    modsecSetReadResponse(ReadResponseCallback);
-    modsecSetWriteResponse(WriteResponseCallback);
 
     server_rec* s = modsecInit();
     DWORD size = MAX_COMPUTERNAME_LENGTH + 1;
diff --git a/iis/mymodule.h b/iis/mymodule.h
index 83d7adb697..c13e4af1da 100644
--- a/iis/mymodule.h
+++ b/iis/mymodule.h
@@ -33,16 +33,8 @@ class CMyHttpModule
     REQUEST_NOTIFICATION_STATUS
     OnBeginRequest(IHttpContext*, IHttpEventProvider*) override;
 
-    REQUEST_NOTIFICATION_STATUS
-    OnSendResponse(IHttpContext*, ISendResponseProvider*) override;
-
-    REQUEST_NOTIFICATION_STATUS
-    OnPostEndRequest(IHttpContext*, IHttpEventProvider*) override;
-
     void Dispose() override;
 
-    HRESULT ReadFileChunk(HTTP_DATA_CHUNK* chunk, char* buf);
-
     BOOL WriteEventViewerLog(LPCSTR szNotification, WORD category = EVENTLOG_INFORMATION_TYPE);
 
 private:

From 20e0de83f489a359dae7be877670ebc096a3e716 Mon Sep 17 00:00:00 2001
From: Vladimir Krivopalov <vlkrivop@microsoft.com>
Date: Wed, 20 Mar 2019 14:59:28 -0700
Subject: [PATCH 40/58] Remove unused/unneeded fields, wrappers and helpers.

Signed-off-by: Vladimir Krivopalov <vlkrivop@microsoft.com>
---
 iis/mymodule.cpp | 81 +++---------------------------------------------
 1 file changed, 4 insertions(+), 77 deletions(-)

diff --git a/iis/mymodule.cpp b/iis/mymodule.cpp
index 3b225ea5e9..971821e2bb 100644
--- a/iis/mymodule.cpp
+++ b/iis/mymodule.cpp
@@ -19,7 +19,6 @@
 #include <string>
 #include <cctype>
 #include <memory>
-#include <future>
 
 //  IIS7 Server API header file
 #include <Windows.h>
@@ -36,7 +35,6 @@
 
 #include "winsock2.h"
 
-#include "asio/packaged_task.hpp"
 #include "asio/post.hpp"
 
 // These helpers make sure that the underlying structures
@@ -57,28 +55,11 @@ RequestRecPtr MakeRequestRec(conn_rec* c, directory_config* config)
 }
 
 struct RequestStoredContext
-    : IHttpStoredContext
 {
     ConnRecPtr connRec;
     RequestRecPtr requestRec;
     IHttpContext* httpContext;
     IHttpEventProvider* provider;
-    char* responseBuffer = nullptr;
-    ULONGLONG responseLength = 0;
-    ULONGLONG responsePosition = 0;
-    bool responseProcessingEnabled = false;
-    std::future<int> detectionProcessing;
-
-    void CleanupStoredContext() override
-    {
-        delete this;
-    }
-
-    void FinishRequest()
-    {
-        requestRec.reset();
-        connRec.reset();
-    }
 };
 
 char *GetIpAddr(apr_pool_t *pool, PSOCKADDR pAddr)
@@ -239,48 +220,6 @@ static void Log(void *obj, int level, char *str)
     mod->WriteEventViewerLog(str, logcat);
 }
 
-#define NOTE_IIS "iis-tx-context"
-
-void StoreIISContext(request_rec *r, RequestStoredContext *rsc)
-{
-    apr_table_setn(r->notes, NOTE_IIS, (const char *)rsc);
-}
-
-RequestStoredContext *RetrieveIISContext(request_rec *r)
-{
-    RequestStoredContext *msr = NULL;
-    request_rec *rx = NULL;
-
-    /* Look in the current request first. */
-    msr = (RequestStoredContext *)apr_table_get(r->notes, NOTE_IIS);
-    if (msr != NULL) {
-        //msr->r = r;
-        return msr;
-    }
-
-    /* If this is a subrequest then look in the main request. */
-    if (r->main != NULL) {
-        msr = (RequestStoredContext *)apr_table_get(r->main->notes, NOTE_IIS);
-        if (msr != NULL) {
-            //msr->r = r;
-            return msr;
-        }
-    }
-
-    /* If the request was redirected then look in the previous requests. */
-    rx = r->prev;
-    while(rx != NULL) {
-        msr = (RequestStoredContext *)apr_table_get(rx->notes, NOTE_IIS);
-        if (msr != NULL) {
-            //msr->r = r;
-            return msr;
-        }
-        rx = rx->prev;
-    }
-
-    return NULL;
-}
-
 /*
  * Read request body from IIS structures, copy it over into
  * Apache buckets and then assign back the entire flatten body
@@ -476,12 +415,6 @@ CMyHttpModule::OnBeginRequest(IHttpContext* httpContext, IHttpEventProvider* pro
     rsc->requestRec = requestRec;
     rsc->httpContext = httpContext;
     rsc->provider = provider;
-    rsc->responseProcessingEnabled = (config->config->resbody_access == 1);
-    RequestStoredContext* context = rsc.get();
-
-    StoreIISContext(r, rsc.get());
-
-    httpContext->GetModuleContextContainer()->SetModuleContext(rsc.release(), g_pModuleContext);
 
     HTTP_REQUEST *req = httpContext->GetRequest()->GetRawHttpRequest();
 
@@ -710,9 +643,9 @@ CMyHttpModule::OnBeginRequest(IHttpContext* httpContext, IHttpEventProvider* pro
     c->remote_host = NULL;
 
     if (config->config->reqbody_access) {
-        hr = SaveRequestBodyToRequestRec(context);
+        hr = SaveRequestBodyToRequestRec(rsc.get());
         if (FAILED(hr)) {
-            context->provider->SetErrorStatus(hr);
+            rsc->provider->SetErrorStatus(hr);
             return RQ_NOTIFICATION_FINISH_REQUEST;
         }
     }
@@ -720,14 +653,8 @@ CMyHttpModule::OnBeginRequest(IHttpContext* httpContext, IHttpEventProvider* pro
     if (config->config->is_enabled == MODSEC_DETECTION_ONLY)
     {
         // We post the processing task to the thread pool to happen in the background.
-        // We store the future to track and wait for this processing in case if we also
-        // need to process the response because we need request processing to finish
-        // before we can start with the response.
-        context->detectionProcessing = asio::post(threadPool,
-            std::packaged_task<int()> {
-            [connRec, requestRec] {
-                return modsecProcessRequest(requestRec.get());
-            }
+        asio::post(threadPool, [connRec, requestRec] {
+            return modsecProcessRequest(requestRec.get());
         });
     }
     else

From 788aab9716caac48b410119bbd859935272892f9 Mon Sep 17 00:00:00 2001
From: Vladimir Krivopalov <vlkrivop@microsoft.com>
Date: Thu, 21 Mar 2019 12:16:18 -0700
Subject: [PATCH 41/58] Simplify per-request context hanlding.

- Use std::unique_ptr-s instead of std::shared_ptr-s as we don't need
any sharing (and inheren reference counter locking) any longer.
- Allocate per-request context on stack rather than on heap.

Signed-off-by: Vladimir Krivopalov <vlkrivop@microsoft.com>
---
 iis/mymodule.cpp | 105 +++++++++++++++++++++++++++++++++++------------
 1 file changed, 78 insertions(+), 27 deletions(-)

diff --git a/iis/mymodule.cpp b/iis/mymodule.cpp
index 971821e2bb..c81d9d517c 100644
--- a/iis/mymodule.cpp
+++ b/iis/mymodule.cpp
@@ -39,27 +39,57 @@
 
 // These helpers make sure that the underlying structures
 // are correctly released on any exit path due to RAII.
-using ConnRecPtr = std::shared_ptr<conn_rec>;
-using RequestRecPtr = std::shared_ptr<request_rec>;
+using ConnRecPtr = std::unique_ptr<conn_rec, decltype(modsecFinishConnection)*>;
+using RequestRecPtr = std::unique_ptr<request_rec, decltype(modsecFinishRequest)*>;
 
-ConnRecPtr MakeConnReq()
+static ConnRecPtr MakeConnReq()
 {
     ConnRecPtr c{modsecNewConnection(), modsecFinishConnection};
     modsecProcessConnection(c.get());
     return c;
 }
 
-RequestRecPtr MakeRequestRec(conn_rec* c, directory_config* config)
+static RequestRecPtr MakeRequestRec(conn_rec* c, directory_config* config)
 {
     return {modsecNewRequest(c, config), modsecFinishRequest};
 }
 
-struct RequestStoredContext
+class AprRequestContext
 {
+private:
     ConnRecPtr connRec;
     RequestRecPtr requestRec;
-    IHttpContext* httpContext;
-    IHttpEventProvider* provider;
+
+public:
+    explicit AprRequestContext(directory_config* config)
+        : connRec{MakeConnReq()}
+        , requestRec{MakeRequestRec(connRec.get(), config)}
+    {}
+
+    AprRequestContext(const AprRequestContext&) = delete;
+    AprRequestContext& operator=(const AprRequestContext&) = delete;
+
+    AprRequestContext(AprRequestContext&& rhs)
+        : connRec(std::move(rhs.connRec))
+        , requestRec(std::move(rhs.requestRec))
+    {}
+
+    AprRequestContext& operator=(AprRequestContext&& rhs)
+    {
+        connRec = std::move(rhs.connRec);
+        requestRec = std::move(rhs.requestRec);
+        return *this;
+    }
+
+    conn_rec* GetConnection() const
+    {
+        return connRec.get();
+    }
+
+    request_rec* GetRequest() const
+    {
+        return requestRec.get();
+    }
 };
 
 char *GetIpAddr(apr_pool_t *pool, PSOCKADDR pAddr)
@@ -226,11 +256,11 @@ static void Log(void *obj, int level, char *str)
  * to IHttpRequest.
  * If the request body is chunked, it will be transformed into fixed-length.
 */
-static HRESULT SaveRequestBodyToRequestRec(RequestStoredContext* rsc)
+static HRESULT SaveRequestBodyToRequestRec(IHttpContext* httpContext, const AprRequestContext& aprContext)
 {
-    request_rec* aprRequest = rsc->requestRec.get();
-    conn_rec* conn = rsc->connRec.get();
-    IHttpRequest* iisRequest = rsc->httpContext->GetRequest();
+    request_rec* aprRequest = aprContext.GetRequest();
+    conn_rec* conn = aprContext.GetConnection();
+    IHttpRequest* iisRequest = httpContext->GetRequest();
     apr_bucket_brigade* brigade = apr_brigade_create(conn->pool, conn->bucket_alloc);
     if (brigade == nullptr)
     {
@@ -307,7 +337,7 @@ static HRESULT SaveRequestBodyToRequestRec(RequestStoredContext* rsc)
 
         // since we clean the APR pool at the end of OnSendRequest, we must get IIS-managed memory chunk
         //
-        char* requestBuffer = static_cast<char*>(rsc->httpContext->AllocateRequestMemory(contentLength));
+        char* requestBuffer = static_cast<char*>(httpContext->AllocateRequestMemory(contentLength));
         status = apr_brigade_flatten(brigade, requestBuffer, reinterpret_cast<apr_size_t*>(&contentLength));
         if (status != APR_SUCCESS)
         {
@@ -405,16 +435,9 @@ CMyHttpModule::OnBeginRequest(IHttpContext* httpContext, IHttpEventProvider* pro
         delete path;
     }
 
-    ConnRecPtr connRec = MakeConnReq();
-    conn_rec* c = connRec.get();
-    RequestRecPtr requestRec = MakeRequestRec(c, config->config);
-    request_rec* r = requestRec.get();
-
-    auto rsc = std::make_unique<RequestStoredContext>();
-    rsc->connRec = connRec;
-    rsc->requestRec = requestRec;
-    rsc->httpContext = httpContext;
-    rsc->provider = provider;
+    AprRequestContext aprContext{config->config};
+    conn_rec* c = aprContext.GetConnection();
+    request_rec* r = aprContext.GetRequest();
 
     HTTP_REQUEST *req = httpContext->GetRequest()->GetRawHttpRequest();
 
@@ -643,19 +666,47 @@ CMyHttpModule::OnBeginRequest(IHttpContext* httpContext, IHttpEventProvider* pro
     c->remote_host = NULL;
 
     if (config->config->reqbody_access) {
-        hr = SaveRequestBodyToRequestRec(rsc.get());
+        hr = SaveRequestBodyToRequestRec(httpContext, aprContext);
         if (FAILED(hr)) {
-            rsc->provider->SetErrorStatus(hr);
+            provider->SetErrorStatus(hr);
             return RQ_NOTIFICATION_FINISH_REQUEST;
         }
     }
 
     if (config->config->is_enabled == MODSEC_DETECTION_ONLY)
     {
+        // This could have been a simple lambda with generalized capture but C++11 doesn't support it yet.
+        // Can be replaced/simplified in C++14.
+        class BackgroundRequestProcessingTask
+        {
+        private:
+            AprRequestContext ctx;
+        public:
+            explicit BackgroundRequestProcessingTask(AprRequestContext&& ctx)
+                : ctx(std::move(ctx))
+            {}
+
+            BackgroundRequestProcessingTask(const BackgroundRequestProcessingTask&) = delete;
+            BackgroundRequestProcessingTask& operator=(const BackgroundRequestProcessingTask&) = delete;
+
+            BackgroundRequestProcessingTask(BackgroundRequestProcessingTask&& rhs)
+                : ctx(std::move(rhs.ctx))
+            {
+            }
+
+            BackgroundRequestProcessingTask& operator=(BackgroundRequestProcessingTask&& rhs)
+            {
+                ctx = std::move(rhs.ctx);
+                return *this;
+            }
+
+            int operator()() const {
+                return modsecProcessRequest(ctx.GetRequest());
+            }
+        };
+
         // We post the processing task to the thread pool to happen in the background.
-        asio::post(threadPool, [connRec, requestRec] {
-            return modsecProcessRequest(requestRec.get());
-        });
+        asio::post(threadPool, BackgroundRequestProcessingTask{ std::move(aprContext) });
     }
     else
     {

From bc9cf9b61793acab870c44e1f5e22482b3e4181f Mon Sep 17 00:00:00 2001
From: Vladimir Krivopalov <vlkrivop@microsoft.com>
Date: Thu, 9 May 2019 10:09:32 -0700
Subject: [PATCH 42/58] Update Asio submodule: 1.12.2 -> 1.13.0

Signed-off-by: Vladimir Krivopalov <vlkrivop@microsoft.com>
---
 .gitmodules | 2 +-
 iis/asio    | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/.gitmodules b/.gitmodules
index 6a5a4a47b1..accdd7caaf 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,4 +1,4 @@
 [submodule "iis/asio"]
 	path = iis/asio
 	url = https://github.com/chriskohlhoff/asio.git
-	branch = tags/asio-1-12-2
+	branch = tags/asio-1-13-0
diff --git a/iis/asio b/iis/asio
index 22afb86087..90f32660cd 160000
--- a/iis/asio
+++ b/iis/asio
@@ -1 +1 @@
-Subproject commit 22afb86087a77037cd296d27134756c9b0d2cb75
+Subproject commit 90f32660cd503494b3707840cfbd5434d8e9dabe

From 14cd98df1fedfe0b1b376962d88147c616fd57b4 Mon Sep 17 00:00:00 2001
From: Vladimir Krivopalov <vlkrivop@microsoft.com>
Date: Fri, 10 May 2019 18:04:49 -0700
Subject: [PATCH 43/58] Use background mode for offloaded processing. Use 12
 threads in the pool.

These settings have been chosen through a series of performance tests
and have shown the best improvement in latencies for detection mode.

Signed-off-by: Vladimir Krivopalov <vlkrivop@microsoft.com>
---
 iis/mymodule.cpp | 21 +++++++++++++++++++++
 iis/mymodule.h   |  2 +-
 2 files changed, 22 insertions(+), 1 deletion(-)

diff --git a/iis/mymodule.cpp b/iis/mymodule.cpp
index c81d9d517c..dfd97b7dc8 100644
--- a/iis/mymodule.cpp
+++ b/iis/mymodule.cpp
@@ -701,6 +701,27 @@ CMyHttpModule::OnBeginRequest(IHttpContext* httpContext, IHttpEventProvider* pro
             }
 
             int operator()() const {
+                // We put the entire thread into background mode for the time of processing.
+                // According to https://docs.microsoft.com/en-us/windows/desktop/api/processthreadsapi/nf-processthreadsapi-setthreadpriority :
+                //
+                // The THREAD_PRIORITY_* values affect the CPU scheduling priority of the thread.
+                // For threads that perform background work such as file I/O, network I/O, or data processing,
+                // it is not sufficient to adjust the CPU scheduling priority; even an idle CPU priority thread
+                // can easily interfere with system responsiveness when it uses the disk and memory.
+                // Threads that perform background work should use the THREAD_MODE_BACKGROUND_BEGIN
+                // and THREAD_MODE_BACKGROUND_END values to adjust their resource scheduling priorities;
+                // threads that interact with the user should not use THREAD_MODE_BACKGROUND_BEGIN.
+                struct BackgroundThreadMode
+                {
+                    BackgroundThreadMode() {
+                        SetThreadPriority(GetCurrentThread(), THREAD_MODE_BACKGROUND_BEGIN);
+                    }
+                    ~BackgroundThreadMode() {
+                        SetThreadPriority(GetCurrentThread(), THREAD_MODE_BACKGROUND_END);
+                    }
+                };
+
+                BackgroundThreadMode backgroundMode;
                 return modsecProcessRequest(ctx.GetRequest());
             }
         };
diff --git a/iis/mymodule.h b/iis/mymodule.h
index c13e4af1da..5b81c976f1 100644
--- a/iis/mymodule.h
+++ b/iis/mymodule.h
@@ -40,7 +40,7 @@ class CMyHttpModule
 private:
     CriticalSection cs;
     EventLogger logger;
-    asio::thread_pool threadPool;
+    asio::thread_pool threadPool{12};
     DWORD pageSize = 0;
     bool statusCallAlreadySent = false;
 };

From 701e693ed9dd8c11f19b79ea67f02fd3b15f0733 Mon Sep 17 00:00:00 2001
From: Vladimir Krivopalov <vlkrivop@microsoft.com>
Date: Tue, 14 May 2019 16:27:36 -0700
Subject: [PATCH 44/58] Fix owasp-modsecurity-crs v3.1.0 for Appveyor tests.

Signed-off-by: Vladimir Krivopalov <vlkrivop@microsoft.com>
---
 appveyor.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/appveyor.yml b/appveyor.yml
index 9a952be94c..055612f258 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -44,7 +44,7 @@ before_test:
         & "$env:SystemRoot\System32\inetsrv\appcmd.exe" set config /section:"system.webServer/ModSecurity" /"enabled:true" /"configFile:$modsec_iis_conf"
         #setup the crs repo and the modsec config
         $crs_path = "C:\projects\owasp-modsecurity-crs"
-        git clone -q https://github.com/SpiderLabs/owasp-modsecurity-crs.git $crs_path
+        git clone -b "v3.1.0" -q https://github.com/SpiderLabs/owasp-modsecurity-crs.git $crs_path
         cd "$modsec_repo\tests"
         Rename-Item -Path "$crs_path\crs-setup.conf.example" -NewName "crs-setup.conf"
         Copy-Item "$crs_path\util\regression-tests\requirements.txt" -Destination "$modsec_repo\tests" -Force

From 757a054040cea88e28183a4ea87f8cfa53d2dfcb Mon Sep 17 00:00:00 2001
From: Allan Boll <allanbo@microsoft.com>
Date: Fri, 17 May 2019 12:20:27 -0700
Subject: [PATCH 45/58] Removing generated files (#118)

Removing generated files
---
 .gitignore               |  12 ++--
 build/compile            | 142 ---------------------------------------
 nginx/modsecurity/config |  46 -------------
 3 files changed, 7 insertions(+), 193 deletions(-)
 delete mode 100755 build/compile
 delete mode 100644 nginx/modsecurity/config

diff --git a/.gitignore b/.gitignore
index f7a731d605..ba6f7e7238 100644
--- a/.gitignore
+++ b/.gitignore
@@ -37,7 +37,7 @@ Makefile
 Makefile.in
 aclocal.m4
 alp2/Makefile.in
-apache2/.dirstamp                                  
+apache2/.dirstamp
 apache2/Makefile
 apache2/Makefile.in
 apache2/ag_mdb/.deps/
@@ -51,7 +51,7 @@ apache2/waf_lock/.deps/
 apache2/waf_lock/.dirstamp
 apache2/waf_logging/.deps/
 apache2/waf_logging/.dirstamp
-apache2/waf_logging/waf_format.pb.h
+apache2/waf_logging/waf_format.pb.h
 
 apache2/waf_logging/waf_format.pb.cc
 autom4te.cache/
@@ -69,10 +69,11 @@ build/ltversion.m4
 build/lt~obsolete.m4
 build/missing
 build/test-driver
+build/compile
 config.status
 configure
-doc/Makefile.in                                
-ext/Makefile.in                                    
+doc/Makefile.in
+ext/Makefile.in
 libtool
 mlogc/Makefile.in
 standalone/.libs/
@@ -90,4 +91,5 @@ tests/run-regression-tests.pl
 tests/run-unit-tests.pl
 tools/Makefile
 tools/Makefile.in
-tools/rules-updater.pl
\ No newline at end of file
+tools/rules-updater.pl
+nginx/modsecurity/config
diff --git a/build/compile b/build/compile
deleted file mode 100755
index 1b1d232169..0000000000
--- a/build/compile
+++ /dev/null
@@ -1,142 +0,0 @@
-#! /bin/sh
-# Wrapper for compilers which do not understand `-c -o'.
-
-scriptversion=2005-05-14.22
-
-# Copyright (C) 1999, 2000, 2003, 2004, 2005 Free Software Foundation, Inc.
-# Written by Tom Tromey <tromey@cygnus.com>.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2, or (at your option)
-# any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
-# As a special exception to the GNU General Public License, if you
-# distribute this file as part of a program that contains a
-# configuration script generated by Autoconf, you may include it under
-# the same distribution terms that you use for the rest of that program.
-
-# This file is maintained in Automake, please report
-# bugs to <bug-automake@gnu.org> or send patches to
-# <automake-patches@gnu.org>.
-
-case $1 in
-  '')
-     echo "$0: No command.  Try \`$0 --help' for more information." 1>&2
-     exit 1;
-     ;;
-  -h | --h*)
-    cat <<\EOF
-Usage: compile [--help] [--version] PROGRAM [ARGS]
-
-Wrapper for compilers which do not understand `-c -o'.
-Remove `-o dest.o' from ARGS, run PROGRAM with the remaining
-arguments, and rename the output as expected.
-
-If you are trying to build a whole package this is not the
-right script to run: please start by reading the file `INSTALL'.
-
-Report bugs to <bug-automake@gnu.org>.
-EOF
-    exit $?
-    ;;
-  -v | --v*)
-    echo "compile $scriptversion"
-    exit $?
-    ;;
-esac
-
-ofile=
-cfile=
-eat=
-
-for arg
-do
-  if test -n "$eat"; then
-    eat=
-  else
-    case $1 in
-      -o)
-	# configure might choose to run compile as `compile cc -o foo foo.c'.
-	# So we strip `-o arg' only if arg is an object.
-	eat=1
-	case $2 in
-	  *.o | *.obj)
-	    ofile=$2
-	    ;;
-	  *)
-	    set x "$@" -o "$2"
-	    shift
-	    ;;
-	esac
-	;;
-      *.c)
-	cfile=$1
-	set x "$@" "$1"
-	shift
-	;;
-      *)
-	set x "$@" "$1"
-	shift
-	;;
-    esac
-  fi
-  shift
-done
-
-if test -z "$ofile" || test -z "$cfile"; then
-  # If no `-o' option was seen then we might have been invoked from a
-  # pattern rule where we don't need one.  That is ok -- this is a
-  # normal compilation that the losing compiler can handle.  If no
-  # `.c' file was seen then we are probably linking.  That is also
-  # ok.
-  exec "$@"
-fi
-
-# Name of file we expect compiler to create.
-cofile=`echo "$cfile" | sed -e 's|^.*/||' -e 's/\.c$/.o/'`
-
-# Create the lock directory.
-# Note: use `[/.-]' here to ensure that we don't use the same name
-# that we are using for the .o file.  Also, base the name on the expected
-# object file name, since that is what matters with a parallel build.
-lockdir=`echo "$cofile" | sed -e 's|[/.-]|_|g'`.d
-while true; do
-  if mkdir "$lockdir" >/dev/null 2>&1; then
-    break
-  fi
-  sleep 1
-done
-# FIXME: race condition here if user kills between mkdir and trap.
-trap "rmdir '$lockdir'; exit 1" 1 2 15
-
-# Run the compile.
-"$@"
-ret=$?
-
-if test -f "$cofile"; then
-  mv "$cofile" "$ofile"
-elif test -f "${cofile}bj"; then
-  mv "${cofile}bj" "$ofile"
-fi
-
-rmdir "$lockdir"
-exit $ret
-
-# Local Variables:
-# mode: shell-script
-# sh-indentation: 2
-# eval: (add-hook 'write-file-hooks 'time-stamp)
-# time-stamp-start: "scriptversion="
-# time-stamp-format: "%:y-%02m-%02d.%02H"
-# time-stamp-end: "$"
-# End:
diff --git a/nginx/modsecurity/config b/nginx/modsecurity/config
deleted file mode 100644
index fe8471ba3d..0000000000
--- a/nginx/modsecurity/config
+++ /dev/null
@@ -1,46 +0,0 @@
-#!/bin/sh
-
-CFLAGS="$CFLAGS \
-     -I/usr/include/apr-1.0  \
-     -I/usr/include/apr-1.0 -I/usr/include \
-    -I/usr/include/apache2 \
-    -I/usr/include/libxml2 \
-    -DWITH_LUA -I/usr/include/lua5.1   \
-    -DWITH_PCRE_STUDY -DMODSEC_PCRE_MATCH_LIMIT=1500 -DMODSEC_PCRE_MATCH_LIMIT_RECURSION=1500  -DREQUEST_EARLY          \
-     \
-    -DWITH_YAJL -I/usr/include/yajl  "
-
-
-CORE_LIBS="$CORE_LIBS \
-     -L/usr/lib -lapr-1 \
-     -L/usr/lib -laprutil-1 \
-    -I/usr/include/apache2 \
-    -L/usr/lib/x86_64-linux-gnu -lcurl \
-    -lxml2 \
-    -llua5.1   \
-    -lpcre \
-    -L/usr/lib  -lcap \
-    -lyajl  "
-
-ngx_addon_name=ngx_http_modsecurity
-
-CORE_MODULES="$CORE_MODULES ngx_pool_context_module"
-
-HTTP_AUX_FILTER_MODULES="ngx_http_modsecurity $HTTP_AUX_FILTER_MODULES"
-
-NGX_ADDON_SRCS="$NGX_ADDON_SRCS \
-		$ngx_addon_dir/ngx_http_modsecurity.c \
-		$ngx_addon_dir/apr_bucket_nginx.c \
-		$ngx_addon_dir/ngx_pool_context.c"
-
-NGX_ADDON_DEPS="$NGX_ADDON_DEPS \
-		$ngx_addon_dir/apr_bucket_nginx.h \
-		$ngx_addon_dir/ngx_pool_context.h"
-
-CORE_LIBS="$ngx_addon_dir/../../standalone/.libs/standalone.a $CORE_LIBS"
-
-CORE_INCS="$CORE_INCS \
-	$ngx_addon_dir \
-	$ngx_addon_dir/../../standalone \
-	$ngx_addon_dir/../../apache2"
-

From 2277dc63de7a93c4c41b763e21e3f0b7c8e2a84d Mon Sep 17 00:00:00 2001
From: "Alex Z. Yang" <zhicheng.yang@microsoft.com>
Date: Sun, 19 May 2019 10:36:53 -0700
Subject: [PATCH 46/58] Get hostname from Host field in request header
 explicitly to pass into log (#119)

---
 apache2/apache2_util.c                   | 4 ++--
 nginx/modsecurity/ngx_http_modsecurity.c | 4 ++++
 2 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/apache2/apache2_util.c b/apache2/apache2_util.c
index 3ec830af19..681ed17054 100755
--- a/apache2/apache2_util.c
+++ b/apache2/apache2_util.c
@@ -476,11 +476,11 @@ static void internal_log_ex(request_rec *r, directory_config *dcfg, modsec_rec *
                             "ModSecurity not able to reopen %s file", WAF_LOG_UTIL_FILE);
                 #endif
             }
-            
+
             msc_waf_log_reopened = 0;
         }
 
-        send_waf_log(msr->modsecurity->wafjsonlog_lock, msc_waf_log_fd, str1, r->useragent_ip ? r->useragent_ip : r->connection->client_ip, log_escape(msr->mp, r->uri), dcfg->is_enabled, (char*)msr->hostname, unique_id, r);
+        send_waf_log(msr->modsecurity->wafjsonlog_lock, msc_waf_log_fd, str1, r->useragent_ip ? r->useragent_ip : r->connection->client_ip, log_escape(msr->mp, r->uri), dcfg->is_enabled, r->hostname, unique_id, r);
 #endif
 
 #if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER > 2
diff --git a/nginx/modsecurity/ngx_http_modsecurity.c b/nginx/modsecurity/ngx_http_modsecurity.c
index d0192ce739..5244160221 100644
--- a/nginx/modsecurity/ngx_http_modsecurity.c
+++ b/nginx/modsecurity/ngx_http_modsecurity.c
@@ -377,6 +377,10 @@ ngx_http_modsecurity_load_headers_in(ngx_http_request_t *r)
     req->range = apr_table_get(req->headers_in, "Range");
     req->content_type = apr_table_get(req->headers_in, "Content-Type");
     req->content_encoding = apr_table_get(req->headers_in, "Content-Encoding");
+    req->hostname = apr_table_get(req->headers_in, "Host");
+    if (req->hostname == NULL) {
+        req->hostname = "<undefined>";
+    }
 
     lang = apr_table_get(ctx->req->headers_in, "Content-Languages");
     if(lang != NULL)

From 565dc00a8c4a7a0e4037f82bbd41ba6ce8f61cdc Mon Sep 17 00:00:00 2001
From: alonzop <alonzop@users.noreply.github.com>
Date: Wed, 29 May 2019 12:50:23 -0700
Subject: [PATCH 47/58] trunk the name to 252 to allow rule info to be
 propegated to the error log (both apache & iis) (#120)

---
 apache2/re_operators.c | 40 +++++++---------------------------------
 1 file changed, 7 insertions(+), 33 deletions(-)

diff --git a/apache2/re_operators.c b/apache2/re_operators.c
index 521dcfc044..f14f396cd1 100755
--- a/apache2/re_operators.c
+++ b/apache2/re_operators.c
@@ -865,13 +865,8 @@ static int msre_op_validateHash_execute(modsec_rec *msr, msre_rule *rule, msre_v
         char *hmac = NULL, *valid = NULL;
         char *hash_link = NULL, *nlink = NULL;
 
-        if (strlen(pattern) > 252) {
-            *error_msg = apr_psprintf(msr->mp, "Request URI matched \"%.252s ...\" at %s.",
+        *error_msg = apr_psprintf(msr->mp, "Request URI matched \"%.252s ...\" at %.252s.",
                     pattern, var->name);
-        } else {
-            *error_msg = apr_psprintf(msr->mp, "Request URI matched \"%s\" at %s.",
-                    pattern, var->name);
-        }
 
         valid = strstr(target, msr->txcfg->crypto_param_name);
 
@@ -880,13 +875,8 @@ static int msre_op_validateHash_execute(modsec_rec *msr, msre_rule *rule, msre_v
             if (msr->txcfg->debuglog_level >= 9)
                 msr_log(msr, 9, "Request URI without hash parameter [%s]", target);
 
-            if (strlen(pattern) > 252) {
-                *error_msg = apr_psprintf(msr->mp, "Request URI matched \"%.252s ...\" at %s. No Hash parameter",
-                        pattern, var->name);
-            } else {
-                *error_msg = apr_psprintf(msr->mp, "Request URI matched \"%s\" at %s. No Hash parameter",
+            *error_msg = apr_psprintf(msr->mp, "Request URI matched \"%.252s ...\" at %.252s. No Hash parameter",
                         pattern, var->name);
-            }
             return 1;
         }   else    {
 
@@ -902,14 +892,8 @@ static int msre_op_validateHash_execute(modsec_rec *msr, msre_rule *rule, msre_v
             hash_link = do_hash_link(msr, (char *)nlink, HASH_ONLY);
 
             if(strcmp(hmac, hash_link) != 0)    {
-
-                if (strlen(pattern) > 252) {
-                    *error_msg = apr_psprintf(msr->mp, "Request URI matched \"%.252s ...\" at %s. Hash parameter hash value = [%s] Requested URI hash value = [%s]",
-                            pattern, var->name, hmac, hash_link);
-                } else {
-                    *error_msg = apr_psprintf(msr->mp, "Request URI matched \"%s\" at %s. Hash parameter hash value = [%s] Requested URI hash value = [%s]",
+                *error_msg = apr_psprintf(msr->mp, "Request URI matched \"%.252s ...\" at %.252s. Hash parameter hash value = [%s] Requested URI hash value = [%s]",
                             pattern, var->name, hmac, hash_link);
-                }
                 return 1;
             }
         }
@@ -1183,14 +1167,9 @@ static int msre_op_rx_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, c
 #else
         char *pattern = apr_pstrdup(msr->mp, log_escape(msr->mp, regex->pattern ? regex->pattern : "<Unknown Match>"));
 #endif
-        /* This message will be logged. */
-        if (strlen(pattern) > 252) {
-            *error_msg = apr_psprintf(msr->mp, "Pattern match \"%.252s ...\" at %s.",
-                    pattern, var->name);
-        } else {
-            *error_msg = apr_psprintf(msr->mp, "Pattern match \"%s\" at %s.",
-                    pattern, var->name);
-        }
+        /* This message will be logged. only the first 252 from the Pattern & the match */
+		*error_msg = apr_psprintf(msr->mp, "Pattern match \"%.252s\" at %.252s ....",
+			pattern, var->name);
 
         return 1;
     }
@@ -1428,13 +1407,8 @@ static int msre_op_pm_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, c
         char *match_escaped = log_escape(msr->mp, match ? match : "<Unknown Match>");
 
         /* This message will be logged. */
-        if (strlen(match_escaped) > 252) {
-            *error_msg = apr_psprintf(msr->mp, "Matched phrase \"%.252s ...\" at %s.",
-                    match_escaped, var->name);
-        } else {
-            *error_msg = apr_psprintf(msr->mp, "Matched phrase \"%s\" at %s.",
+        *error_msg = apr_psprintf(msr->mp, "Matched phrase \"%.252s ...\" at %.252s.",
                     match_escaped, var->name);
-        }
 
         /* Handle capture as tx.0=match */
         if (capture) {

From 0f123828b07f682b3cca6c6ed41483a7e825f5de Mon Sep 17 00:00:00 2001
From: Vladimir Krivopalov <vlkrivop@microsoft.com>
Date: Wed, 12 Jun 2019 15:01:00 -0700
Subject: [PATCH 48/58] Make WAF logging representation more compact by
 removing unneeded header.

Signed-off-by: Vladimir Krivopalov <vlkrivop@microsoft.com>
---
 apache2/apache2_config.c                      |  2 +-
 apache2/apache2_util.c                        |  2 +-
 apache2/waf_logging/waf_log_util.cc           | 60 +++++++++++++++++-
 ...waf_log_util_external.h => waf_log_util.h} |  7 ---
 apache2/waf_logging/waf_log_util_internal.h   | 62 -------------------
 nginx/modsecurity/ngx_http_modsecurity.c      |  2 +-
 6 files changed, 61 insertions(+), 74 deletions(-)
 rename apache2/waf_logging/{waf_log_util_external.h => waf_log_util.h} (80%)
 delete mode 100755 apache2/waf_logging/waf_log_util_internal.h

diff --git a/apache2/apache2_config.c b/apache2/apache2_config.c
index 75ede330da..8077b8813a 100755
--- a/apache2/apache2_config.c
+++ b/apache2/apache2_config.c
@@ -29,7 +29,7 @@
 #include "msc_lua.h"
 #endif
 #ifdef WAF_JSON_LOGGING_ENABLE
-#include "waf_log_util_external.h"
+#include "waf_log_util.h"
 #endif
 
 
diff --git a/apache2/apache2_util.c b/apache2/apache2_util.c
index 681ed17054..85e0c978c2 100755
--- a/apache2/apache2_util.c
+++ b/apache2/apache2_util.c
@@ -18,7 +18,7 @@
 #include "util_script.h"
 
 #ifdef WAF_JSON_LOGGING_ENABLE
-#include "waf_log_util_external.h"
+#include "waf_log_util.h"
 #include "waf_lock_external.h"
 #include "string.h"
 #endif
diff --git a/apache2/waf_logging/waf_log_util.cc b/apache2/waf_logging/waf_log_util.cc
index 3423c4d24a..3b7d2dbb7f 100755
--- a/apache2/waf_logging/waf_log_util.cc
+++ b/apache2/waf_logging/waf_log_util.cc
@@ -1,5 +1,61 @@
-#include "waf_log_util_internal.h"
-#include "waf_log_util_external.h"
+#include "waf_log_util.h"
+
+#include <fstream>
+#include <unordered_map>
+#include <jsoncons/json.hpp>
+#include <jsoncons/json_options.hpp>
+
+// For convenience
+using jsoncons::ojson;
+using jsoncons::json_options;
+using jsoncons::line_split_kind;
+
+namespace waf_logging {
+
+    struct detail
+    {
+        std::string message;
+        std::string data;
+        std::string file;
+        std::string line;
+    };
+
+    struct property
+    {
+        std::string instanceId;
+        std::string clientIp;
+        std::string clientPort;
+        std::string requestUri;
+        std::string ruleSetType;
+        std::string ruleSetVersion;
+        std::string ruleId;
+        std::string message;
+        std::string action;
+        std::string site;
+        detail details;
+        std::string hostname;
+        std::string transactionId;
+    };
+
+    struct waf_log
+    {
+        std::string resourceId;
+        std::string operationName;
+        std::string category;
+        property properties;
+    };
+}
+
+JSONCONS_TYPE_TRAITS_DECL(waf_logging::detail, message, data, file, line);
+JSONCONS_TYPE_TRAITS_DECL(waf_logging::property, instanceId, clientIp, clientPort, requestUri, ruleSetType, ruleSetVersion, ruleId, message, action, site, details, hostname, transactionId);
+JSONCONS_TYPE_TRAITS_DECL(waf_logging::waf_log, resourceId, operationName, category, properties);
+
+std::string to_json_string(const waf_logging::waf_log& log) {
+    json_options options;
+    std::string json_output;
+    encode_json(ojson{}, log, json_output, options, jsoncons::indenting::indent);
+    return json_output;
+};
 
 using namespace std;
 unordered_map<int, bool> appgw_ruleid_hash;
diff --git a/apache2/waf_logging/waf_log_util_external.h b/apache2/waf_logging/waf_log_util.h
similarity index 80%
rename from apache2/waf_logging/waf_log_util_external.h
rename to apache2/waf_logging/waf_log_util.h
index 7c9f7dcbab..1ee1e33577 100755
--- a/apache2/waf_logging/waf_log_util_external.h
+++ b/apache2/waf_logging/waf_log_util.h
@@ -10,23 +10,16 @@
 #define WAF_LOG_UTIL_OPERATION_NAME "ApplicationGatewayFirewall"
 #define WAF_LOG_UTIL_CATEGORY "ApplicationGatewayFirewallLog"
 
-#define WAF_ACTION_BLOCKED "Blocked"
-#define WAF_ACTION_DETECTED "Detected"
-#define WAF_ACTION_MATCHED "Matched"
-
 #define RULE_TYPE_OWASP_CRS "OWASP_CRS"
 
 #define RULE_HASH_SIZE 499
-#define RULES_ID_FILE "/etc/nginx/modsec/disableableRules.conf"
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 int generate_json(char** result, char* resourceId, char* operationName, char* category, char* instanceId, char* clientIP, char* clientPort, const char* requestUri, char* ruleSetType, char* ruleSetVersion, char* ruleId, char* messages, int action, int site, char* details_messages, char* details_data, char* details_file, char* details_line, const char* hostname, char* waf_unique_id);
 void free_json(char* str);
-bool rule_is_mandatory(int ruleId);
 void init_appgw_rules_id_hash();
-void strip_number(char * in);
 #ifdef __cplusplus
 }
 #endif
diff --git a/apache2/waf_logging/waf_log_util_internal.h b/apache2/waf_logging/waf_log_util_internal.h
deleted file mode 100755
index 70e475f709..0000000000
--- a/apache2/waf_logging/waf_log_util_internal.h
+++ /dev/null
@@ -1,62 +0,0 @@
-#ifndef _WAF_LOG_UTIL_INTERNAL_HEADER
-#define _WAF_LOG_UTIL_INTERNAL_HEADER
-
-#include <fstream>
-#include <unordered_map>
-#include <exception>
-#include <jsoncons/json.hpp>
-#include <jsoncons/json_options.hpp>
-
-// For convenience
-using jsoncons::ojson;
-using jsoncons::json_options;
-using jsoncons::line_split_kind;
-
-namespace waf_logging {
-
-    struct detail
-    {
-        std::string message;
-        std::string data;
-        std::string file;
-        std::string line;
-    };
-
-    struct property
-    {
-        std::string instanceId;
-        std::string clientIp;
-        std::string clientPort;
-        std::string requestUri;
-        std::string ruleSetType;
-        std::string ruleSetVersion;
-        std::string ruleId;
-        std::string message;
-        std::string action;
-        std::string site;
-        detail details;
-        std::string hostname;
-        std::string transactionId;
-    };
-
-    struct waf_log
-    {
-        std::string resourceId;
-        std::string operationName;
-        std::string category;
-        property properties;
-    };
-}
-
-JSONCONS_TYPE_TRAITS_DECL(waf_logging::detail, message, data, file, line);
-JSONCONS_TYPE_TRAITS_DECL(waf_logging::property, instanceId, clientIp, clientPort, requestUri, ruleSetType, ruleSetVersion, ruleId, message, action, site, details, hostname, transactionId);
-JSONCONS_TYPE_TRAITS_DECL(waf_logging::waf_log, resourceId, operationName, category, properties);
-
-std::string to_json_string(const waf_logging::waf_log& log) {
-    json_options options;
-    std::string json_output;
-    encode_json(ojson{}, log, json_output, options, jsoncons::indenting::indent);
-    return json_output;
-};
-
-#endif 
diff --git a/nginx/modsecurity/ngx_http_modsecurity.c b/nginx/modsecurity/ngx_http_modsecurity.c
index 5244160221..d10c10f882 100644
--- a/nginx/modsecurity/ngx_http_modsecurity.c
+++ b/nginx/modsecurity/ngx_http_modsecurity.c
@@ -24,7 +24,7 @@
 
 #include "api.h"
 #ifdef WAF_JSON_LOGGING_ENABLE
-#include <waf_log_util_external.h>
+#include <waf_log_util.h>
 #endif
 
 #define NOTE_NGINX_REQUEST_CTX "nginx-ctx"

From 06df0a17e70bdef8090153384f52f56b3d2d46df Mon Sep 17 00:00:00 2001
From: Vladimir Krivopalov <vlkrivop@microsoft.com>
Date: Fri, 14 Jun 2019 11:59:30 -0700
Subject: [PATCH 49/58] WAF logging code refactoring.

The change brings in several improvements:
 - Use a sorted vector of ints instead of a hash map.
   It reduces memory footprint and makes for more cache-friendly
   data locality.
 - Use jsoncons::string_view non-owning string references.
   This avoids unnecessary memory allocations when filling WAF JSON
   structures and lets us operate safely on input C-style strings
   without having to enforce null-termination on them.
 - Fixed potential memory corruption when setting trailing zero byte
   to details_data that can be potentially an empty string.
 - Declared most input parameters and local variables const.
 - Adjusted generate_json() to return the resulting string as a result
   and not through an in-out parameter.
 - Use standard library algorithms instead of manual loops for copying
   sequences of data.

Signed-off-by: Vladimir Krivopalov <vlkrivop@microsoft.com>
---
 apache2/apache2_util.c              |   8 +-
 apache2/waf_logging/waf_log_util.cc | 284 ++++++++++++++--------------
 apache2/waf_logging/waf_log_util.h  |   2 +-
 3 files changed, 146 insertions(+), 148 deletions(-)

diff --git a/apache2/apache2_util.c b/apache2/apache2_util.c
index 85e0c978c2..5c9643b347 100755
--- a/apache2/apache2_util.c
+++ b/apache2/apache2_util.c
@@ -319,8 +319,6 @@ static int write_file_with_lock(struct waf_lock* lock, apr_file_t* fd, char* str
  * send all waf fields in json format to a file.
  */
 static void send_waf_log(struct waf_lock* lock, apr_file_t* fd, const char* str1, const char* ip_port, const char* uri, int mode, const char* hostname, char* unique_id, request_rec *r) {
-    int rc = 0;
-    char* json_str;
     char waf_filename[1024] = "";
     char waf_line[1024] = "";
     char waf_id[1024] = "";
@@ -346,8 +344,8 @@ static void send_waf_log(struct waf_lock* lock, apr_file_t* fd, const char* str1
     get_short_filename(waf_filename);
     get_ruleset_type_version(waf_ruleset_info, waf_ruleset_type, waf_ruleset_version); 
 
-    rc = generate_json(&json_str, msc_waf_resourceId, WAF_LOG_UTIL_OPERATION_NAME, WAF_LOG_UTIL_CATEGORY, msc_waf_instanceId, waf_ip, waf_port, uri, waf_ruleset_type, waf_ruleset_version, waf_id, waf_message, mode, 0, waf_detail_message, waf_data, waf_filename, waf_line, hostname, waf_unique_id);
-    if (rc == WAF_LOG_UTIL_FAILED) {
+    char* json_str = generate_json(msc_waf_resourceId, WAF_LOG_UTIL_OPERATION_NAME, WAF_LOG_UTIL_CATEGORY, msc_waf_instanceId, waf_ip, waf_port, uri, waf_ruleset_type, waf_ruleset_version, waf_id, waf_message, mode, 0, waf_detail_message, waf_data, waf_filename, waf_line, hostname, waf_unique_id);
+    if (!json_str) {
 #if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER > 2
        ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r,
             "ModSecurity: can't print json log");
@@ -358,7 +356,7 @@ static void send_waf_log(struct waf_lock* lock, apr_file_t* fd, const char* str1
         return;
     }
 
-    rc = write_file_with_lock(lock, fd, json_str);
+    int rc = write_file_with_lock(lock, fd, json_str);
     if (rc == WAF_LOG_UTIL_FAILED) {
 #if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER > 2
        ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r,
diff --git a/apache2/waf_logging/waf_log_util.cc b/apache2/waf_logging/waf_log_util.cc
index 3b7d2dbb7f..b5cb068aa9 100755
--- a/apache2/waf_logging/waf_log_util.cc
+++ b/apache2/waf_logging/waf_log_util.cc
@@ -1,178 +1,178 @@
 #include "waf_log_util.h"
 
+#include <cstdlib>
 #include <fstream>
-#include <unordered_map>
+#include <vector>
 #include <jsoncons/json.hpp>
 #include <jsoncons/json_options.hpp>
 
-// For convenience
-using jsoncons::ojson;
-using jsoncons::json_options;
-using jsoncons::line_split_kind;
-
 namespace waf_logging {
 
-    struct detail
-    {
-        std::string message;
-        std::string data;
-        std::string file;
-        std::string line;
-    };
+struct detail
+{
+    jsoncons::string_view message;
+    jsoncons::string_view data;
+    jsoncons::string_view file;
+    jsoncons::string_view line;
+};
 
-    struct property
-    {
-        std::string instanceId;
-        std::string clientIp;
-        std::string clientPort;
-        std::string requestUri;
-        std::string ruleSetType;
-        std::string ruleSetVersion;
-        std::string ruleId;
-        std::string message;
-        std::string action;
-        std::string site;
-        detail details;
-        std::string hostname;
-        std::string transactionId;
-    };
+struct property
+{
+    jsoncons::string_view instanceId;
+    jsoncons::string_view clientIp;
+    jsoncons::string_view clientPort;
+    jsoncons::string_view requestUri;
+    jsoncons::string_view ruleSetType;
+    jsoncons::string_view ruleSetVersion;
+    jsoncons::string_view ruleId;
+    jsoncons::string_view message;
+    jsoncons::string_view action;
+    jsoncons::string_view site;
+    detail details;
+    jsoncons::string_view hostname;
+    jsoncons::string_view transactionId;
+};
 
-    struct waf_log
-    {
-        std::string resourceId;
-        std::string operationName;
-        std::string category;
-        property properties;
-    };
-}
+struct waf_log
+{
+    jsoncons::string_view resourceId;
+    jsoncons::string_view operationName;
+    jsoncons::string_view category;
+    property properties;
+};
+
+}   // namespace waf_logging
 
 JSONCONS_TYPE_TRAITS_DECL(waf_logging::detail, message, data, file, line);
 JSONCONS_TYPE_TRAITS_DECL(waf_logging::property, instanceId, clientIp, clientPort, requestUri, ruleSetType, ruleSetVersion, ruleId, message, action, site, details, hostname, transactionId);
 JSONCONS_TYPE_TRAITS_DECL(waf_logging::waf_log, resourceId, operationName, category, properties);
 
-std::string to_json_string(const waf_logging::waf_log& log) {
-    json_options options;
+static std::string to_json_string(const waf_logging::waf_log& log) {
+    jsoncons::json_options options;
     std::string json_output;
-    encode_json(ojson{}, log, json_output, options, jsoncons::indenting::indent);
+    jsoncons::encode_json(jsoncons::ojson{}, log, json_output, options, jsoncons::indenting::indent);
     return json_output;
 };
 
-using namespace std;
-unordered_map<int, bool> appgw_ruleid_hash;
-
-// This function fills in a waf format message based on modsec input.
-string get_json_log_message(char* resourceId, char* operationName, char* category, char* instanceId, char* clientIP, char* clientPort, const char* requestUri, char* ruleSetType, char* ruleSetVersion, char* ruleId, char* messages, int action, int site, char* details_messages, char* details_data, char* details_file, char* details_line, const char* hostname, char* waf_unique_id) {
-    string action_str;
-    string message_str;
-    string site_str;
-
-    if (ruleId != NULL) {
-		ruleId[strlen(ruleId) - 1] = '\0';
-    }
-    
-	bool is_mandatory = false;
-    try {
-		int tmpid = atoi(ruleId+1);
-		is_mandatory = rule_is_mandatory(tmpid);
-
-		if (ruleSetVersion[0] != '2' && !is_mandatory)
-			action_str = WAF_ACTION_MATCHED;
-		else {
-			switch (action) {
-			case MODSEC_MODE_DETECT:
-				action_str = WAF_ACTION_DETECTED;
-				break;
-			case MODSEC_MODE_PREVENT:
-				action_str = WAF_ACTION_BLOCKED;
-				break;
-			default:
-				break;
-			}
-		}
-	}
-    catch (...) {
-		action_str = "";
-	}
-    
-	if (messages != NULL) {
+static std::vector<int> default_disableable_rule_ids;
+
+static const std::string WAF_ACTION_BLOCKED {"Blocked"};
+static const std::string WAF_ACTION_DETECTED {"Detected"};
+static const std::string WAF_ACTION_MATCHED {"Matched"};
+
+static std::string get_json_log_message(const char* resource_id, const char* operation_name, const char* category,
+        const char* instance_id, const char* client_ip, const char* client_port, const char* request_uri,
+        const char* rule_set_type, const char* rule_set_version, const char* rule_id, const char* messages,
+        const int action, const int site, const char* details_messages, const char* details_data,
+        const char* details_file, const char* details_line, const char* hostname, const char* waf_unique_id) {
+
+    using str_view = jsoncons::string_view;
+    const auto make_string_view_strip_quotes = [] (const char* str) -> str_view {
+        if (!str) {
+            return {};
+        }
+        auto length = strlen(str);
+        if (length < 2) {
+            return {};
+        }
+
+        return {str + 1, length - 2};
+    };
+    const str_view rule_id_str = make_string_view_strip_quotes(rule_id);
+    const int current_id = std::stoi(static_cast<std::string>(rule_id_str));
+    std::cout << "Current id" << current_id << std::endl;
+    const bool is_mandatory = !std::binary_search(default_disableable_rule_ids.begin(), default_disableable_rule_ids.end(),
+            current_id);
+    const str_view action_str =
+        (rule_set_version[0] != '2' && !is_mandatory) ? WAF_ACTION_MATCHED :
+        action == MODSEC_MODE_DETECT                ? WAF_ACTION_DETECTED :
+        action == MODSEC_MODE_PREVENT               ? WAF_ACTION_BLOCKED :
+        str_view{};
+
+    #define MANDATORY_RULE_MESSAGE ("Mandatory rule. Cannot be disabled. ")
+    #define MANDATORY_RULE_MESSAGE_LENGTH (sizeof(MANDATORY_RULE_MESSAGE) - 1)
+    std::array<char, 1024> mandatory_message {MANDATORY_RULE_MESSAGE};
+    str_view message_str;
+	if (messages) {
 		if (is_mandatory) {
-			char mandatory_message[1024] = "Mandatory rule. Cannot be disabled. ";
-			int ind = strlen(mandatory_message) - 1;
-			int i;
-			for (i = 1; i < strlen(messages) - 1; i++) {
-				if (i + ind < 1023) {
-					mandatory_message[ind + i] = messages[i];
-				}
-				else {
-					break;
-				}
-			}
-			mandatory_message[ind + i] = '\0';
-			message_str = mandatory_message;
+            size_t truncated_length = std::min(strlen(messages) - 1, mandatory_message.size() - MANDATORY_RULE_MESSAGE_LENGTH);
+            if (truncated_length > 1) {
+                const str_view messages_view {messages + 1, truncated_length - 1};
+                std::copy(messages_view.cbegin(), messages_view.cend(), mandatory_message.begin() + MANDATORY_RULE_MESSAGE_LENGTH);
+            }
+            message_str = {&mandatory_message.front(), MANDATORY_RULE_MESSAGE_LENGTH + truncated_length - 1};
 		}
 		else {
-			messages[strlen(messages) - 1] = '\0';
-			message_str = messages+1;
+            message_str = make_string_view_strip_quotes(messages);
 		}		
 	}
 
-	if (site == 0) {
-        site_str = "Global";
-    }
-
-    if (details_file != NULL) {
-		details_file[strlen(details_file) - 1] = '\0';
-    }
-
-    if (details_data != NULL) {
-		details_data[strlen(details_data) - 1] = '\0';
-    }
-    
-    if (details_line != NULL) {
-		details_line[strlen(details_line) - 1] = '\0';
-    }
-
-	if (waf_unique_id != NULL) {
-		waf_unique_id[strlen(waf_unique_id) - 1] = '\0';
-	}
-
-    return to_json_string({resourceId, operationName, category, waf_logging::property{ instanceId, clientIP, clientPort, requestUri, ruleSetType, ruleSetVersion, ruleId+1, message_str, action_str, site_str, waf_logging::detail{ details_messages, details_data+1, details_file+1, details_line+1 }, hostname, waf_unique_id+1}});
+    const str_view site_str = (site == 0) ? "Global" : str_view{};
+
+    const str_view details_file_str = details_file ? str_view {details_file, strlen(details_file) - 1} : str_view{};
+    const str_view details_data_str = make_string_view_strip_quotes(details_data);
+    const str_view details_line_str = make_string_view_strip_quotes(details_line);
+    const str_view waf_unique_id_str = make_string_view_strip_quotes(waf_unique_id);
+
+    return to_json_string({
+            resource_id,
+            operation_name,
+            category,
+            waf_logging::property {
+                instance_id,
+                client_ip,
+                client_port,
+                request_uri,
+                rule_set_type,
+                rule_set_version,
+                rule_id_str,
+                message_str,
+                action_str,
+                site_str,
+                waf_logging::detail {
+                    details_messages,
+                    details_data_str,
+                    details_file_str,
+                    details_line_str
+                },
+            hostname,
+            waf_unique_id_str
+        }
+    });
 }
 
-// Main function:  get fields from modsec, set the protobuf object and write to file in json.
-int generate_json(char** result_json, char* resourceId, char* operationName, char* category, char* instanceId, char* clientIP, char* clientPort, const char* requestUri, char* ruleSetType, char* ruleSetVersion, char* ruleId, char* messages, int action, int site, char* details_messages, char* details_data, char* details_file, char* details_line, const char* hostname, char* waf_unique_id) {
-    string json_string;
-    char* json_str;
+// Get fields from ModSec and format them to JSON.
+char* generate_json(const char* resource_id, const char* operation_name, const char* category,
+        const char* instance_id, const char* client_ip, const char* client_port, const char* request_uri,
+        const char* rule_set_type, const char* rule_set_version, const char* rule_id, const char* messages,
+        const int action, const int site, const char* details_messages, const char* details_data,
+        const char* details_file, const char* details_line, const char* hostname, const char* waf_unique_id) {
     
     try {
-        // Set Waf format.
-        json_string = get_json_log_message(resourceId, operationName, category, instanceId, clientIP, clientPort, requestUri, ruleSetType, ruleSetVersion, ruleId, messages, action, site, details_messages, details_data, details_file, details_line, hostname, waf_unique_id); 
-    }
-    catch (...) {
-        return WAF_LOG_UTIL_FAILED;
-    }
-
-    *result_json = strdup((json_string + "\n").c_str());
-    return WAF_LOG_UTIL_SUCCESS; 
+        const std::string json_string = get_json_log_message(resource_id, operation_name, category,
+                instance_id, client_ip, client_port, request_uri, rule_set_type, rule_set_version,
+                rule_id, messages, action, site, details_messages, details_data, details_file,
+                details_line, hostname, waf_unique_id);
+        char* result = static_cast<char*>(std::malloc(json_string.length() + 2)); // Two extra bytes for \n and \0
+        std::copy(json_string.begin(), json_string.end(), result);
+        result[json_string.length()] = '\n';
+        result[json_string.length() + 1] = '\0';
+        return result;
+    } catch (...) {}
+
+    return nullptr;
 }
 
 void free_json(char* str) {
-    free(str);
+    std::free(str);
 }
 
 void init_appgw_rules_id_hash() {
-	ifstream infile(RULES_ID_FILE);
-	string line;
-
-	while (getline(infile, line)) {
-		int rule_id = stoi(line);
-		appgw_ruleid_hash[rule_id] = true;
-	}
-	infile.close();
-
-	return;
+    std::ifstream ifs("/etc/nginx/modsec/disableableRules.conf");
+    if(ifs) {
+        std::copy(std::istream_iterator<int>(ifs),
+                std::istream_iterator<int>(),
+                std::back_inserter(default_disableable_rule_ids));
+        std::sort(default_disableable_rule_ids.begin(), default_disableable_rule_ids.end());
+    }
 }
-
-bool rule_is_mandatory(int rule_id) {
-	return (appgw_ruleid_hash.find(rule_id) == appgw_ruleid_hash.end());
-}
\ No newline at end of file
diff --git a/apache2/waf_logging/waf_log_util.h b/apache2/waf_logging/waf_log_util.h
index 1ee1e33577..42afbebaae 100755
--- a/apache2/waf_logging/waf_log_util.h
+++ b/apache2/waf_logging/waf_log_util.h
@@ -17,7 +17,7 @@
 #ifdef __cplusplus
 extern "C" {
 #endif
-int generate_json(char** result, char* resourceId, char* operationName, char* category, char* instanceId, char* clientIP, char* clientPort, const char* requestUri, char* ruleSetType, char* ruleSetVersion, char* ruleId, char* messages, int action, int site, char* details_messages, char* details_data, char* details_file, char* details_line, const char* hostname, char* waf_unique_id);
+char* generate_json(const char* resourceId, const char* operationName, const char* category, const char* instanceId, const char* clientIP, const char* clientPort, const char* requestUri, const char* ruleSetType, const char* ruleSetVersion, const char* ruleId, const char* messages, const int action, const int site, const char* details_messages, const char* details_data, const char* details_file, const char* details_line, const char* hostname, const char* waf_unique_id);
 void free_json(char* str);
 void init_appgw_rules_id_hash();
 #ifdef __cplusplus

From 0495bba9ceda9914e309ac413848af7b049974ea Mon Sep 17 00:00:00 2001
From: Vladimir Krivopalov <vlkrivop@microsoft.com>
Date: Mon, 17 Jun 2019 10:57:51 -0700
Subject: [PATCH 50/58] Bump C++ version from C++11 to C++14.

Signed-off-by: Vladimir Krivopalov <vlkrivop@microsoft.com>
---
 BUILD.md            | 2 +-
 docker-compose.yaml | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/BUILD.md b/BUILD.md
index 14e7420765..edd84cfdd5 100644
--- a/BUILD.md
+++ b/BUILD.md
@@ -93,6 +93,6 @@ The steps below are for Ubuntu 16.04 LTS.
  5.  Configure and build ModSecurity:
 	 ```bash
 	 ./autogen.sh
-	 ./configure LDFLAGS=-g  CXXFLAGS="-std=c++11 " CFLAGS="-fPIC " --enable-standalone-module --disable-mlogc --enable-waf_json_logging
+	 ./configure LDFLAGS=-g  CXXFLAGS="-std=c++14 " CFLAGS="-fPIC " --enable-standalone-module --disable-mlogc --enable-waf_json_logging
 	 make
 	 ```
diff --git a/docker-compose.yaml b/docker-compose.yaml
index 61da8dfe54..a344cd8cd3 100644
--- a/docker-compose.yaml
+++ b/docker-compose.yaml
@@ -21,7 +21,7 @@ services:
     working_dir: /microsoft/modsecurity
     entrypoint: 
       - ./configure
-      - CXXFLAGS=-std=c++11
+      - CXXFLAGS=-std=c++14
       - CFLAGS=-fPIC
       - --enable-standalone-module
       - --disable-mlogc

From 936c2e5601a155bd034f858c0f30e4403d357140 Mon Sep 17 00:00:00 2001
From: Vladimir Krivopalov <vlkrivop@microsoft.com>
Date: Fri, 14 Jun 2019 15:50:23 -0700
Subject: [PATCH 51/58] Support separate per-type/version files with
 disableable rule IDs.

This is a pre-requisite for supporting multiple different WAF
configurations that may use different rule sets.

Signed-off-by: Vladimir Krivopalov <vlkrivop@microsoft.com>
---
 apache2/waf_logging/waf_log_util.cc      | 127 +++++++++++++++++++----
 apache2/waf_logging/waf_log_util.h       |   3 +-
 nginx/modsecurity/ngx_http_modsecurity.c |   5 +-
 3 files changed, 115 insertions(+), 20 deletions(-)

diff --git a/apache2/waf_logging/waf_log_util.cc b/apache2/waf_logging/waf_log_util.cc
index b5cb068aa9..0b6a50bccb 100755
--- a/apache2/waf_logging/waf_log_util.cc
+++ b/apache2/waf_logging/waf_log_util.cc
@@ -3,6 +3,8 @@
 #include <cstdlib>
 #include <fstream>
 #include <vector>
+#include <unordered_map>
+#include <experimental/optional>
 #include <jsoncons/json.hpp>
 #include <jsoncons/json_options.hpp>
 
@@ -54,12 +56,71 @@ static std::string to_json_string(const waf_logging::waf_log& log) {
     return json_output;
 };
 
-static std::vector<int> default_disableable_rule_ids;
+enum class rule_set_types {
+    TYPE_UNKNOWN,
+    OWASP_CRS,
+};
+
+// Employing X-Macro trick (https://en.wikipedia.org/wiki/X_Macro) to keep the list of versions
+// automatically synced up with the map of file paths
+// If you need to add new OWASP version, just add it here and it will sync up in all the places
+#define LIST_OF_VARIABLES \
+    X(2_2_9) \
+    X(3_0) \
+    X(3_1)
+
+enum class rule_set_versions {
+    VERSION_UNKNOWN,
+    #define X(name) VERSION_##name,
+    LIST_OF_VARIABLES
+    #undef X
+};
+
+using rule_set_info = std::pair<rule_set_types, rule_set_versions>;
+#define X(name) static const rule_set_info OWASP_##name {std::make_pair(rule_set_types::OWASP_CRS, rule_set_versions::VERSION_##name)};
+    LIST_OF_VARIABLES
+#undef X
+
+static rule_set_types parse_rule_set_type(const char* type) {
+    if (!type) {
+        return rule_set_types::TYPE_UNKNOWN;
+    }
+
+    return (std::strcmp(type, "OWASP_CRS") == 0) ? rule_set_types::OWASP_CRS : rule_set_types::TYPE_UNKNOWN;
+}
+
+static rule_set_versions parse_rule_set_version(const char* version) {
+    if (!version) {
+        return rule_set_versions::VERSION_UNKNOWN;
+    }
+
+    return (std::strcmp(version, "2.2.9") == 0) ? rule_set_versions::VERSION_2_2_9 :
+        (std::strcmp(version, "3.0.0") == 0) ? rule_set_versions::VERSION_3_0 :
+        (std::strcmp(version, "3.1.0") == 0) ? rule_set_versions::VERSION_3_1 :
+        rule_set_versions::VERSION_UNKNOWN;
+}
+
+using rule_ids_vector = std::vector<int>;
+
+static rule_ids_vector current_rule_ids;
+static std::map<rule_set_info, rule_ids_vector> disableable_rule_ids_map;
 
 static const std::string WAF_ACTION_BLOCKED {"Blocked"};
 static const std::string WAF_ACTION_DETECTED {"Detected"};
 static const std::string WAF_ACTION_MATCHED {"Matched"};
 
+static bool is_mandatory_rule(const rule_set_types type, const rule_set_versions version, const int current_id) {
+    const auto contains_current_id = [current_id] (const rule_ids_vector& rule_ids) {
+        return !std::binary_search(std::begin(rule_ids), std::end(rule_ids), current_id);
+    };
+    const auto rules_id_iter = disableable_rule_ids_map.find(std::make_pair(type, version));
+    if (rules_id_iter != std::end(disableable_rule_ids_map)) {
+        return contains_current_id(rules_id_iter->second);
+    }
+
+    return contains_current_id(current_rule_ids);
+}
+
 static std::string get_json_log_message(const char* resource_id, const char* operation_name, const char* category,
         const char* instance_id, const char* client_ip, const char* client_port, const char* request_uri,
         const char* rule_set_type, const char* rule_set_version, const char* rule_id, const char* messages,
@@ -79,33 +140,34 @@ static std::string get_json_log_message(const char* resource_id, const char* ope
         return {str + 1, length - 2};
     };
     const str_view rule_id_str = make_string_view_strip_quotes(rule_id);
+    const rule_set_types type = parse_rule_set_type(rule_set_type);
+    const rule_set_versions version = parse_rule_set_version(rule_set_version);
     const int current_id = std::stoi(static_cast<std::string>(rule_id_str));
-    std::cout << "Current id" << current_id << std::endl;
-    const bool is_mandatory = !std::binary_search(default_disableable_rule_ids.begin(), default_disableable_rule_ids.end(),
-            current_id);
+    const bool is_mandatory = is_mandatory_rule(type, version, current_id);
+
     const str_view action_str =
-        (rule_set_version[0] != '2' && !is_mandatory) ? WAF_ACTION_MATCHED :
-        action == MODSEC_MODE_DETECT                ? WAF_ACTION_DETECTED :
-        action == MODSEC_MODE_PREVENT               ? WAF_ACTION_BLOCKED :
+        (version != rule_set_versions::VERSION_2_2_9 && !is_mandatory)  ? WAF_ACTION_MATCHED :
+        action == MODSEC_MODE_DETECT                                    ? WAF_ACTION_DETECTED :
+        action == MODSEC_MODE_PREVENT                                   ? WAF_ACTION_BLOCKED :
         str_view{};
 
     #define MANDATORY_RULE_MESSAGE ("Mandatory rule. Cannot be disabled. ")
     #define MANDATORY_RULE_MESSAGE_LENGTH (sizeof(MANDATORY_RULE_MESSAGE) - 1)
     std::array<char, 1024> mandatory_message {MANDATORY_RULE_MESSAGE};
     str_view message_str;
-	if (messages) {
-		if (is_mandatory) {
+    if (messages) {
+        if (is_mandatory) {
             size_t truncated_length = std::min(strlen(messages) - 1, mandatory_message.size() - MANDATORY_RULE_MESSAGE_LENGTH);
             if (truncated_length > 1) {
                 const str_view messages_view {messages + 1, truncated_length - 1};
                 std::copy(messages_view.cbegin(), messages_view.cend(), mandatory_message.begin() + MANDATORY_RULE_MESSAGE_LENGTH);
             }
             message_str = {&mandatory_message.front(), MANDATORY_RULE_MESSAGE_LENGTH + truncated_length - 1};
-		}
-		else {
+        }
+        else {
             message_str = make_string_view_strip_quotes(messages);
-		}		
-	}
+        }
+    }
 
     const str_view site_str = (site == 0) ? "Global" : str_view{};
 
@@ -167,12 +229,41 @@ void free_json(char* str) {
     std::free(str);
 }
 
-void init_appgw_rules_id_hash() {
-    std::ifstream ifs("/etc/nginx/modsec/disableableRules.conf");
-    if(ifs) {
+namespace stdx = std::experimental;
+static stdx::optional<rule_ids_vector> read_disableable_rule_ids(const std::string& filename) {
+    std::ifstream ifs(filename);
+    if (ifs) {
+        rule_ids_vector rule_ids;
         std::copy(std::istream_iterator<int>(ifs),
                 std::istream_iterator<int>(),
-                std::back_inserter(default_disableable_rule_ids));
-        std::sort(default_disableable_rule_ids.begin(), default_disableable_rule_ids.end());
+                std::back_inserter(rule_ids));
+        std::sort(std::begin(rule_ids), std::end(rule_ids));
+        return rule_ids;
+    }
+
+    return {};
+}
+
+int init_appgw_rules_id_hash() {
+    const std::map<rule_set_info, std::string> disableableRulesPathsMap {
+        #define X(name) {OWASP_##name, "/etc/nginx/modsec/OWASP/" #name "/disableableRules.conf"},
+        LIST_OF_VARIABLES
+        #undef X
+    };
+    for (const auto& item : disableableRulesPathsMap) {
+        const auto vec = read_disableable_rule_ids(item.second);
+        if (vec) {
+            disableable_rule_ids_map[item.first] = *vec;
+        }
+    }
+    if (disableable_rule_ids_map.empty()) {
+        // If we haven't found type/version-specific files, we need to read the default (deprecated one)
+        const auto vec = read_disableable_rule_ids("/etc/nginx/modsec/disableableRules.conf");
+        if (!vec) {
+            return -1;
+        }
+
+        current_rule_ids = *vec;
     }
+    return 0;
 }
diff --git a/apache2/waf_logging/waf_log_util.h b/apache2/waf_logging/waf_log_util.h
index 42afbebaae..9b137c4940 100755
--- a/apache2/waf_logging/waf_log_util.h
+++ b/apache2/waf_logging/waf_log_util.h
@@ -19,7 +19,8 @@ extern "C" {
 #endif
 char* generate_json(const char* resourceId, const char* operationName, const char* category, const char* instanceId, const char* clientIP, const char* clientPort, const char* requestUri, const char* ruleSetType, const char* ruleSetVersion, const char* ruleId, const char* messages, const int action, const int site, const char* details_messages, const char* details_data, const char* details_file, const char* details_line, const char* hostname, const char* waf_unique_id);
 void free_json(char* str);
-void init_appgw_rules_id_hash();
+// Returns 0 if succeeded, non-zero code otherwise
+int init_appgw_rules_id_hash();
 #ifdef __cplusplus
 }
 #endif
diff --git a/nginx/modsecurity/ngx_http_modsecurity.c b/nginx/modsecurity/ngx_http_modsecurity.c
index d10c10f882..33d11335d3 100644
--- a/nginx/modsecurity/ngx_http_modsecurity.c
+++ b/nginx/modsecurity/ngx_http_modsecurity.c
@@ -598,7 +598,10 @@ ngx_http_modsecurity_init(ngx_conf_t *cf)
     pthread_mutex_init(&msc_pregcomp_ex_mtx, NULL);
 
 #ifdef WAF_JSON_LOGGING_ENABLE
-    init_appgw_rules_id_hash();
+    int result = init_appgw_rules_id_hash();
+    if (result) {
+        ngx_log_error(NGX_LOG_INFO, cf->log, 0, "ModSecurity: could not load application gateway rules IDs.");
+    }
 #endif    
 
     return NGX_OK;

From c055b9dd5890512d9359f499fa1368249193e727 Mon Sep 17 00:00:00 2001
From: Vladimir Krivopalov <vlkrivop@microsoft.com>
Date: Mon, 1 Jul 2019 17:28:06 -0700
Subject: [PATCH 52/58] Revert fix for non-blocking detection mode in IIS
 ModSecurity.

The fix appears to not behave well under heavy load when IIS runs many
threads (up to 200). Further investigation and improvements are due.

Signed-off-by: Vladimir Krivopalov <vlkrivop@microsoft.com>
---
 iis/Makefile.win |  3 +-
 iis/mymodule.cpp | 75 +++++-------------------------------------------
 iis/mymodule.h   |  4 ---
 3 files changed, 8 insertions(+), 74 deletions(-)

diff --git a/iis/Makefile.win b/iis/Makefile.win
index 740021d3e3..1e198f65c3 100644
--- a/iis/Makefile.win
+++ b/iis/Makefile.win
@@ -37,8 +37,7 @@ INCLUDES = -I. -I.. \
            -I..\apache2 \
            -I..\standalone \
            -I..\apache2\ag_mdb \
-           -I..\apache2\waf_lock \
-           -Iasio\asio\include
+           -I..\apache2\waf_lock
 
 # Enables support for SecRemoteRules and external resources.
 DEFS=$(DEFS) -DWITH_CURL -DWITH_REMOTE_RULES
diff --git a/iis/mymodule.cpp b/iis/mymodule.cpp
index dfd97b7dc8..dde8695a7b 100644
--- a/iis/mymodule.cpp
+++ b/iis/mymodule.cpp
@@ -35,8 +35,6 @@
 
 #include "winsock2.h"
 
-#include "asio/post.hpp"
-
 // These helpers make sure that the underlying structures
 // are correctly released on any exit path due to RAII.
 using ConnRecPtr = std::unique_ptr<conn_rec, decltype(modsecFinishConnection)*>;
@@ -673,75 +671,16 @@ CMyHttpModule::OnBeginRequest(IHttpContext* httpContext, IHttpEventProvider* pro
         }
     }
 
-    if (config->config->is_enabled == MODSEC_DETECTION_ONLY)
-    {
-        // This could have been a simple lambda with generalized capture but C++11 doesn't support it yet.
-        // Can be replaced/simplified in C++14.
-        class BackgroundRequestProcessingTask
-        {
-        private:
-            AprRequestContext ctx;
-        public:
-            explicit BackgroundRequestProcessingTask(AprRequestContext&& ctx)
-                : ctx(std::move(ctx))
-            {}
-
-            BackgroundRequestProcessingTask(const BackgroundRequestProcessingTask&) = delete;
-            BackgroundRequestProcessingTask& operator=(const BackgroundRequestProcessingTask&) = delete;
-
-            BackgroundRequestProcessingTask(BackgroundRequestProcessingTask&& rhs)
-                : ctx(std::move(rhs.ctx))
-            {
-            }
-
-            BackgroundRequestProcessingTask& operator=(BackgroundRequestProcessingTask&& rhs)
-            {
-                ctx = std::move(rhs.ctx);
-                return *this;
-            }
-
-            int operator()() const {
-                // We put the entire thread into background mode for the time of processing.
-                // According to https://docs.microsoft.com/en-us/windows/desktop/api/processthreadsapi/nf-processthreadsapi-setthreadpriority :
-                //
-                // The THREAD_PRIORITY_* values affect the CPU scheduling priority of the thread.
-                // For threads that perform background work such as file I/O, network I/O, or data processing,
-                // it is not sufficient to adjust the CPU scheduling priority; even an idle CPU priority thread
-                // can easily interfere with system responsiveness when it uses the disk and memory.
-                // Threads that perform background work should use the THREAD_MODE_BACKGROUND_BEGIN
-                // and THREAD_MODE_BACKGROUND_END values to adjust their resource scheduling priorities;
-                // threads that interact with the user should not use THREAD_MODE_BACKGROUND_BEGIN.
-                struct BackgroundThreadMode
-                {
-                    BackgroundThreadMode() {
-                        SetThreadPriority(GetCurrentThread(), THREAD_MODE_BACKGROUND_BEGIN);
-                    }
-                    ~BackgroundThreadMode() {
-                        SetThreadPriority(GetCurrentThread(), THREAD_MODE_BACKGROUND_END);
-                    }
-                };
-
-                BackgroundThreadMode backgroundMode;
-                return modsecProcessRequest(ctx.GetRequest());
-            }
-        };
+    lock.unlock();
+    int status = modsecProcessRequest(r);
+    lock.lock();
 
-        // We post the processing task to the thread pool to happen in the background.
-        asio::post(threadPool, BackgroundRequestProcessingTask{ std::move(aprContext) });
-    }
-    else
+    if (status != DECLINED)
     {
-        lock.unlock();
-        int status = modsecProcessRequest(r);
-        lock.lock();
-
-        if (status != DECLINED)
-        {
-            httpContext->GetResponse()->SetStatus(status, "ModSecurity Action");
-            httpContext->SetRequestHandled();
+        httpContext->GetResponse()->SetStatus(status, "ModSecurity Action");
+        httpContext->SetRequestHandled();
 
-            return RQ_NOTIFICATION_FINISH_REQUEST;
-        }
+        return RQ_NOTIFICATION_FINISH_REQUEST;
     }
 
     return RQ_NOTIFICATION_CONTINUE;
diff --git a/iis/mymodule.h b/iis/mymodule.h
index 5b81c976f1..8b339b3796 100644
--- a/iis/mymodule.h
+++ b/iis/mymodule.h
@@ -14,9 +14,6 @@
 
 #pragma once
 
-#define ASIO_STANDALONE
-#include "asio/thread_pool.hpp"
-
 #include "critical_section.h"
 #include "event_logger.h"
 
@@ -40,7 +37,6 @@ class CMyHttpModule
 private:
     CriticalSection cs;
     EventLogger logger;
-    asio::thread_pool threadPool{12};
     DWORD pageSize = 0;
     bool statusCallAlreadySent = false;
 };

From b7be88a3e9db2ce9c3cd462064bf6804d5df76b7 Mon Sep 17 00:00:00 2001
From: Yanshu <yanshu.zhao7@gmail.com>
Date: Tue, 23 Jul 2019 20:18:43 -0700
Subject: [PATCH 53/58] reopen flag set to 1 for the nginx worker crash case
 (#123)

---
 apache2/mod_security2.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/apache2/mod_security2.c b/apache2/mod_security2.c
index 272f4fd35d..70121e7517 100755
--- a/apache2/mod_security2.c
+++ b/apache2/mod_security2.c
@@ -95,7 +95,7 @@ TreeRoot DSOLOCAL *conn_write_state_suspicious_list = 0;
 #ifdef WAF_JSON_LOGGING_ENABLE
 char DSOLOCAL *msc_waf_resourceId = NULL;
 char DSOLOCAL *msc_waf_instanceId = NULL;
-sig_atomic_t DSOLOCAL msc_waf_log_reopened = 0;
+sig_atomic_t DSOLOCAL msc_waf_log_reopened = 1;
 apr_file_t DSOLOCAL *msc_waf_log_fd = NULL;
 char DSOLOCAL msc_waf_log_path[WAF_LOG_PATH_LENGTH] = ""; 
 cmd_parms DSOLOCAL *msc_waf_log_cmd = NULL;

From 886e633ef44ca15646772b906c347eabc99278b5 Mon Sep 17 00:00:00 2001
From: Vladimir Krivopalov <vlkrivop@microsoft.com>
Date: Tue, 6 Aug 2019 17:28:28 -0700
Subject: [PATCH 54/58] Revert all the recent changes for ModSecurity IIS.

We are reverting all IIS changes down to the last known stable version.
---
 .gitmodules                              |    4 -
 apache2/apache2_config.c                 |    2 +-
 apache2/apache2_util.c                   |   18 +-
 apache2/libinjection/libinjection_sqli.c |    8 +-
 apache2/mod_security2.c                  |    2 +-
 apache2/modsecurity.h                    |   28 +-
 apache2/modsecurity_config.h             |    2 +-
 apache2/msc_json.h                       |    2 +-
 apache2/msc_logging.c                    |   22 +-
 apache2/msc_release.h                    |    6 +-
 apache2/msc_util.c                       |   32 +-
 apache2/persist_dbm.c                    |   34 +-
 apache2/re.c                             |    2 +-
 apache2/re_actions.c                     |   12 +-
 appveyor.yml                             |    1 -
 iis/ModSecurityIIS.vcxproj               |    8 +-
 iis/ModSecurityIIS.vcxproj.filters       |    2 -
 iis/asio                                 |    1 -
 iis/critical_section.h                   |   57 -
 iis/event_logger.h                       |   66 -
 iis/main.cpp                             |   82 +-
 iis/moduleconfig.cpp                     |   14 +-
 iis/moduleconfig.h                       |    8 +-
 iis/mymodule.cpp                         | 1416 ++++++++++++++++------
 iis/mymodule.def                         |    2 +-
 iis/mymodule.h                           |   45 +-
 iis/mymodulefactory.h                    |   80 +-
 mlogc/mlogc.c                            |   54 +-
 standalone/api.c                         |   54 +-
 standalone/api.h                         |    2 +-
 standalone/buckets.c                     |    2 +-
 standalone/config.c                      |  298 ++---
 standalone/filters.c                     |   68 +-
 standalone/hooks.c                       |    4 +-
 standalone/server.c                      |   66 +-
 35 files changed, 1538 insertions(+), 966 deletions(-)
 delete mode 100644 .gitmodules
 delete mode 160000 iis/asio
 delete mode 100644 iis/critical_section.h
 delete mode 100644 iis/event_logger.h

diff --git a/.gitmodules b/.gitmodules
deleted file mode 100644
index accdd7caaf..0000000000
--- a/.gitmodules
+++ /dev/null
@@ -1,4 +0,0 @@
-[submodule "iis/asio"]
-	path = iis/asio
-	url = https://github.com/chriskohlhoff/asio.git
-	branch = tags/asio-1-13-0
diff --git a/apache2/apache2_config.c b/apache2/apache2_config.c
index 8077b8813a..a105b1cef6 100755
--- a/apache2/apache2_config.c
+++ b/apache2/apache2_config.c
@@ -820,7 +820,7 @@ static const char *add_rule(cmd_parms *cmd, directory_config *dcfg, int type,
     }
 
 #ifndef ALLOW_ID_NOT_UNIQUE
-    /* Rules must have uniq ID */
+	/* Rules must have uniq ID */
     type_rule = (dcfg->tmp_chain_starter == NULL);
 #if defined(WITH_LUA)
             type_rule = (type != RULE_TYPE_LUA && type_rule);
diff --git a/apache2/apache2_util.c b/apache2/apache2_util.c
index 5c9643b347..cabc64b3ea 100755
--- a/apache2/apache2_util.c
+++ b/apache2/apache2_util.c
@@ -200,7 +200,7 @@ char *get_env_var(request_rec *r, char *name) {
 static void get_field_value(const char* from, const char* to, const char* text, char* output) {
     char* first = strstr(text, from);
     int first_index = first - text;
-    char backslash[] = "\\";
+	char backslash[] = "\\";
 
     if (first != NULL ) {
         if ((first_index > 0 && strncmp((first-1), backslash, 2) != 0) || (first_index == 0)) {
@@ -330,16 +330,16 @@ static void send_waf_log(struct waf_lock* lock, apr_file_t* fd, const char* str1
     char waf_ruleset_type[50] = "";
     char waf_ruleset_version[50] = "";
     char waf_detail_message[1024] = "";
-    char waf_unique_id[100] = "";
+	char waf_unique_id[100] = "";
 
     get_field_value("[file ", "]", str1, waf_filename);
     get_field_value("[id ", "]", str1, waf_id);
     get_field_value("[line ", "]", str1, waf_line);
     get_field_value("[msg ", "]", str1, waf_message);
     get_field_value("[data ", "]", str1, waf_data);
-    get_field_value("[ver ", "]", str1, waf_ruleset_info);
-    get_field_value("[unique_id ", "]", unique_id, waf_unique_id);
-    get_ip_port(ip_port, waf_ip, waf_port);
+	get_field_value("[ver ", "]", str1, waf_ruleset_info);
+	get_field_value("[unique_id ", "]", unique_id, waf_unique_id);
+	get_ip_port(ip_port, waf_ip, waf_port);
     get_detail_message(str1, waf_detail_message); 
     get_short_filename(waf_filename);
     get_ruleset_type_version(waf_ruleset_info, waf_ruleset_type, waf_ruleset_version); 
@@ -436,8 +436,8 @@ static void internal_log_ex(request_rec *r, directory_config *dcfg, modsec_rec *
 
     /* Send message levels 1-3 to the Apache error log and 
      * add it to the message list in the audit log. */
-    char *unique_id = (char *)get_env_var(r, "UNIQUE_ID");
-    if (level <= 3) {
+	char *unique_id = (char *)get_env_var(r, "UNIQUE_ID");
+	if (level <= 3) {
         char *hostname = (char *)msr->hostname;
         char *requestheaderhostname = (char *)r->hostname;
 
@@ -467,7 +467,7 @@ static void internal_log_ex(request_rec *r, directory_config *dcfg, modsec_rec *
 
             if (rc != APR_SUCCESS) {
                 #if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER > 2
-                    ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r,
+                	ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r,
                             "ModSecurity not able to reopen %s file", WAF_LOG_UTIL_FILE);
                 #else
                         ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r->server,
@@ -482,7 +482,7 @@ static void internal_log_ex(request_rec *r, directory_config *dcfg, modsec_rec *
 #endif
 
 #if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER > 2
-    ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r,
+	ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r,
             "[client %s] ModSecurity: %s%s [uri \"%s\"]%s%s", r->useragent_ip ? r->useragent_ip : r->connection->client_ip, str1,
             hostname, log_escape(msr->mp, r->uri), unique_id, requestheaderhostname);
 #else
diff --git a/apache2/libinjection/libinjection_sqli.c b/apache2/libinjection/libinjection_sqli.c
index d2048ec010..cecbbea3fb 100644
--- a/apache2/libinjection/libinjection_sqli.c
+++ b/apache2/libinjection/libinjection_sqli.c
@@ -1444,7 +1444,7 @@ int libinjection_sqli_fold(struct libinjection_sqli_state * sf)
                 )
             {
                 if (pos > LIBINJECTION_SQLI_MAX_TOKENS) {
-            st_copy(&(sf->tokenvec[1]), &(sf->tokenvec[LIBINJECTION_SQLI_MAX_TOKENS]));
+		    st_copy(&(sf->tokenvec[1]), &(sf->tokenvec[LIBINJECTION_SQLI_MAX_TOKENS]));
                     pos = 2;
                     left = 0;
                 } else {
@@ -1521,9 +1521,9 @@ int libinjection_sqli_fold(struct libinjection_sqli_state * sf)
             continue;
         } else if (sf->tokenvec[left].type == TYPE_SEMICOLON &&
                    sf->tokenvec[left+1].type == TYPE_FUNCTION &&
-           (sf->tokenvec[left+1].val[0] == 'I' ||
-            sf->tokenvec[left+1].val[0] == 'i' ) &&
-           (sf->tokenvec[left+1].val[1] == 'F' ||
+		   (sf->tokenvec[left+1].val[0] == 'I' ||
+		    sf->tokenvec[left+1].val[0] == 'i' ) &&
+		   (sf->tokenvec[left+1].val[1] == 'F' ||
                     sf->tokenvec[left+1].val[1] == 'f' )) {
             /* IF is normally a function, except in Transact-SQL where it can be used as a
              * standalone control flow operator, e.g. ; IF 1=1 ...
diff --git a/apache2/mod_security2.c b/apache2/mod_security2.c
index 70121e7517..60a4b9eaa1 100755
--- a/apache2/mod_security2.c
+++ b/apache2/mod_security2.c
@@ -294,7 +294,7 @@ int perform_interception(modsec_rec *msr) {
                     csd = ap_get_module_config(msr->r->connection->conn_config, &core_module);
                 }
 #else
-        csd = ap_get_module_config(msr->r->connection->conn_config, &core_module);
+		csd = ap_get_module_config(msr->r->connection->conn_config, &core_module);
 #endif
                 if (csd) {
                     if (apr_socket_close(csd) == APR_SUCCESS) {
diff --git a/apache2/modsecurity.h b/apache2/modsecurity.h
index 2e0367aa7a..cdd707300a 100755
--- a/apache2/modsecurity.h
+++ b/apache2/modsecurity.h
@@ -231,8 +231,8 @@ extern DSOLOCAL char *msc_waf_lock_group;
 #define STATUS_ENGINE_ENABLED           1
 #define STATUS_ENGINE_DISABLED          0
 
-#define REMOTE_RULES_ABORT_ON_FAIL    0
-#define REMOTE_RULES_WARN_ON_FAIL    1
+#define REMOTE_RULES_ABORT_ON_FAIL	0
+#define REMOTE_RULES_WARN_ON_FAIL	1
 
 #define HASH_DISABLED             0
 #define HASH_ENABLED              1
@@ -412,8 +412,8 @@ struct modsec_rec {
 
     apr_size_t           msc_reqbody_no_files_length;
 
-    char        *msc_full_request_buffer;
-    int            msc_full_request_length;
+    char		*msc_full_request_buffer;
+    int			msc_full_request_length;
 
     char                *multipart_filename;
     char                *multipart_name;
@@ -439,15 +439,15 @@ struct modsec_rec {
 
     /* performance measurement */
     apr_time_t       request_time;
-    apr_time_t         time_phase1;
-    apr_time_t         time_phase2;
-    apr_time_t         time_phase3;
-    apr_time_t         time_phase4;
-    apr_time_t         time_phase5;
-    apr_time_t         time_storage_read;
-    apr_time_t         time_storage_write;
-    apr_time_t         time_logging;
-    apr_time_t         time_gc;
+    apr_time_t		 time_phase1;
+    apr_time_t		 time_phase2;
+    apr_time_t		 time_phase3;
+    apr_time_t		 time_phase4;
+    apr_time_t		 time_phase5;
+    apr_time_t		 time_storage_read;
+    apr_time_t		 time_storage_write;
+    apr_time_t		 time_logging;
+    apr_time_t		 time_gc;
     apr_table_t      *perf_rules;
 
     apr_array_header_t  *matched_rules;
@@ -670,7 +670,7 @@ struct directory_config {
     int                 xml_external_entity;
 #ifdef MEMORY_DATABASE_ENABLE
     /* AGMDB */
-    directory_config    *root_config;
+    directory_config	*root_config;
     int                 db_option;
     void                *agmdb_handles;    
 #endif
diff --git a/apache2/modsecurity_config.h b/apache2/modsecurity_config.h
index 69d9d8ef19..f18101683b 100644
--- a/apache2/modsecurity_config.h
+++ b/apache2/modsecurity_config.h
@@ -2,7 +2,7 @@
  * so this is here to prevent that by removing them.
  */
 
-#ifndef    WIN32
+#ifndef	WIN32
 
 /* Undefine all these so there are no conflicts */
 #undef PACKAGE
diff --git a/apache2/msc_json.h b/apache2/msc_json.h
index f22fe3ab2c..02326ec03d 100644
--- a/apache2/msc_json.h
+++ b/apache2/msc_json.h
@@ -54,7 +54,7 @@ int DSOLOCAL json_complete(modsec_rec *msr, char **error_msg);
 apr_status_t DSOLOCAL json_cleanup(modsec_rec *msr);
 
 int DSOLOCAL json_process_chunk(modsec_rec *msr, const char *buf,
-        unsigned int size, char **error_msg);
+		unsigned int size, char **error_msg);
 
 #endif
 #endif
diff --git a/apache2/msc_logging.c b/apache2/msc_logging.c
index 0f5ade79bb..35d867eb77 100755
--- a/apache2/msc_logging.c
+++ b/apache2/msc_logging.c
@@ -735,7 +735,7 @@ void sec_audit_logger_json(modsec_rec *msr) {
 
     /* Lock the mutex, but only if we are using serial format. */
     if (msr->txcfg->auditlog_type != AUDITLOG_CONCURRENT) {
-        rc = waf_get_exclusive_lock(msr->modsecurity->auditlog_lock);
+	    rc = waf_get_exclusive_lock(msr->modsecurity->auditlog_lock);
         if (waf_lock_is_error(rc)) {
             msr_log(msr, 1, "Audit log: Failed to lock global mutex: %s",
                 get_apr_error(msr->mp, rc));
@@ -1279,7 +1279,7 @@ void sec_audit_logger_json(modsec_rec *msr) {
             yajl_gen_map_close(g); // sanitized args map is finished
         }
 #ifdef LOG_NO_SERVER_CONTEXT
-    }
+	}
 #endif
 
         /* Web application info. */
@@ -1447,7 +1447,7 @@ void sec_audit_logger_json(modsec_rec *msr) {
     if (msr->txcfg->auditlog_type != AUDITLOG_CONCURRENT) {
 
         /* Unlock the mutex we used to serialise access to the audit log file. */
-        rc = waf_free_exclusive_lock(msr->modsecurity->auditlog_lock);
+	    rc = waf_free_exclusive_lock(msr->modsecurity->auditlog_lock);
         if (waf_lock_is_error(rc)) {
             msr_log(msr, 1, "Audit log: Failed to unlock global mutex: %s",
                     get_apr_error(msr->mp, rc));
@@ -1622,7 +1622,7 @@ void sec_audit_logger_native(modsec_rec *msr) {
 
     /* Lock the mutex, but only if we are using serial format. */
     if (msr->txcfg->auditlog_type != AUDITLOG_CONCURRENT) {
-        rc = waf_get_exclusive_lock(msr->modsecurity->auditlog_lock);
+	    rc = waf_get_exclusive_lock(msr->modsecurity->auditlog_lock);
         if (waf_lock_is_error(rc)) {
             msr_log(msr, 1, "Audit log: Failed to lock global mutex: %s",
                 get_apr_error(msr->mp, rc));
@@ -1991,16 +1991,16 @@ void sec_audit_logger_native(modsec_rec *msr) {
 
         /* Apache-Handler */
 #ifdef LOG_NO_HANDLER
-    if (msr->txcfg->debuglog_level >= 9)
+	if (msr->txcfg->debuglog_level >= 9)
 #endif
-    if (msr->r->handler != NULL) {
+	if (msr->r->handler != NULL) {
             text = apr_psprintf(msr->mp, "Apache-Handler: %s\n", msr->r->handler);
             sec_auditlog_write(msr, text, strlen(text));
         }
 
         /* Stopwatch; left in for compatibility reasons */
 #ifdef LOG_NO_STOPWATCH
-    if (msr->txcfg->debuglog_level >= 9) {
+	if (msr->txcfg->debuglog_level >= 9) {
 #endif
         text = apr_psprintf(msr->mp, "Stopwatch: %" APR_TIME_T_FMT " %" APR_TIME_T_FMT " (- - -)\n",
             msr->request_time, (now - msr->request_time));
@@ -2022,7 +2022,7 @@ void sec_audit_logger_native(modsec_rec *msr) {
         /* ENH Only write this when the output was chunked. */
         /* ENH Add info when request body was decompressed, dechunked too. */
 #ifdef LOG_NO_DECHUNK
-    if (msr->txcfg->debuglog_level >= 9)
+	if (msr->txcfg->debuglog_level >= 9)
 #endif
         if (wrote_response_body) {
             text = apr_psprintf(msr->mp, "Response-Body-Transformed: Dechunked\n");
@@ -2101,10 +2101,10 @@ void sec_audit_logger_native(modsec_rec *msr) {
             }
         }
 #ifdef LOG_NO_SERVER_CONTEXT
-    }
+	}
 #endif
 
-    /* Web application info. */
+	/* Web application info. */
         if ( ((msr->txcfg->webappid != NULL)&&(strcmp(msr->txcfg->webappid, "default") != 0))
             || (msr->sessionid != NULL) || (msr->userid != NULL))
         {
@@ -2227,7 +2227,7 @@ void sec_audit_logger_native(modsec_rec *msr) {
         sec_auditlog_write(msr, "\n", 1);
 
         /* Unlock the mutex we used to serialise access to the audit log file. */
-        rc = waf_free_exclusive_lock(msr->modsecurity->auditlog_lock);
+	    rc = waf_free_exclusive_lock(msr->modsecurity->auditlog_lock);
         if (waf_lock_is_error(rc)) {
             msr_log(msr, 1, "Audit log: Failed to unlock global mutex: %s",
                     get_apr_error(msr->mp, rc));
diff --git a/apache2/msc_release.h b/apache2/msc_release.h
index f1793be7ad..dcfde11c89 100644
--- a/apache2/msc_release.h
+++ b/apache2/msc_release.h
@@ -49,13 +49,13 @@
   MODSEC_VERSION_SUFFIX
 
 /* Apache Module Defines */
-#ifdef    VERSION_IIS
+#ifdef	VERSION_IIS
 #define MODSEC_MODULE_NAME "ModSecurity for IIS (STABLE)"
 #else
-#ifdef    VERSION_NGINX
+#ifdef	VERSION_NGINX
 #define MODSEC_MODULE_NAME "ModSecurity for nginx (STABLE)"
 #else
-#ifdef    VERSION_STANDALONE
+#ifdef	VERSION_STANDALONE
 #define MODSEC_MODULE_NAME "ModSecurity Standalone (STABLE)"
 #else
 #define MODSEC_MODULE_NAME "ModSecurity for Apache"
diff --git a/apache2/msc_util.c b/apache2/msc_util.c
index be3e2ec071..4f7fc2d084 100644
--- a/apache2/msc_util.c
+++ b/apache2/msc_util.c
@@ -1225,22 +1225,22 @@ char *log_escape(apr_pool_t *mp, const char *text) {
 
 char *log_escape_nq(apr_pool_t *mp, const char *text) {
 #ifdef VERSION_IIS
-    int l = 0;
-
-    // this is a workaround for unknown bug that causes 'text' sometimes to lack zero-termination
-    //
-    __try
-    {
-        l = text ? strlen(text) : 0;
-    }
-    __except(EXCEPTION_EXECUTE_HANDLER)
-    {
-        l = -1;
-    }
-    if(l < 0)
-        return _log_escape(mp, "BUG: see log_escape_nq()", 24, 0, 0, 0);
-
-    return _log_escape(mp, (const unsigned char *)text, l, 0, 0, 0);
+	int l = 0;
+
+	// this is a workaround for unknown bug that causes 'text' sometimes to lack zero-termination
+	//
+	__try
+	{
+		l = text ? strlen(text) : 0;
+	}
+	__except(EXCEPTION_EXECUTE_HANDLER)
+	{
+		l = -1;
+	}
+	if(l < 0)
+	    return _log_escape(mp, "BUG: see log_escape_nq()", 24, 0, 0, 0);
+
+	return _log_escape(mp, (const unsigned char *)text, l, 0, 0, 0);
 #else
     return _log_escape(mp, (const unsigned char *)text, text ? strlen(text) : 0, 0, 0, 0);
 #endif
diff --git a/apache2/persist_dbm.c b/apache2/persist_dbm.c
index dbe7e5ad6a..04262c97f4 100755
--- a/apache2/persist_dbm.c
+++ b/apache2/persist_dbm.c
@@ -171,8 +171,8 @@ static apr_table_t *collection_retrieve_ex(int db_option, void *existing_dbm, mo
         
         if (existing_dbm == NULL) {
 #ifdef GLOBAL_COLLECTION_LOCK
-        rc = waf_get_exclusive_lock(msr->modsecurity->dbm_lock);
-        if (waf_lock_is_error(rc)) {
+	    rc = waf_get_exclusive_lock(msr->modsecurity->dbm_lock);
+	    if (waf_lock_is_error(rc)) {
                 msr_log(msr, 1, "collection_retrieve_ex: Failed to lock proc mutex: %s",
                         get_apr_error(msr->mp, rc));
                 goto cleanup;
@@ -183,7 +183,7 @@ static apr_table_t *collection_retrieve_ex(int db_option, void *existing_dbm, mo
             if (rc != APR_SUCCESS) {
                 apr_dbm = NULL;
 #ifdef GLOBAL_COLLECTION_LOCK
-                waf_free_exclusive_lock(msr->modsecurity->dbm_lock);
+	            waf_free_exclusive_lock(msr->modsecurity->dbm_lock);
 #endif
                 goto cleanup;
             }
@@ -256,7 +256,7 @@ static apr_table_t *collection_retrieve_ex(int db_option, void *existing_dbm, mo
         if (existing_dbm == NULL) {
             apr_sdbm_close(apr_dbm);
 #ifdef GLOBAL_COLLECTION_LOCK
-            waf_free_exclusive_lock(msr->modsecurity->dbm_lock);
+	        waf_free_exclusive_lock(msr->modsecurity->dbm_lock);
 #endif
             apr_dbm = NULL;
         }
@@ -339,8 +339,8 @@ static apr_table_t *collection_retrieve_ex(int db_option, void *existing_dbm, mo
 #endif
             if (existing_dbm == NULL) {
 #ifdef GLOBAL_COLLECTION_LOCK
-            rc = waf_get_exclusive_lock(msr->modsecurity->dbm_lock);
-            if (waf_lock_is_error(rc)) {
+	        rc = waf_get_exclusive_lock(msr->modsecurity->dbm_lock);
+	        if (waf_lock_is_error(rc)) {
                     msr_log(msr, 1, "collection_retrieve_ex: Failed to lock proc mutex: %s",
                             get_apr_error(msr->mp, rc));
                     goto cleanup;
@@ -353,7 +353,7 @@ static apr_table_t *collection_retrieve_ex(int db_option, void *existing_dbm, mo
                         log_escape(msr->mp, dbm_filename), get_apr_error(msr->mp, rc));
                     apr_dbm = NULL;
 #ifdef GLOBAL_COLLECTION_LOCK
-                    waf_free_exclusive_lock(msr->modsecurity->dbm_lock);
+	                waf_free_exclusive_lock(msr->modsecurity->dbm_lock);
 #endif
                     goto cleanup;
                 }
@@ -368,7 +368,7 @@ static apr_table_t *collection_retrieve_ex(int db_option, void *existing_dbm, mo
             if (existing_dbm == NULL) {
                 apr_sdbm_close(apr_dbm);
 #ifdef GLOBAL_COLLECTION_LOCK
-                waf_free_exclusive_lock(msr->modsecurity->dbm_lock);
+	            waf_free_exclusive_lock(msr->modsecurity->dbm_lock);
 #endif
                 apr_dbm = NULL;
             }
@@ -451,7 +451,7 @@ static apr_table_t *collection_retrieve_ex(int db_option, void *existing_dbm, mo
 
         apr_sdbm_close(apr_dbm);
 #ifdef GLOBAL_COLLECTION_LOCK
-        waf_free_exclusive_lock(msr->modsecurity->dbm_lock);
+	    waf_free_exclusive_lock(msr->modsecurity->dbm_lock);
 #endif
     }
 
@@ -466,7 +466,7 @@ static apr_table_t *collection_retrieve_ex(int db_option, void *existing_dbm, mo
         if ((existing_dbm == NULL) && apr_dbm) {
             apr_sdbm_close(apr_dbm);
 #ifdef GLOBAL_COLLECTION_LOCK
-            waf_free_exclusive_lock(msr->modsecurity->dbm_lock);
+	        waf_free_exclusive_lock(msr->modsecurity->dbm_lock);
 #endif
         }
 #ifdef MEMORY_DATABASE_ENABLE
@@ -644,8 +644,8 @@ static int collection_store_ex(int db_option, modsec_rec *msr, apr_table_t *col)
         
 #ifdef GLOBAL_COLLECTION_LOCK
         /* Need to lock to pull in the stored data again and apply deltas. */
-    rc = waf_get_exclusive_lock(msr->modsecurity->dbm_lock);
-    if (waf_lock_is_error(rc)) {
+	rc = waf_get_exclusive_lock(msr->modsecurity->dbm_lock);
+	if (waf_lock_is_error(rc)) {
             msr_log(msr, 1, "collection_store: Failed to lock proc mutex: %s",
                     get_apr_error(msr->mp, rc));
             goto error;
@@ -656,7 +656,7 @@ static int collection_store_ex(int db_option, modsec_rec *msr, apr_table_t *col)
             CREATEMODE, msr->mp);
         if (rc != APR_SUCCESS) {
 #ifdef GLOBAL_COLLECTION_LOCK
-            waf_free_exclusive_lock(msr->modsecurity->dbm_lock);
+	        waf_free_exclusive_lock(msr->modsecurity->dbm_lock);
 #endif
             msr_log(msr, 1, "collection_store_ex_origin: Failed to access DBM file \"%s\": %s", log_escape(msr->mp, dbm_filename),
                 get_apr_error(msr->mp, rc));
@@ -784,7 +784,7 @@ static int collection_store_ex(int db_option, modsec_rec *msr, apr_table_t *col)
             if (apr_dbm != NULL) {
 #ifdef GLOBAL_COLLECTION_LOCK
                 apr_sdbm_close(apr_dbm);
-                waf_free_exclusive_lock(msr->modsecurity->dbm_lock);
+	            waf_free_exclusive_lock(msr->modsecurity->dbm_lock);
 #else
                 apr_sdbm_unlock(apr_dbm);
                 apr_sdbm_close(apr_dbm);
@@ -866,7 +866,7 @@ static int collection_store_ex(int db_option, modsec_rec *msr, apr_table_t *col)
             if (apr_dbm != NULL) {
 #ifdef GLOBAL_COLLECTION_LOCK
                 apr_sdbm_close(apr_dbm);
-                waf_free_exclusive_lock(msr->modsecurity->dbm_lock);
+	            waf_free_exclusive_lock(msr->modsecurity->dbm_lock);
 #else
                 apr_sdbm_unlock(apr_dbm);
                 apr_sdbm_close(apr_dbm);
@@ -877,7 +877,7 @@ static int collection_store_ex(int db_option, modsec_rec *msr, apr_table_t *col)
         }
 #ifdef GLOBAL_COLLECTION_LOCK
         apr_sdbm_close(apr_dbm);
-        waf_free_exclusive_lock(msr->modsecurity->dbm_lock);
+	    waf_free_exclusive_lock(msr->modsecurity->dbm_lock);
 #else
         apr_sdbm_unlock(apr_dbm);
         apr_sdbm_close(apr_dbm);
@@ -1063,7 +1063,7 @@ static int collections_remove_stale_ex(int db_option, modsec_rec *msr, const cha
                     rc = apr_sdbm_delete(apr_dbm, key);
                     if (rc != APR_SUCCESS) {
 #ifdef LOG_NO_COLL_DELET_PB
-            if (msr->txcfg->debuglog_level >= 9)
+			if (msr->txcfg->debuglog_level >= 9)
 #endif
                         msr_log(msr, 1, "collections_remove_stale: Failed deleting collection (name \"%s\", "
                             "key \"%s\"): %s", log_escape(msr->mp, col_name),
diff --git a/apache2/re.c b/apache2/re.c
index 6573d625c4..cf9f655ad9 100644
--- a/apache2/re.c
+++ b/apache2/re.c
@@ -1265,7 +1265,7 @@ msre_actionset *msre_actionset_merge(msre_engine *engine, apr_pool_t *mp, msre_a
 
     if (inherit_by_default == 0) {
         /* There is nothing to merge in this case. */
-        return msre_actionset_copy(mp, child);
+	    return msre_actionset_copy(mp, child);
     }
 
     /* Start with a copy of the parent configuration. */
diff --git a/apache2/re_actions.c b/apache2/re_actions.c
index 506b2f37ee..f81ddc87c7 100644
--- a/apache2/re_actions.c
+++ b/apache2/re_actions.c
@@ -1253,10 +1253,10 @@ static apr_status_t msre_action_ctl_execute(modsec_rec *msr, apr_pool_t *mptmp,
         if (msr->txcfg->debuglog_level >= 4) {
             msr_log(msr, 4, "Ctl: ruleRemoveTargetByTag tag=%s targets=%s", p1, p2);
         }
-    if (p2 == NULL) {
+	if (p2 == NULL) {
             msr_log(msr, 1, "ModSecurity: Missing target for tag \"%s\"", p1);
-        return -1;
-    }
+	    return -1;
+	}
 
     re = apr_pcalloc(msr->mp, sizeof(rule_exception));
     re->type = RULE_EXCEPTION_REMOVE_TAG;
@@ -1568,7 +1568,7 @@ apr_status_t msre_action_setvar_execute(modsec_rec *msr, apr_pool_t *mptmp,
 
     if (strcasecmp(col_name,"USER") == 0 || strcasecmp(col_name,"SESSION") == 0
         || strcasecmp(col_name, "RESOURCE") == 0) {
-    real_col_name = apr_psprintf(mptmp, "%s_%s", msr->txcfg->webappid, col_name);
+	real_col_name = apr_psprintf(mptmp, "%s_%s", msr->txcfg->webappid, col_name);
     }
 
     /* Locate the collection. */
@@ -1581,8 +1581,8 @@ apr_status_t msre_action_setvar_execute(modsec_rec *msr, apr_pool_t *mptmp,
 
     if (target_col == NULL) {
         if (msr->txcfg->debuglog_level >= 3) {
-        msr_log(msr, 3, "Could not set variable \"%s.%s\" as the collection does not exist.",
-            log_escape(msr->mp, col_name), log_escape(msr->mp, var_name));
+	    msr_log(msr, 3, "Could not set variable \"%s.%s\" as the collection does not exist.",
+	        log_escape(msr->mp, col_name), log_escape(msr->mp, var_name));
         }
 
         return 0;
diff --git a/appveyor.yml b/appveyor.yml
index 055612f258..1e26ae1279 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -4,7 +4,6 @@ services:
     - iis                 # start IIS
 
 install:
-    - git submodule update --init --recursive
     - "python --version"
     - ps: cd iis; .\getModSecurityPkgs.ps1 https://modsecurity.blob.core.windows.net/windows-artifacts
 
diff --git a/iis/ModSecurityIIS.vcxproj b/iis/ModSecurityIIS.vcxproj
index 5542559026..7f2822a409 100755
--- a/iis/ModSecurityIIS.vcxproj
+++ b/iis/ModSecurityIIS.vcxproj
@@ -120,7 +120,7 @@
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
     <ClCompile>
       <Optimization>Disabled</Optimization>
-      <AdditionalIncludeDirectories>dependencies\build_dir\pcre\include;dependencies\build_dir\pcre;dependencies\build_dir\libxml2\include;.\asio\asio\include;dependencies\build_dir\apache24\include;..\apache2;..\standalone;.\asio\asio\include;dependencies\build_dir\lloyd-yajl-f4b2b1a\build\yajl-2.0.1\include</AdditionalIncludeDirectories>
+      <AdditionalIncludeDirectories>dependencies\build_dir\pcre\include;dependencies\build_dir\pcre;dependencies\build_dir\libxml2\include;dependencies\build_dir\apache24\include;..\apache2;..\standalone;dependencies\build_dir\lloyd-yajl-f4b2b1a\build\yajl-2.0.1\include;</AdditionalIncludeDirectories>
       <PreprocessorDefinitions>_MBCS;%(PreprocessorDefinitions);WIN32;WINNT;inline=APR_INLINE;AP_DECLARE_STATIC;VERSION_IIS</PreprocessorDefinitions>
       <PrecompiledHeader>NotUsing</PrecompiledHeader>
       <PrecompiledHeaderFile>precomp.h</PrecompiledHeaderFile>
@@ -140,7 +140,7 @@
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Custom Debug|Win32'">
     <ClCompile>
       <Optimization>Disabled</Optimization>
-      <AdditionalIncludeDirectories>dependencies\build_dir\pcre\include;dependencies\build_dir\pcre;dependencies\build_dir\libxml2\include;.\asio\asio\include;dependencies\build_dir\apache24\include;..\apache2;..\standalone;.\asio\asio\include;dependencies\build_dir\lloyd-yajl-f4b2b1a\build\yajl-2.0.1\include</AdditionalIncludeDirectories>
+      <AdditionalIncludeDirectories>dependencies\build_dir\pcre\include;dependencies\build_dir\pcre;dependencies\build_dir\libxml2\include;dependencies\build_dir\apache24\include;..\apache2;..\standalone;dependencies\build_dir\lloyd-yajl-f4b2b1a\build\yajl-2.0.1\include;</AdditionalIncludeDirectories>
       <PreprocessorDefinitions>_MBCS;%(PreprocessorDefinitions);WIN32;WINNT;inline=APR_INLINE;AP_DECLARE_STATIC;VERSION_IIS</PreprocessorDefinitions>
       <PrecompiledHeader>NotUsing</PrecompiledHeader>
       <PrecompiledHeaderFile>precomp.h</PrecompiledHeaderFile>
@@ -217,7 +217,7 @@ net start W3SVC /y</Command>
     <ClCompile>
       <PreprocessorDefinitions>_MBCS;%(PreprocessorDefinitions);WIN32;WINNT;inline=APR_INLINE;AP_DECLARE_STATIC;VERSION_IIS</PreprocessorDefinitions>
       <PrecompiledHeader>NotUsing</PrecompiledHeader>
-      <AdditionalIncludeDirectories>dependencies\build_dir\pcre\include;dependencies\build_dir\pcre;dependencies\build_dir\libxml2\include;.\asio\asio\include;..\apache2;..\standalone;dependencies\build_dir\lloyd-yajl-f4b2b1a\build\yajl-2.0.1\include;</AdditionalIncludeDirectories>
+      <AdditionalIncludeDirectories>dependencies\build_dir\pcre\include;dependencies\build_dir\pcre;dependencies\build_dir\libxml2\include;..\apache2;..\standalone;dependencies\build_dir\lloyd-yajl-f4b2b1a\build\yajl-2.0.1\include;</AdditionalIncludeDirectories>
     </ClCompile>
     <Link>
       <ModuleDefinitionFile>mymodule.def</ModuleDefinitionFile>
@@ -325,8 +325,6 @@ net start W3SVC /y</Command>
     <ClInclude Include="..\apache2\re.h" />
     <ClInclude Include="..\apache2\utf8tables.h" />
     <ClInclude Include="..\standalone\api.h" />
-    <ClInclude Include="critical_section.h" />
-    <ClInclude Include="event_logger.h" />
     <ClInclude Include="moduleconfig.h" />
     <ClInclude Include="mymodule.h" />
     <ClInclude Include="mymodulefactory.h" />
diff --git a/iis/ModSecurityIIS.vcxproj.filters b/iis/ModSecurityIIS.vcxproj.filters
index 7d741e9623..cdc9bb8d90 100755
--- a/iis/ModSecurityIIS.vcxproj.filters
+++ b/iis/ModSecurityIIS.vcxproj.filters
@@ -201,8 +201,6 @@
     <ClInclude Include="..\apache2\msc_status_engine.h">
       <Filter>ModSecurity</Filter>
     </ClInclude>
-    <ClInclude Include="event_logger.h" />
-    <ClInclude Include="critical_section.h" />
   </ItemGroup>
   <ItemGroup>
     <None Include="ModSecurity.xml" />
diff --git a/iis/asio b/iis/asio
deleted file mode 160000
index 90f32660cd..0000000000
--- a/iis/asio
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit 90f32660cd503494b3707840cfbd5434d8e9dabe
diff --git a/iis/critical_section.h b/iis/critical_section.h
deleted file mode 100644
index 260e69b51d..0000000000
--- a/iis/critical_section.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
-* ModSecurity for Apache 2.x, http://www.modsecurity.org/
-* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/)
-*
-* You may not use this file except in compliance with
-* the License.  You may obtain a copy of the License at
-*
-*     http://www.apache.org/licenses/LICENSE-2.0
-*
-* If any of the files related to licensing are missing or if you have any
-* other questions related to licensing please contact Trustwave Holdings, Inc.
-* directly using the email address security@modsecurity.org.
-*/
-
-#pragma once
-
-#include <Windows.h>
-
-#include <mutex>
-
-// Implements BasicLockable requirements:
-//      https://en.cppreference.com/w/cpp/named_req/BasicLockable
-//
-// Like std::mutex, CriticalSection is neither Copyable nor Moveable.
-class CriticalSection
-{
-public:
-    CriticalSection() /* noexcept */
-    {
-        InitializeCriticalSection(&cs);
-    }
-
-    CriticalSection(const CriticalSection&) = delete;
-    CriticalSection(CriticalSection&&) = delete;
-    CriticalSection& operator=(const CriticalSection&) = delete;
-    CriticalSection& operator=(CriticalSection&&) = delete;
-
-    void lock() /* noexcept */
-    {
-        EnterCriticalSection(&cs);
-    }
-
-    void unlock() /* noexcept */
-    {
-        LeaveCriticalSection(&cs);
-    }
-
-    ~CriticalSection()
-    {
-        DeleteCriticalSection(&cs);
-    }
-
-private:
-    CRITICAL_SECTION cs;
-};
-
-using CriticalSectionLock = std::unique_lock<CriticalSection>;
\ No newline at end of file
diff --git a/iis/event_logger.h b/iis/event_logger.h
deleted file mode 100644
index c71a3db7a1..0000000000
--- a/iis/event_logger.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
-* ModSecurity for Apache 2.x, http://www.modsecurity.org/
-* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/)
-*
-* You may not use this file except in compliance with
-* the License.  You may obtain a copy of the License at
-*
-*     http://www.apache.org/licenses/LICENSE-2.0
-*
-* If any of the files related to licensing are missing or if you have any
-* other questions related to licensing please contact Trustwave Holdings, Inc.
-* directly using the email address security@modsecurity.org.
-*/
-
-#pragma once
-
-#include <Windows.h>
-
-// A simple class to use to write messages to common Windows event log.
-// The class is Moveable but non-Copyable.
-class EventLogger
-{
-public:
-    EventLogger() /* noexcept */
-        : handle{RegisterEventSource(nullptr, "ModSecurity")}
-    {
-    }
-
-    BOOL Log(const char* message, DWORD category)
-    {
-        if (handle != nullptr)
-        {
-            return ReportEvent(
-                handle,
-                category, 0, 0x1,
-                NULL, 1, 0, &message, NULL);
-        }
-        return FALSE;
-    }
-
-    EventLogger(const EventLogger&) = delete;
-    EventLogger& operator=(const EventLogger&) = delete;
-
-    EventLogger(EventLogger&& rhs) /* noexcept */
-        : handle(rhs.handle)
-    {
-        rhs.handle = nullptr;
-    }
-
-    EventLogger& operator=(EventLogger&& rhs) /* noexcept */
-    {
-        handle = rhs.handle;
-        rhs.handle = nullptr;
-        return *this;
-    }
-
-    ~EventLogger()
-    {
-        if (handle) {
-            DeregisterEventSource(handle);
-        }
-    }
-
-private:
-    HANDLE handle;
-};
\ No newline at end of file
diff --git a/iis/main.cpp b/iis/main.cpp
index 570c2d49c4..35bfa1dd6a 100644
--- a/iis/main.cpp
+++ b/iis/main.cpp
@@ -15,8 +15,7 @@
 #define WIN32_LEAN_AND_MEAN
 
 #undef inline
-
-#include <memory>
+#define inline inline
 
 //  IIS7 Server API header file
 #include "httpserv.h"
@@ -26,43 +25,78 @@
 #include "mymodulefactory.h"
 
 //  Global server instance
-IHttpServer* g_pHttpServer = nullptr;
+IHttpServer *                       g_pHttpServer = NULL;
 
 //  Global module context id
-void* g_pModuleContext = nullptr;
+PVOID                               g_pModuleContext = NULL;
 
 //  The RegisterModule entrypoint implementation.
 //  This method is called by the server when the module DLL is 
 //  loaded in order to create the module factory,
 //  and register for server events.
-HRESULT __stdcall
-RegisterModule(DWORD, IHttpModuleRegistrationInfo* moduleInfo, IHttpServer * httpServer)
+HRESULT
+__stdcall
+RegisterModule(
+    DWORD                           dwServerVersion,
+    IHttpModuleRegistrationInfo *   pModuleInfo,
+    IHttpServer *                   pHttpServer
+)
 {
-    if (moduleInfo == nullptr || httpServer == nullptr)
+    HRESULT                             hr = S_OK;
+    CMyHttpModuleFactory  *             pFactory = NULL;
+    //IHttpModuleRegistrationInfo2 *		pModuleInfo2;
+
+    if ( pModuleInfo == NULL || pHttpServer == NULL )
     {
-        return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
+        hr = HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
+        goto Finished;
     }
 
+    /*hr = HttpGetExtendedInterface( g_pGlobalInfo, 
+                                   pModuleInfo, 
+                                   &pModuleInfo2 );
+    if ( FAILED ( hr ) )
+    {
+        goto Finished;
+    }*/
+
     // step 1: save the IHttpServer and the module context id for future use
-    //
-    g_pModuleContext = moduleInfo->GetId();
-    g_pHttpServer = httpServer;
+	//
+    g_pModuleContext = pModuleInfo->GetId();
+    g_pHttpServer = pHttpServer;
 
-    try
+    // step 2: create the module factory
+	//
+    pFactory = new CMyHttpModuleFactory();
+    if ( pFactory == NULL )
     {
-        // step 2: create the module factory
-        //
-        auto factory = std::make_unique<CMyHttpModuleFactory>();
-
-        // step 3: register for server events
-        //
-        return moduleInfo->SetRequestNotifications(
-            factory.release(), /* module factory */
-            RQ_BEGIN_REQUEST /* server event mask */,
-            0 /* server post event mask */);
+        hr = HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
+        goto Finished;
     }
-    catch (const std::bad_alloc&)
+
+    // step 3: register for server events
+	//
+    hr = pModuleInfo->SetRequestNotifications( pFactory, /* module factory */
+                                               RQ_BEGIN_REQUEST | RQ_SEND_RESPONSE /* server event mask */,
+                                               RQ_END_REQUEST /* server post event mask */);
+    if ( FAILED( hr ) )
     {
-        return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
+        goto Finished;
     }
+
+	hr = pModuleInfo->SetPriorityForRequestNotification(RQ_BEGIN_REQUEST, PRIORITY_ALIAS_FIRST);
+	hr = pModuleInfo->SetPriorityForRequestNotification(RQ_SEND_RESPONSE, PRIORITY_ALIAS_LAST);	// reverted!
+	//hr = pModuleInfo2->SetPriorityForPostRequestNotification(RQ_END_REQUEST, PRIORITY_ALIAS_LAST);
+
+    pFactory = NULL;
+
+Finished:
+    
+/*    if ( pFactory != NULL )
+    {
+        delete pFactory;
+        pFactory = NULL;
+    }   */
+
+    return hr;
 }
diff --git a/iis/moduleconfig.cpp b/iis/moduleconfig.cpp
index b78dc27d67..b47a531a33 100644
--- a/iis/moduleconfig.cpp
+++ b/iis/moduleconfig.cpp
@@ -15,6 +15,7 @@
 #define WIN32_LEAN_AND_MEAN
 
 #undef inline
+#define inline inline
 
 //  IIS7 Server API header file
 #include "httpserv.h"
@@ -464,7 +465,8 @@ MODSECURITY_STORED_CONTEXT::~MODSECURITY_STORED_CONTEXT()
 
 MODSECURITY_STORED_CONTEXT::MODSECURITY_STORED_CONTEXT():
     m_bIsEnabled ( FALSE ),
-    m_pszPath( NULL )
+    m_pszPath( NULL ),
+	m_Config( NULL )
 {
 }
 
@@ -577,17 +579,17 @@ MODSECURITY_STORED_CONTEXT::GetConfig(
     HRESULT                          hr                 = S_OK;
     MODSECURITY_STORED_CONTEXT * pModuleConfig      = NULL;
     IHttpModuleContextContainer *    pMetadataContainer = NULL;
-    IAppHostConfigException *        pException         = NULL;
+	IAppHostConfigException *        pException         = NULL;
 
     pMetadataContainer = pContext->GetMetadata()->GetModuleContextContainer();
 
-    if ( pMetadataContainer == NULL )
-    {
+	if ( pMetadataContainer == NULL )
+	{
         hr = E_UNEXPECTED;
         return hr;
-    }
+	}
 
-    pModuleConfig = (MODSECURITY_STORED_CONTEXT *)pMetadataContainer->GetModuleContext( g_pModuleContext );    
+    pModuleConfig = (MODSECURITY_STORED_CONTEXT *)pMetadataContainer->GetModuleContext( g_pModuleContext );	
     if ( pModuleConfig != NULL )
     {
         //
diff --git a/iis/moduleconfig.h b/iis/moduleconfig.h
index e7da87a4e6..1fb33e29a7 100644
--- a/iis/moduleconfig.h
+++ b/iis/moduleconfig.h
@@ -16,21 +16,19 @@
 
 #define MODSECURITY_SECTION                        L"system.webServer/ModSecurity"
 #define MODSECURITY_SECTION_ENABLED                L"enabled"
-#define MODSECURITY_SECTION_CONFIGFILE               L"configFile"
+#define MODSECURITY_SECTION_CONFIGFILE			   L"configFile"
 
 extern IHttpServer *                       g_pHttpServer;
 
 extern PVOID                               g_pModuleContext;
 
-struct directory_config; // forward declaration
-
 class MODSECURITY_STORED_CONTEXT : public IHttpStoredContext
 {
  public:
     MODSECURITY_STORED_CONTEXT();
     ~MODSECURITY_STORED_CONTEXT();
     
-    static
+	static
     HRESULT
     GetConfig(
         IHttpContext *   pContext,
@@ -69,7 +67,7 @@ class MODSECURITY_STORED_CONTEXT : public IHttpStoredContext
             CHAR**  ppszDestination,
             USHORT*  pdwLengthDestination );
 
-    directory_config* config = nullptr;
+	void*			  m_Config;
 
     bool configLoadingFailed = false;
 
diff --git a/iis/mymodule.cpp b/iis/mymodule.cpp
index dde8695a7b..1e5e32c3c8 100644
--- a/iis/mymodule.cpp
+++ b/iis/mymodule.cpp
@@ -15,10 +15,7 @@
 #define WIN32_LEAN_AND_MEAN
 
 #undef inline
-
-#include <string>
-#include <cctype>
-#include <memory>
+#define inline inline
 
 //  IIS7 Server API header file
 #include <Windows.h>
@@ -35,103 +32,104 @@
 
 #include "winsock2.h"
 
-// These helpers make sure that the underlying structures
-// are correctly released on any exit path due to RAII.
-using ConnRecPtr = std::unique_ptr<conn_rec, decltype(modsecFinishConnection)*>;
-using RequestRecPtr = std::unique_ptr<request_rec, decltype(modsecFinishRequest)*>;
-
-static ConnRecPtr MakeConnReq()
-{
-    ConnRecPtr c{modsecNewConnection(), modsecFinishConnection};
-    modsecProcessConnection(c.get());
-    return c;
-}
-
-static RequestRecPtr MakeRequestRec(conn_rec* c, directory_config* config)
-{
-    return {modsecNewRequest(c, config), modsecFinishRequest};
-}
 
-class AprRequestContext
+class REQUEST_STORED_CONTEXT : public IHttpStoredContext
 {
-private:
-    ConnRecPtr connRec;
-    RequestRecPtr requestRec;
-
-public:
-    explicit AprRequestContext(directory_config* config)
-        : connRec{MakeConnReq()}
-        , requestRec{MakeRequestRec(connRec.get(), config)}
-    {}
-
-    AprRequestContext(const AprRequestContext&) = delete;
-    AprRequestContext& operator=(const AprRequestContext&) = delete;
-
-    AprRequestContext(AprRequestContext&& rhs)
-        : connRec(std::move(rhs.connRec))
-        , requestRec(std::move(rhs.requestRec))
-    {}
-
-    AprRequestContext& operator=(AprRequestContext&& rhs)
+ public:
+    REQUEST_STORED_CONTEXT()
+	{
+		m_pConnRec = NULL;
+		m_pRequestRec = NULL;
+		m_pHttpContext = NULL;
+		m_pProvider = NULL;
+		m_pResponseBuffer = NULL;
+		m_pResponseLength = 0;
+		m_pResponsePosition = 0;
+	}
+
+    ~REQUEST_STORED_CONTEXT()
+	{
+		FinishRequest();
+	}
+    
+    // virtual
+    VOID
+    CleanupStoredContext(
+        VOID
+    )
     {
-        connRec = std::move(rhs.connRec);
-        requestRec = std::move(rhs.requestRec);
-        return *this;
+		FinishRequest();
+        delete this;
     }
 
-    conn_rec* GetConnection() const
-    {
-        return connRec.get();
-    }
-
-    request_rec* GetRequest() const
-    {
-        return requestRec.get();
-    }
+	void FinishRequest()
+	{
+		if(m_pRequestRec != NULL)
+		{
+			modsecFinishRequest(m_pRequestRec);
+			m_pRequestRec = NULL;
+		}
+		if(m_pConnRec != NULL)
+		{
+			modsecFinishConnection(m_pConnRec);
+			m_pConnRec = NULL;
+		}
+	}
+
+	conn_rec			*m_pConnRec;
+	request_rec			*m_pRequestRec;
+	IHttpContext		*m_pHttpContext;
+	IHttpEventProvider	*m_pProvider;
+	char				*m_pResponseBuffer;
+	ULONGLONG			m_pResponseLength;
+	ULONGLONG			m_pResponsePosition;
 };
 
+
+//----------------------------------------------------------------------------
+
 char *GetIpAddr(apr_pool_t *pool, PSOCKADDR pAddr)
 {
-    const char *format = "%15[0-9.]:%5[0-9]";
-    char ip[16] = { 0 };  // ip4 addresses have max len 15
-    char port[6] = { 0 }; // port numbers are 16bit, ie 5 digits max
+	const char *format = "%15[0-9.]:%5[0-9]";
+	char ip[16] = { 0 };  // ip4 addresses have max len 15
+	char port[6] = { 0 }; // port numbers are 16bit, ie 5 digits max
 
-    DWORD len = 50;
-    char *buf = (char *)apr_palloc(pool, len);
+	DWORD len = 50;
+	char *buf = (char *)apr_palloc(pool, len);
 
-    if(buf == NULL)
-        return "";
+	if(buf == NULL)
+		return "";
 
-    buf[0] = 0;
+	buf[0] = 0;
 
-    WSAAddressToString(pAddr, sizeof(SOCKADDR), NULL, buf, &len);
+	WSAAddressToString(pAddr, sizeof(SOCKADDR), NULL, buf, &len);
 
-    // test for IPV4 with port on the end
-    if (sscanf(buf, format, ip, port) == 2) {
-        // IPV4 but with port - remove the port
-        char* input = ":";
-        char* ipv4 = strtok(buf, input);
-        return ipv4;
-    }
+	// test for IPV4 with port on the end
+	if (sscanf(buf, format, ip, port) == 2) {
+		// IPV4 but with port - remove the port
+		char* input = ":";
+		char* ipv4 = strtok(buf, input);
+		return ipv4;
+	}
 
-    return buf;
+	return buf;
 }
 
 apr_sockaddr_t *CopySockAddr(apr_pool_t *pool, PSOCKADDR pAddr)
 {
     apr_sockaddr_t *addr = (apr_sockaddr_t *)apr_palloc(pool, sizeof(apr_sockaddr_t));
-    int adrlen = 16, iplen = 4;
+	int adrlen = 16, iplen = 4;
 
-    if(pAddr->sa_family == AF_INET6)
-    {
-        adrlen = 46;
-        iplen = 16;
-    }
+	if(pAddr->sa_family == AF_INET6)
+	{
+		adrlen = 46;
+		iplen = 16;
+	}
 
-    addr->addr_str_len = adrlen;
-    addr->family = pAddr->sa_family;
+	addr->addr_str_len = adrlen;
+	addr->family = pAddr->sa_family;
 
-    addr->hostname = "unknown";
+	addr->hostname = "unknown";
 #ifdef WIN32
     addr->ipaddr_len = sizeof(IN_ADDR);
 #else
@@ -141,29 +139,29 @@ apr_sockaddr_t *CopySockAddr(apr_pool_t *pool, PSOCKADDR pAddr)
     addr->pool = pool;
     addr->port = 80;
 #ifdef WIN32
-    memcpy(&addr->sa.sin.sin_addr.S_un.S_addr, pAddr->sa_data, iplen);
+	memcpy(&addr->sa.sin.sin_addr.S_un.S_addr, pAddr->sa_data, iplen);
 #else
     memcpy(&addr->sa.sin.sin_addr.s_addr, pAddr->sa_data, iplen);
 #endif
-    addr->sa.sin.sin_family = pAddr->sa_family;
+	addr->sa.sin.sin_family = pAddr->sa_family;
     addr->sa.sin.sin_port = 80;
     addr->salen = sizeof(addr->sa);
-    addr->servname = addr->hostname;
+	addr->servname = addr->hostname;
 
-    return addr;
+	return addr;
 }
 
 //----------------------------------------------------------------------------
 
 char *ZeroTerminate(const char *str, size_t len, apr_pool_t *pool)
 {
-    char *_n = (char *)apr_palloc(pool, len + 1);
+	char *_n = (char *)apr_palloc(pool, len + 1);
 
-    memcpy(_n, str, len);
+	memcpy(_n, str, len);
 
-    _n[len] = 0;
+	_n[len] = 0;
 
-    return _n;
+	return _n;
 }
 
 //----------------------------------------------------------------------------
@@ -197,7 +195,7 @@ char *ConvertUTF16ToUTF8( __in const WCHAR * pszTextUTF16, size_t cchUTF16, apr_
 
     if ( cbUTF8 == 0 )
     {
-        return "";
+		return "";
     }
 
     //
@@ -224,258 +222,665 @@ char *ConvertUTF16ToUTF8( __in const WCHAR * pszTextUTF16, size_t cchUTF16, apr_
 
     if ( result == 0 )
     {
-        return "";
+		return "";
     }
 
-    pszUTF8[cchUTF8] =  0;
+	pszUTF8[cchUTF8] =  0;
 
     return pszUTF8;
 }
  
-static void Log(void *obj, int level, char *str)
+void Log(void *obj, int level, char *str)
 {
-    CMyHttpModule *mod = (CMyHttpModule *)obj;
-    WORD logcat = EVENTLOG_INFORMATION_TYPE;
+	CMyHttpModule *mod = (CMyHttpModule *)obj;
+	WORD logcat = EVENTLOG_INFORMATION_TYPE;
 
-    level &= APLOG_LEVELMASK;
+	level &= APLOG_LEVELMASK;
 
-    if(level <= APLOG_ERR)
-        logcat = EVENTLOG_ERROR_TYPE;
+	if(level <= APLOG_ERR)
+		logcat = EVENTLOG_ERROR_TYPE;
 
-    if(level == APLOG_WARNING || strstr(str, "Warning.") != NULL)
-        logcat = EVENTLOG_WARNING_TYPE;
+	if(level == APLOG_WARNING || strstr(str, "Warning.") != NULL)
+		logcat = EVENTLOG_WARNING_TYPE;
 
-    mod->WriteEventViewerLog(str, logcat);
+	mod->WriteEventViewerLog(str, logcat);
 }
 
-/*
- * Read request body from IIS structures, copy it over into
- * Apache buckets and then assign back the entire flatten body
- * to IHttpRequest.
- * If the request body is chunked, it will be transformed into fixed-length.
-*/
-static HRESULT SaveRequestBodyToRequestRec(IHttpContext* httpContext, const AprRequestContext& aprContext)
+#define NOTE_IIS "iis-tx-context"
+
+void StoreIISContext(request_rec *r, REQUEST_STORED_CONTEXT *rsc)
+{
+    apr_table_setn(r->notes, NOTE_IIS, (const char *)rsc);
+}
+
+REQUEST_STORED_CONTEXT *RetrieveIISContext(request_rec *r)
 {
-    request_rec* aprRequest = aprContext.GetRequest();
-    conn_rec* conn = aprContext.GetConnection();
-    IHttpRequest* iisRequest = httpContext->GetRequest();
-    apr_bucket_brigade* brigade = apr_brigade_create(conn->pool, conn->bucket_alloc);
-    if (brigade == nullptr)
+    REQUEST_STORED_CONTEXT *msr = NULL;
+    request_rec *rx = NULL;
+
+    /* Look in the current request first. */
+    msr = (REQUEST_STORED_CONTEXT *)apr_table_get(r->notes, NOTE_IIS);
+    if (msr != NULL) {
+        //msr->r = r;
+        return msr;
+    }
+
+    /* If this is a subrequest then look in the main request. */
+    if (r->main != NULL) {
+        msr = (REQUEST_STORED_CONTEXT *)apr_table_get(r->main->notes, NOTE_IIS);
+        if (msr != NULL) {
+            //msr->r = r;
+            return msr;
+        }
+    }
+
+    /* If the request was redirected then look in the previous requests. */
+    rx = r->prev;
+    while(rx != NULL) {
+        msr = (REQUEST_STORED_CONTEXT *)apr_table_get(rx->notes, NOTE_IIS);
+        if (msr != NULL) {
+            //msr->r = r;
+            return msr;
+        }
+        rx = rx->prev;
+    }
+
+    return NULL;
+}
+
+
+HRESULT CMyHttpModule::ReadFileChunk(HTTP_DATA_CHUNK *chunk, char *buf)
+{
+    OVERLAPPED ovl;
+    DWORD dwDataStartOffset;
+    ULONGLONG bytesTotal = 0;
+	BYTE *	pIoBuffer = NULL;
+	HANDLE	hIoEvent = INVALID_HANDLE_VALUE;
+	HRESULT hr = S_OK;
+
+    pIoBuffer = (BYTE *)VirtualAlloc(NULL,
+                                        1,
+                                        MEM_COMMIT | MEM_RESERVE,
+                                        PAGE_READWRITE);
+    if (pIoBuffer == NULL)
     {
-        return E_OUTOFMEMORY;
+        hr = HRESULT_FROM_WIN32(GetLastError());
+		goto Done;
     }
 
-    while (iisRequest->GetRemainingEntityBytes() > 0)
+    hIoEvent = CreateEvent(NULL,  // security attr
+                                FALSE, // manual reset
+                                FALSE, // initial state
+                                NULL); // name
+    if (hIoEvent == NULL)
     {
-        DWORD bytesRead = 0;
-        char* buf = static_cast<char*>(apr_palloc(aprRequest->pool, HUGE_STRING_LEN));
-        HRESULT hr = iisRequest->ReadEntityBody(buf, HUGE_STRING_LEN, false, &bytesRead, nullptr);
-        if (FAILED(hr))
-        {
-            // End of data is okay.
-            if (ERROR_HANDLE_EOF != (hr & 0x0000FFFF))
-            {
-                return hr;
-            }
+        hr = HRESULT_FROM_WIN32(GetLastError());
+		goto Done;
+    }
 
-            break;
-        }
+	while(bytesTotal < chunk->FromFileHandle.ByteRange.Length.QuadPart)
+	{
+		DWORD bytesRead = 0;
+		int was_eof = 0;
+		ULONGLONG offset = chunk->FromFileHandle.ByteRange.StartingOffset.QuadPart + bytesTotal;
+
+		ZeroMemory(&ovl, sizeof ovl);
+		ovl.hEvent     = hIoEvent;
+		ovl.Offset = (DWORD)offset;
+		dwDataStartOffset = ovl.Offset & (m_dwPageSize - 1);
+		ovl.Offset &= ~(m_dwPageSize - 1);
+		ovl.OffsetHigh = offset >> 32;
+
+		if (!ReadFile(chunk->FromFileHandle.FileHandle,
+					  pIoBuffer,
+					  m_dwPageSize,
+					  &bytesRead,
+					  &ovl))
+		{
+			DWORD dwErr = GetLastError();
+
+			switch (dwErr)
+			{
+			case ERROR_IO_PENDING:
+				//
+				// GetOverlappedResult can return without waiting for the
+				// event thus leaving it signalled and causing problems
+				// with future use of that event handle, so just wait ourselves
+				//
+				WaitForSingleObject(ovl.hEvent, INFINITE); // == WAIT_OBJECT_0);
+
+				if (!GetOverlappedResult(
+						 chunk->FromFileHandle.FileHandle,
+						 &ovl,
+						 &bytesRead,
+						 TRUE))
+				{
+					dwErr = GetLastError();
+
+					switch(dwErr)
+					{
+					case ERROR_HANDLE_EOF:
+						was_eof = 1;
+						break;
+
+					default:
+						hr = HRESULT_FROM_WIN32(dwErr);
+						goto Done;
+					}
+				}
+				break;
+
+			case ERROR_HANDLE_EOF:
+				was_eof = 1;
+				break;
+
+			default:
+				hr = HRESULT_FROM_WIN32(dwErr);
+				goto Done;
+			}
+		}
+
+		bytesRead -= dwDataStartOffset;
+
+		if (bytesRead > chunk->FromFileHandle.ByteRange.Length.QuadPart)
+		{
+			bytesRead = (DWORD)chunk->FromFileHandle.ByteRange.Length.QuadPart;
+		}
+		if ((bytesTotal + bytesRead) > chunk->FromFileHandle.ByteRange.Length.QuadPart)
+		{ 
+			bytesRead = chunk->FromFileHandle.ByteRange.Length.QuadPart - bytesTotal; 
+		}
+
+		memcpy(buf, pIoBuffer + dwDataStartOffset, bytesRead);
+
+		buf += bytesRead;
+		bytesTotal += bytesRead;
+
+		if(was_eof != 0)
+			chunk->FromFileHandle.ByteRange.Length.QuadPart = bytesTotal;
+	}
+
+Done:
+	if(NULL != pIoBuffer)
+	{
+		VirtualFree(pIoBuffer, 0, MEM_RELEASE);
+	}
+
+	if(INVALID_HANDLE_VALUE != hIoEvent)
+	{
+		CloseHandle(hIoEvent);
+	}
+
+	return hr;
+}
+
+REQUEST_NOTIFICATION_STATUS
+CMyHttpModule::OnSendResponse(
+    IN IHttpContext * pHttpContext,
+    IN ISendResponseProvider * pResponseProvider
+)
+{
+	REQUEST_STORED_CONTEXT *rsc = NULL;
+
+	rsc = (REQUEST_STORED_CONTEXT *)pHttpContext->GetModuleContextContainer()->GetModuleContext(g_pModuleContext);
+
+	EnterCriticalSection(&m_csLock);
+
+	// here we must check if response body processing is enabled
+	//
+	if(rsc == NULL || rsc->m_pRequestRec == NULL || rsc->m_pResponseBuffer != NULL || !modsecIsResponseBodyAccessEnabled(rsc->m_pRequestRec))
+	{
+		goto Exit;
+	}
+
+    HRESULT hr = S_OK;
+	IHttpResponse *pHttpResponse = NULL;
+    HTTP_RESPONSE *pRawHttpResponse = NULL;
+    HTTP_BYTE_RANGE *pFileByteRange = NULL;
+    HTTP_DATA_CHUNK *pSourceDataChunk = NULL;
+    LARGE_INTEGER  lFileSize;
+    REQUEST_NOTIFICATION_STATUS ret = RQ_NOTIFICATION_CONTINUE;
+	ULONGLONG ulTotalLength = 0;
+	DWORD c;
+	request_rec *r = rsc->m_pRequestRec;
+
+	pHttpResponse = pHttpContext->GetResponse();
+	pRawHttpResponse = pHttpResponse->GetRawHttpResponse();
+
+	// here we must add handling of chunked response
+	// apparently IIS 7 calls this handler once per chunk
+	// see: http://stackoverflow.com/questions/4385249/how-to-buffer-and-process-chunked-data-before-sending-headers-in-iis7-native-mod
+
+	if(pRawHttpResponse->EntityChunkCount == 0)
+		goto Exit;
+
+	// here we must transfer response headers
+	//
+	USHORT ctcch = 0;
+	char *ct = (char *)pHttpResponse->GetHeader(HttpHeaderContentType, &ctcch);
+	char *ctz = ZeroTerminate(ct, ctcch, r->pool);
+
+	// assume HTML if content type not set
+	// without this output filter would not buffer response and processing would hang
+	//
+	if(ctz[0] == 0)
+		ctz = "text/html";
+
+	r->content_type = ctz;
+
+#define _TRANSHEADER(id,str) if(pRawHttpResponse->Headers.KnownHeaders[id].pRawValue != NULL) \
+	{\
+		apr_table_setn(r->headers_out, str, \
+			ZeroTerminate(pRawHttpResponse->Headers.KnownHeaders[id].pRawValue, pRawHttpResponse->Headers.KnownHeaders[id].RawValueLength, r->pool)); \
+	}
 
-        apr_bucket* bucket = apr_bucket_pool_create(buf, bytesRead, aprRequest->pool, conn->bucket_alloc);
-        if (bucket == nullptr)
+    _TRANSHEADER(HttpHeaderCacheControl, "Cache-Control");
+    _TRANSHEADER(HttpHeaderConnection, "Connection");
+    _TRANSHEADER(HttpHeaderDate, "Date");
+    _TRANSHEADER(HttpHeaderKeepAlive, "Keep-Alive");             
+    _TRANSHEADER(HttpHeaderPragma, "Pragma");                
+    _TRANSHEADER(HttpHeaderTrailer, "Trailer");               
+    _TRANSHEADER(HttpHeaderTransferEncoding, "Transfer-Encoding");      
+    _TRANSHEADER(HttpHeaderUpgrade, "Upgrade");               
+    _TRANSHEADER(HttpHeaderVia, "Via");                   
+    _TRANSHEADER(HttpHeaderWarning, "Warning");               
+    _TRANSHEADER(HttpHeaderAllow, "Allow");                 
+    _TRANSHEADER(HttpHeaderContentLength, "Content-Length");         
+    _TRANSHEADER(HttpHeaderContentType, "Content-Type");           
+    _TRANSHEADER(HttpHeaderContentEncoding, "Content-Encoding");       
+    _TRANSHEADER(HttpHeaderContentLanguage, "Content-Language");       
+    _TRANSHEADER(HttpHeaderContentLocation, "Content-Location");       
+    _TRANSHEADER(HttpHeaderContentMd5, "Content-Md5");            
+    _TRANSHEADER(HttpHeaderContentRange, "Content-Range");          
+    _TRANSHEADER(HttpHeaderExpires, "Expires");               
+    _TRANSHEADER(HttpHeaderLastModified, "Last-Modified");          
+	_TRANSHEADER(HttpHeaderAcceptRanges, "Accept-Ranges");
+    _TRANSHEADER(HttpHeaderAge, "Age");                   
+    _TRANSHEADER(HttpHeaderEtag, "Etag");                  
+    _TRANSHEADER(HttpHeaderLocation, "Location");              
+    _TRANSHEADER(HttpHeaderProxyAuthenticate, "Proxy-Authenticate");     
+    _TRANSHEADER(HttpHeaderRetryAfter, "Retry-After");            
+    _TRANSHEADER(HttpHeaderServer, "Server");                
+    _TRANSHEADER(HttpHeaderSetCookie, "Set-Cookie");             
+    _TRANSHEADER(HttpHeaderVary, "Vary");                  
+    _TRANSHEADER(HttpHeaderWwwAuthenticate, "Www-Authenticate");
+
+#undef	_TRANSHEADER
+
+	for(int i = 0; i < pRawHttpResponse->Headers.UnknownHeaderCount; i++)
+	{
+		apr_table_setn(r->headers_out, 
+			ZeroTerminate(pRawHttpResponse->Headers.pUnknownHeaders[i].pName, pRawHttpResponse->Headers.pUnknownHeaders[i].NameLength, r->pool), 
+			ZeroTerminate(pRawHttpResponse->Headers.pUnknownHeaders[i].pRawValue, pRawHttpResponse->Headers.pUnknownHeaders[i].RawValueLength, r->pool));
+	}
+
+	r->content_encoding = apr_table_get(r->headers_out, "Content-Encoding");
+	//r->content_type = apr_table_get(r->headers_out, "Content-Type");		-- already set above
+
+	const char *lng = apr_table_get(r->headers_out, "Content-Languages");
+
+	if(lng != NULL)
+	{
+		r->content_languages = apr_array_make(r->pool, 1, sizeof(const char *));
+
+		*(const char **)apr_array_push(r->content_languages) = lng;
+	}
+
+	// Disable kernel caching for this response
+	// Probably we don't have to do it for ModSecurity
+
+    //pHttpContext->GetResponse()->DisableKernelCache(
+    //        IISCacheEvents::HTTPSYS_CACHEABLE::HANDLER_HTTPSYS_UNFRIENDLY);
+
+    for(c = 0; c < pRawHttpResponse->EntityChunkCount; c++ )
+    {
+        pSourceDataChunk = &pRawHttpResponse->pEntityChunks[ c ];
+
+        switch( pSourceDataChunk->DataChunkType )
         {
-            return E_OUTOFMEMORY;
+            case HttpDataChunkFromMemory:
+                ulTotalLength += pSourceDataChunk->FromMemory.BufferLength;
+                break;
+            case HttpDataChunkFromFileHandle:
+                pFileByteRange = &pSourceDataChunk->FromFileHandle.ByteRange;
+                //
+                // File chunks may contain by ranges with unspecified length 
+                // (HTTP_BYTE_RANGE_TO_EOF).  In order to send parts of such a chunk, 
+                // its necessary to know when the chunk is finished, and
+                // we need to move to the next chunk.
+                //              
+                if ( pFileByteRange->Length.QuadPart == HTTP_BYTE_RANGE_TO_EOF)
+                {
+                    if ( GetFileType( pSourceDataChunk->FromFileHandle.FileHandle ) == 
+                                    FILE_TYPE_DISK )
+                    {
+                        if ( !GetFileSizeEx( pSourceDataChunk->FromFileHandle.FileHandle,
+                                             &lFileSize ) )
+                        {
+                            DWORD dwError = GetLastError();
+                            hr = HRESULT_FROM_WIN32(dwError);
+                            goto Finished;
+                        }
+
+                        // put the resolved file length in the chunk, replacing 
+                        // HTTP_BYTE_RANGE_TO_EOF
+                        pFileByteRange->Length.QuadPart = 
+                              lFileSize.QuadPart - pFileByteRange->StartingOffset.QuadPart;
+                    }
+                    else
+                    {
+                        hr = HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
+                        goto Finished;                        
+                    }
+                }  
+
+                ulTotalLength += pFileByteRange->Length.QuadPart;
+                break;
+            default:
+                // TBD: consider implementing HttpDataChunkFromFragmentCache, 
+                // and HttpDataChunkFromFragmentCacheEx
+                hr = HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
+                goto Finished;                        
         }
-        APR_BRIGADE_INSERT_TAIL(brigade, bucket);
     }
 
-    if (!APR_BRIGADE_EMPTY(brigade)) {
-        apr_bucket* e = apr_bucket_eos_create(conn->bucket_alloc);
-        if (e == nullptr)
-        {
-            return E_OUTOFMEMORY;
-        }
-        APR_BRIGADE_INSERT_TAIL(brigade, e);
+	rsc->m_pResponseBuffer = (char *)apr_palloc(rsc->m_pRequestRec->pool, ulTotalLength);
 
-        modsecSetBodyBrigade(aprRequest, brigade);
+	ulTotalLength = 0;
 
-        apr_off_t contentLength = 0;
-        apr_status_t status = apr_brigade_length(brigade, FALSE, &contentLength);
-        if (status != APR_SUCCESS)
-        {
-            return E_FAIL;
-        }
+    for(c = 0; c < pRawHttpResponse->EntityChunkCount; c++ )
+    {
+        pSourceDataChunk = &pRawHttpResponse->pEntityChunks[ c ];
 
-        // Remove/Modify Transfer-Encoding header if "chunked" Encoding is set in the request. 
-        // This is to avoid sending both Content-Length and Chunked Transfer-Encoding in the request header.
-        static const std::string CHUNKED = "chunked";
-        USHORT encodingLength = 0;
-        const char* transferEncoding = iisRequest->GetHeader(HttpHeaderTransferEncoding, &encodingLength);
-        if (transferEncoding)
+        switch( pSourceDataChunk->DataChunkType )
         {
-            if (encodingLength == CHUNKED.size() &&
-                std::equal(CHUNKED.cbegin(), CHUNKED.cend(), transferEncoding,
-                [](char lhs, char rhs) { return std::tolower(lhs) == std::tolower(rhs); }))
-            {
-                iisRequest->DeleteHeader(HttpHeaderTransferEncoding);
-            }
+            case HttpDataChunkFromMemory:
+				memcpy(rsc->m_pResponseBuffer + ulTotalLength, pSourceDataChunk->FromMemory.pBuffer, pSourceDataChunk->FromMemory.BufferLength);
+                ulTotalLength += pSourceDataChunk->FromMemory.BufferLength;
+                break;
+            case HttpDataChunkFromFileHandle:
+                pFileByteRange = &pSourceDataChunk->FromFileHandle.ByteRange;
+
+				if(ReadFileChunk(pSourceDataChunk, rsc->m_pResponseBuffer + ulTotalLength) != S_OK)
+				{
+			        DWORD dwErr = GetLastError();
+
+					hr = HRESULT_FROM_WIN32(dwErr);
+	                goto Finished;
+				}
+
+                ulTotalLength += pFileByteRange->Length.QuadPart;
+                break;
+            default:
+                // TBD: consider implementing HttpDataChunkFromFragmentCache, 
+                // and HttpDataChunkFromFragmentCacheEx
+                hr = HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
+                goto Finished;                        
         }
+    }
 
-        auto contentLengthStr = std::to_string(contentLength);
-        HRESULT hr = iisRequest->SetHeader(
-            HttpHeaderContentLength,
-            contentLengthStr.c_str(),
-            contentLengthStr.size(),
-            TRUE);
+	rsc->m_pResponseLength = ulTotalLength;
+
+	//
+    // If there's no content-length set, we need to set it to avoid chunked transfer mode
+    // We can only do it if there is it's the only response to be sent.
+    //
+
+    DWORD dwFlags = pResponseProvider->GetFlags();
 
-        if (FAILED(hr))
+	if (pResponseProvider->GetHeadersBeingSent() && 
+         (dwFlags & HTTP_SEND_RESPONSE_FLAG_MORE_DATA) == 0 &&
+         pHttpContext->GetResponse()->GetHeader(HttpHeaderContentLength) == NULL)    
+    {
+        CHAR szLength[21]; //Max length for a 64 bit int is 20
+
+         ZeroMemory(szLength, sizeof(szLength));
+
+         hr = StringCchPrintfA(
+                    szLength, 
+                    sizeof(szLength) / sizeof(CHAR) - 1, "%d", 
+                    ulTotalLength);
+
+        if(FAILED(hr))
         {
-            return hr;
+            goto Finished;      
         }
 
-        // since we clean the APR pool at the end of OnSendRequest, we must get IIS-managed memory chunk
-        //
-        char* requestBuffer = static_cast<char*>(httpContext->AllocateRequestMemory(contentLength));
-        status = apr_brigade_flatten(brigade, requestBuffer, reinterpret_cast<apr_size_t*>(&contentLength));
-        if (status != APR_SUCCESS)
+         hr = pHttpContext->GetResponse()->SetHeader(
+                    HttpHeaderContentLength, 
+                    szLength, 
+                    (USHORT)strlen(szLength),
+                    TRUE);
+
+        if(FAILED(hr))
         {
-            return E_FAIL;
+            goto Finished;      
         }
-        return iisRequest->InsertEntityBody(requestBuffer, contentLength);
     }
 
-    return S_OK;
+Finished:
+
+	int status = modsecProcessResponse(rsc->m_pRequestRec);
+
+	// the logic here is temporary, needs clarification
+	//
+	if(status != 0 && status != -1)
+	{
+		pHttpContext->GetResponse()->Clear();
+		pHttpContext->GetResponse()->SetStatus(status, "ModSecurity Action");
+		pHttpContext->SetRequestHandled();
+
+		rsc->FinishRequest();
+
+		LeaveCriticalSection(&m_csLock);
+		
+		return RQ_NOTIFICATION_FINISH_REQUEST;
+	}
+Exit:
+	// temporary hack, in reality OnSendRequest theoretically could possibly come before OnEndRequest
+	//
+	if(rsc != NULL)
+		rsc->FinishRequest();
+
+	LeaveCriticalSection(&m_csLock);
+		
+	return RQ_NOTIFICATION_CONTINUE;
 }
 
 REQUEST_NOTIFICATION_STATUS
-CMyHttpModule::OnBeginRequest(IHttpContext* httpContext, IHttpEventProvider* provider)
+CMyHttpModule::OnPostEndRequest(
+    IN IHttpContext * pHttpContext,
+    IN IHttpEventProvider * pProvider
+)
 {
-    if (httpContext == nullptr || httpContext->GetRequest() == nullptr)
+	REQUEST_STORED_CONTEXT *rsc = NULL;
+
+	rsc = (REQUEST_STORED_CONTEXT *)pHttpContext->GetModuleContextContainer()->GetModuleContext(g_pModuleContext);
+
+	// only finish request if OnSendResponse have been called already
+	//
+	if(rsc != NULL && rsc->m_pResponseBuffer != NULL)
+	{
+		EnterCriticalSection(&m_csLock);
+
+		rsc->FinishRequest();
+
+		LeaveCriticalSection(&m_csLock);
+	}
+
+	return RQ_NOTIFICATION_CONTINUE;
+}
+
+REQUEST_NOTIFICATION_STATUS
+CMyHttpModule::OnBeginRequest(
+    IN IHttpContext * pHttpContext,
+    IN IHttpEventProvider * pProvider
+)
+{
+    HRESULT                         hr                  = S_OK;
+    IHttpRequest*                   pRequest            = NULL;
+	MODSECURITY_STORED_CONTEXT*		pConfig = NULL;
+    
+    UNREFERENCED_PARAMETER ( pProvider );
+
+	EnterCriticalSection(&m_csLock);
+
+    if ( pHttpContext == NULL ) 
     {
-        return RQ_NOTIFICATION_FINISH_REQUEST;
+        hr = E_UNEXPECTED;
+        goto Finished;
     }
 
-    CriticalSectionLock lock{cs};
-    MODSECURITY_STORED_CONTEXT* config = nullptr;
-    HRESULT hr = MODSECURITY_STORED_CONTEXT::GetConfig(httpContext, &config);
-    if (FAILED(hr))
+    pRequest = pHttpContext->GetRequest();
+
+    if ( pRequest == NULL )
     {
-        httpContext->GetResponse()->SetStatus(500, "WAF internal error. Unable to get config.");
-        httpContext->SetRequestHandled();
-        return RQ_NOTIFICATION_FINISH_REQUEST;
+        hr = E_UNEXPECTED;
+        goto Finished;
     }
 
-    // If module is disabled, don't go any further
-    //
-    if (!config->GetIsEnabled())
+    hr = MODSECURITY_STORED_CONTEXT::GetConfig(pHttpContext, &pConfig );
+    
+    if ( FAILED( hr ) )
     {
-        return RQ_NOTIFICATION_CONTINUE;
+        pHttpContext->GetResponse()->SetStatus(500, "WAF internal error. Unable to get config.");
+        pHttpContext->SetRequestHandled();
+        return RQ_NOTIFICATION_FINISH_REQUEST;
     }
 
-    auto reportConfigurationError = [config, httpContext] {
-        config->configLoadingFailed = true;
-        httpContext->GetResponse()->SetStatus(500, "WAF internal error. Invalid configuration.");
-        httpContext->SetRequestHandled();
+	// If module is disabled, dont go any further
+	//
+	if( pConfig->GetIsEnabled() == false )
+	{
+        goto Finished;
+	}
+
+    auto reportConfigurationError = [pConfig, pHttpContext] {
+        pConfig->configLoadingFailed = true;
+        pHttpContext->GetResponse()->SetStatus(500, "WAF internal error. Invalid configuration.");
+        pHttpContext->SetRequestHandled();
         return RQ_NOTIFICATION_FINISH_REQUEST;
     };
 
     // If we previously failed to load the config, don't spam the event log by trying and failing again
-    if (config->configLoadingFailed)
+    if (pConfig->configLoadingFailed)
     {
         return reportConfigurationError();
     }
 
-    if (config->config == nullptr)
-    {
-        char *path;
-        USHORT pathlen;
+	if(pConfig->m_Config == NULL)
+	{
+		char *path;
+		USHORT pathlen;
 
-        hr = config->GlobalWideCharToMultiByte(config->GetPath(), wcslen(config->GetPath()), &path, &pathlen);
-        if (FAILED(hr))
-        {
+		hr = pConfig->GlobalWideCharToMultiByte(pConfig->GetPath(), wcslen(pConfig->GetPath()), &path, &pathlen);
+
+		if ( FAILED( hr ) )
+		{
             return reportConfigurationError();
-        }
+		}
 
-        config->config = modsecGetDefaultConfig();
+		pConfig->m_Config = modsecGetDefaultConfig();
 
-        PCWSTR servpath = httpContext->GetApplication()->GetApplicationPhysicalPath();
-        char *apppath;
-        USHORT apppathlen;
+		PCWSTR servpath = pHttpContext->GetApplication()->GetApplicationPhysicalPath();
+		char *apppath;
+		USHORT apppathlen;
 
-        hr = config->GlobalWideCharToMultiByte((WCHAR *)servpath, wcslen(servpath), &apppath, &apppathlen);
-        if (FAILED(hr))
-        {
-            delete path;
+		hr = pConfig->GlobalWideCharToMultiByte((WCHAR *)servpath, wcslen(servpath), &apppath, &apppathlen);
+
+		if ( FAILED( hr ) )
+		{
+			delete path;
             return reportConfigurationError();
-        }
+		}
 
-        if (path[0] != 0)
-        {
-            const char * err = modsecProcessConfig(config->config, path, apppath);
+		if(path[0] != 0)
+		{
+			const char * err = modsecProcessConfig((directory_config *)pConfig->m_Config, path, apppath);
 
-            if (err != NULL)
-            {
-                WriteEventViewerLog(err, EVENTLOG_ERROR_TYPE);
-                delete apppath;
-                delete path;
+			if(err != NULL)
+			{
+				WriteEventViewerLog(err, EVENTLOG_ERROR_TYPE);
+				delete apppath;
+				delete path;
                 return reportConfigurationError();
-            }
-
-            modsecReportRemoteLoadedRules();
-            if (!statusCallAlreadySent)
-            {
-                statusCallAlreadySent = true;
-                modsecStatusEngineCall();
-            }
-        }
+			}
 
-        delete apppath;
-        delete path;
-    }
+			modsecReportRemoteLoadedRules();
+			if (this->status_call_already_sent == false)
+			{
+				this->status_call_already_sent = true;
+				modsecStatusEngineCall();
+			}
+		}
 
-    AprRequestContext aprContext{config->config};
-    conn_rec* c = aprContext.GetConnection();
-    request_rec* r = aprContext.GetRequest();
+		delete apppath;
+		delete path;
+	}
 
-    HTTP_REQUEST *req = httpContext->GetRequest()->GetRawHttpRequest();
+	conn_rec *c;
+	request_rec *r;
 
-    r->hostname = ConvertUTF16ToUTF8(req->CookedUrl.pHost, req->CookedUrl.HostLength / sizeof(WCHAR), r->pool);
-    r->path_info = ConvertUTF16ToUTF8(req->CookedUrl.pAbsPath, req->CookedUrl.AbsPathLength / sizeof(WCHAR), r->pool);
+	c = modsecNewConnection();
+	modsecProcessConnection(c);
 
-    if(r->hostname == NULL)
-    {
-        if(req->Headers.KnownHeaders[HttpHeaderHost].pRawValue != NULL)
-            r->hostname = ZeroTerminate(req->Headers.KnownHeaders[HttpHeaderHost].pRawValue,
-                                        req->Headers.KnownHeaders[HttpHeaderHost].RawValueLength, r->pool);
-    }
+	r = modsecNewRequest(c, (directory_config *)pConfig->m_Config);
 
-    int port = 0;
-    char *port_str = NULL;
+	// on IIS we force input stream inspection flag, because its absence does not add any performance gain
+	// it's because on IIS request body must be restored each time it was read
+	//
+	modsecSetConfigForIISRequestBody(r);
 
-    if(r->hostname != NULL)
-    {
-        int k = 0;
-        char *ptr = (char *)r->hostname;
+	REQUEST_STORED_CONTEXT *rsc = new REQUEST_STORED_CONTEXT();
 
-        while(*ptr != 0 && *ptr != ':')
-            ptr++;
+	rsc->m_pConnRec = c;
+	rsc->m_pRequestRec = r;
+	rsc->m_pHttpContext = pHttpContext;
+	rsc->m_pProvider = pProvider;
 
-        if(*ptr == ':')
-        {
-            *ptr = 0;
-            port_str = ptr + 1;
-            port = atoi(port_str);
-        }
-    }
+	pHttpContext->GetModuleContextContainer()->SetModuleContext(rsc, g_pModuleContext);
+
+	StoreIISContext(r, rsc);
+
+	HTTP_REQUEST *req = pRequest->GetRawHttpRequest();
+
+	r->hostname = ConvertUTF16ToUTF8(req->CookedUrl.pHost, req->CookedUrl.HostLength / sizeof(WCHAR), r->pool);
+	r->path_info = ConvertUTF16ToUTF8(req->CookedUrl.pAbsPath, req->CookedUrl.AbsPathLength / sizeof(WCHAR), r->pool);
+
+	if(r->hostname == NULL)
+	{
+		if(req->Headers.KnownHeaders[HttpHeaderHost].pRawValue != NULL)
+			r->hostname = ZeroTerminate(req->Headers.KnownHeaders[HttpHeaderHost].pRawValue,
+										req->Headers.KnownHeaders[HttpHeaderHost].RawValueLength, r->pool);
+	}
+
+	int port = 0;
+	char *port_str = NULL;
+
+	if(r->hostname != NULL)
+	{
+		int k = 0;
+		char *ptr = (char *)r->hostname;
 
-    if(req->CookedUrl.pQueryString != NULL && req->CookedUrl.QueryStringLength > 0)
-        r->args = ConvertUTF16ToUTF8(req->CookedUrl.pQueryString + 1, (req->CookedUrl.QueryStringLength / sizeof(WCHAR)) - 1, r->pool);
+		while(*ptr != 0 && *ptr != ':')
+			ptr++;
+
+		if(*ptr == ':')
+		{
+			*ptr = 0;
+			port_str = ptr + 1;
+			port = atoi(port_str);
+		}
+	}
+
+	if(req->CookedUrl.pQueryString != NULL && req->CookedUrl.QueryStringLength > 0)
+		r->args = ConvertUTF16ToUTF8(req->CookedUrl.pQueryString + 1, (req->CookedUrl.QueryStringLength / sizeof(WCHAR)) - 1, r->pool);
 
 #define _TRANSHEADER(id,str) if(req->Headers.KnownHeaders[id].pRawValue != NULL) \
-    {\
-        apr_table_setn(r->headers_in, str, \
-            ZeroTerminate(req->Headers.KnownHeaders[id].pRawValue, req->Headers.KnownHeaders[id].RawValueLength, r->pool)); \
-    }
+	{\
+		apr_table_setn(r->headers_in, str, \
+			ZeroTerminate(req->Headers.KnownHeaders[id].pRawValue, req->Headers.KnownHeaders[id].RawValueLength, r->pool)); \
+	}
 
     _TRANSHEADER(HttpHeaderCacheControl, "Cache-Control");
     _TRANSHEADER(HttpHeaderConnection, "Connection");
@@ -521,188 +926,410 @@ CMyHttpModule::OnBeginRequest(IHttpContext* httpContext, IHttpEventProvider* pro
 
 #undef _TRANSHEADER
 
-    for(int i = 0; i < req->Headers.UnknownHeaderCount; i++)
-    {
-        apr_table_setn(r->headers_in, 
-            ZeroTerminate(req->Headers.pUnknownHeaders[i].pName, req->Headers.pUnknownHeaders[i].NameLength, r->pool), 
-            ZeroTerminate(req->Headers.pUnknownHeaders[i].pRawValue, req->Headers.pUnknownHeaders[i].RawValueLength, r->pool));
-    }
+	for(int i = 0; i < req->Headers.UnknownHeaderCount; i++)
+	{
+		apr_table_setn(r->headers_in, 
+			ZeroTerminate(req->Headers.pUnknownHeaders[i].pName, req->Headers.pUnknownHeaders[i].NameLength, r->pool), 
+			ZeroTerminate(req->Headers.pUnknownHeaders[i].pRawValue, req->Headers.pUnknownHeaders[i].RawValueLength, r->pool));
+	}
 
-    r->content_encoding = apr_table_get(r->headers_in, "Content-Encoding");
-    r->content_type = apr_table_get(r->headers_in, "Content-Type");
+	r->content_encoding = apr_table_get(r->headers_in, "Content-Encoding");
+	r->content_type = apr_table_get(r->headers_in, "Content-Type");
 
-    const char *lng = apr_table_get(r->headers_in, "Content-Languages");
+	const char *lng = apr_table_get(r->headers_in, "Content-Languages");
 
-    if(lng != NULL)
-    {
-        r->content_languages = apr_array_make(r->pool, 1, sizeof(const char *));
+	if(lng != NULL)
+	{
+		r->content_languages = apr_array_make(r->pool, 1, sizeof(const char *));
 
-        *(const char **)apr_array_push(r->content_languages) = lng;
-    }
+		*(const char **)apr_array_push(r->content_languages) = lng;
+	}
 
-    switch(req->Verb)
-    {
-    case HttpVerbUnparsed:
-    case HttpVerbUnknown:
-    case HttpVerbInvalid:
+	switch(req->Verb)
+	{
+	case HttpVerbUnparsed:
+	case HttpVerbUnknown:
+	case HttpVerbInvalid:
     case HttpVerbTRACK:  // used by Microsoft Cluster Server for a non-logged trace
     case HttpVerbSEARCH:
-    default:
-        r->method = "INVALID";
-        r->method_number = M_INVALID;
-        break;
-    case HttpVerbOPTIONS:
-        r->method = "OPTIONS";
-        r->method_number = M_OPTIONS;
-        break;
-    case HttpVerbGET:
-    case HttpVerbHEAD:
-        r->method = "GET";
-        r->method_number = M_GET;
-        break;
-    case HttpVerbPOST:
-        r->method = "POST";
-        r->method_number = M_POST;
-        break;
+	default:
+		r->method = "INVALID";
+		r->method_number = M_INVALID;
+		break;
+	case HttpVerbOPTIONS:
+		r->method = "OPTIONS";
+		r->method_number = M_OPTIONS;
+		break;
+	case HttpVerbGET:
+	case HttpVerbHEAD:
+		r->method = "GET";
+		r->method_number = M_GET;
+		break;
+	case HttpVerbPOST:
+		r->method = "POST";
+		r->method_number = M_POST;
+		break;
     case HttpVerbPUT:
-        r->method = "PUT";
-        r->method_number = M_PUT;
-        break;
+		r->method = "PUT";
+		r->method_number = M_PUT;
+		break;
     case HttpVerbDELETE:
-        r->method = "DELETE";
-        r->method_number = M_DELETE;
-        break;
+		r->method = "DELETE";
+		r->method_number = M_DELETE;
+		break;
     case HttpVerbTRACE:
-        r->method = "TRACE";
-        r->method_number = M_TRACE;
-        break;
+		r->method = "TRACE";
+		r->method_number = M_TRACE;
+		break;
     case HttpVerbCONNECT:
-        r->method = "CONNECT";
-        r->method_number = M_CONNECT;
-        break;
+		r->method = "CONNECT";
+		r->method_number = M_CONNECT;
+		break;
     case HttpVerbMOVE:
-        r->method = "MOVE";
-        r->method_number = M_MOVE;
-        break;
+		r->method = "MOVE";
+		r->method_number = M_MOVE;
+		break;
     case HttpVerbCOPY:
-        r->method = "COPY";
-        r->method_number = M_COPY;
-        break;
+		r->method = "COPY";
+		r->method_number = M_COPY;
+		break;
     case HttpVerbPROPFIND:
-        r->method = "PROPFIND";
-        r->method_number = M_PROPFIND;
-        break;
+		r->method = "PROPFIND";
+		r->method_number = M_PROPFIND;
+		break;
     case HttpVerbPROPPATCH:
-        r->method = "PROPPATCH";
-        r->method_number = M_PROPPATCH;
-        break;
+		r->method = "PROPPATCH";
+		r->method_number = M_PROPPATCH;
+		break;
     case HttpVerbMKCOL:
-        r->method = "MKCOL";
-        r->method_number = M_MKCOL;
-        break;
+		r->method = "MKCOL";
+		r->method_number = M_MKCOL;
+		break;
     case HttpVerbLOCK:
-        r->method = "LOCK";
-        r->method_number = M_LOCK;
-        break;
+		r->method = "LOCK";
+		r->method_number = M_LOCK;
+		break;
     case HttpVerbUNLOCK:
-        r->method = "UNLOCK";
-        r->method_number = M_UNLOCK;
-        break;
-    }
+		r->method = "UNLOCK";
+		r->method_number = M_UNLOCK;
+		break;
+	}
 
-    if(HTTP_EQUAL_VERSION(req->Version, 0, 9))
-        r->protocol = "HTTP/0.9";
-    else if(HTTP_EQUAL_VERSION(req->Version, 1, 0))
-        r->protocol = "HTTP/1.0";
-    else
-        r->protocol = "HTTP/1.1";
+	if(HTTP_EQUAL_VERSION(req->Version, 0, 9))
+		r->protocol = "HTTP/0.9";
+	else if(HTTP_EQUAL_VERSION(req->Version, 1, 0))
+		r->protocol = "HTTP/1.0";
+	else
+		r->protocol = "HTTP/1.1";
 
-    r->request_time = apr_time_now();
+	r->request_time = apr_time_now();
 
-    r->parsed_uri.scheme = "http";
-    r->parsed_uri.path = r->path_info;
-    r->parsed_uri.hostname = (char *)r->hostname;
-    r->parsed_uri.is_initialized = 1;
-    r->parsed_uri.port = port;
-    r->parsed_uri.port_str = port_str;
-    r->parsed_uri.query = r->args;
-    r->parsed_uri.dns_looked_up = 0;
-    r->parsed_uri.dns_resolved = 0;
-    r->parsed_uri.password = NULL;
-    r->parsed_uri.user = NULL;
-    r->parsed_uri.fragment = NULL;
+	r->parsed_uri.scheme = "http";
+	r->parsed_uri.path = r->path_info;
+	r->parsed_uri.hostname = (char *)r->hostname;
+	r->parsed_uri.is_initialized = 1;
+	r->parsed_uri.port = port;
+	r->parsed_uri.port_str = port_str;
+	r->parsed_uri.query = r->args;
+	r->parsed_uri.dns_looked_up = 0;
+	r->parsed_uri.dns_resolved = 0;
+	r->parsed_uri.password = NULL;
+	r->parsed_uri.user = NULL;
+	r->parsed_uri.fragment = NULL;
 
-    r->unparsed_uri = ZeroTerminate(req->pRawUrl, req->RawUrlLength, r->pool);
-    r->uri = r->unparsed_uri;
+	r->unparsed_uri = ZeroTerminate(req->pRawUrl, req->RawUrlLength, r->pool);
+	r->uri = r->unparsed_uri;
 
-    r->the_request = (char *)apr_palloc(r->pool, strlen(r->method) + 1 + req->RawUrlLength + 1 + strlen(r->protocol) + 1);
+	r->the_request = (char *)apr_palloc(r->pool, strlen(r->method) + 1 + req->RawUrlLength + 1 + strlen(r->protocol) + 1);
 
-    strcpy(r->the_request, r->method);
-    strcat(r->the_request, " ");
-    strcat(r->the_request, r->uri);
-    strcat(r->the_request, " ");
-    strcat(r->the_request, r->protocol);
+	strcpy(r->the_request, r->method);
+	strcat(r->the_request, " ");
+	strcat(r->the_request, r->uri);
+	strcat(r->the_request, " ");
+	strcat(r->the_request, r->protocol);
 
-    HTTP_REQUEST_ID httpRequestID;
-    char *pszValue = (char *)apr_palloc(r->pool, 24);
+	HTTP_REQUEST_ID httpRequestID;
+	char *pszValue = (char *)apr_palloc(r->pool, 24);
 
-    httpRequestID = httpContext->GetRequest()->GetRawHttpRequest()->RequestId;
+	httpRequestID = pRequest->GetRawHttpRequest()->RequestId;
 
-    _ui64toa(httpRequestID, pszValue, 10);
+	_ui64toa(httpRequestID, pszValue, 10);
 
-    apr_table_setn(r->subprocess_env, "UNIQUE_ID", pszValue);
+	apr_table_setn(r->subprocess_env, "UNIQUE_ID", pszValue);
 
-    PSOCKADDR pAddr = httpContext->GetRequest()->GetRemoteAddress();
+	PSOCKADDR pAddr = pRequest->GetRemoteAddress();
 
 #if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER < 3
     c->remote_addr = CopySockAddr(r->pool, pAddr);
     c->remote_ip = GetIpAddr(r->pool, pAddr);
 #else
     c->client_addr = CopySockAddr(r->pool, pAddr);
-    c->client_ip = GetIpAddr(r->pool, pAddr);
+	c->client_ip = GetIpAddr(r->pool, pAddr);
 #endif
-    c->remote_host = NULL;
+	c->remote_host = NULL;
+
+    LeaveCriticalSection(&m_csLock);
+	int status = modsecProcessRequest(r);
+    EnterCriticalSection(&m_csLock);
+
+	if(status != DECLINED)
+	{
+		pHttpContext->GetResponse()->SetStatus(status, "ModSecurity Action");
+		pHttpContext->SetRequestHandled();
+
+		hr = E_FAIL;
+		goto Finished;
+	}
+
+Finished:
+	LeaveCriticalSection(&m_csLock);
+
+    if ( FAILED( hr )  )
+    {
+        return RQ_NOTIFICATION_FINISH_REQUEST;
+    }
+	return RQ_NOTIFICATION_CONTINUE;
+}
+
+
+apr_status_t ReadBodyCallback(request_rec *r, char *buf, unsigned int length, unsigned int *readcnt, int *is_eos)
+{
+    REQUEST_STORED_CONTEXT *rsc = RetrieveIISContext(r);
+
+    *readcnt = 0;
+
+    if (rsc == NULL)
+    {
+        *is_eos = 1;
+        return APR_SUCCESS;
+    }
+
+    IHttpContext *pHttpContext = rsc->m_pHttpContext;
+    IHttpRequest *pRequest = pHttpContext->GetRequest();
+
+    if (pRequest->GetRemainingEntityBytes() == 0)
+    {
+        *is_eos = 1;
+        return APR_SUCCESS;
+    }
+
+    HRESULT hr = pRequest->ReadEntityBody(buf, length, false, (DWORD *)readcnt, NULL);
 
-    if (config->config->reqbody_access) {
-        hr = SaveRequestBodyToRequestRec(httpContext, aprContext);
-        if (FAILED(hr)) {
-            provider->SetErrorStatus(hr);
-            return RQ_NOTIFICATION_FINISH_REQUEST;
+    if (FAILED(hr))
+    {
+        // End of data is okay.
+        if (ERROR_HANDLE_EOF != (hr & 0x0000FFFF))
+        {
+            // Set the error status.
+            rsc->m_pProvider->SetErrorStatus(hr);
         }
+
+        *is_eos = 1;
     }
 
-    lock.unlock();
-    int status = modsecProcessRequest(r);
-    lock.lock();
+    return APR_SUCCESS;
+}
+
+apr_status_t WriteBodyCallback(request_rec *r, char *buf, unsigned int length)
+{
+	REQUEST_STORED_CONTEXT *rsc = RetrieveIISContext(r);
+
+	if(rsc == NULL || rsc->m_pRequestRec == NULL)
+		return APR_SUCCESS;
 
-    if (status != DECLINED)
+	IHttpContext *pHttpContext = rsc->m_pHttpContext;
+	IHttpRequest *pHttpRequest = pHttpContext->GetRequest();
+
+    CHAR szLength[21]; //Max length for a 64 bit int is 20
+
+    ZeroMemory(szLength, sizeof(szLength));
+
+    HRESULT hr = StringCchPrintfA(
+            szLength, 
+            sizeof(szLength) / sizeof(CHAR) - 1, "%d", 
+            length);
+
+    if(FAILED(hr))
     {
-        httpContext->GetResponse()->SetStatus(status, "ModSecurity Action");
-        httpContext->SetRequestHandled();
+		// not possible
+    }
 
-        return RQ_NOTIFICATION_FINISH_REQUEST;
+	// Remove/Modify Transfer-Encoding header if "chunked" Encoding is set in the request. 
+	// This is to avoid sending both Content-Length and Chunked Transfer-Encoding in the request header.
+
+	USHORT ctcch = 0;
+	char *ct = (char *)pHttpRequest->GetHeader(HttpHeaderTransferEncoding, &ctcch);
+	if (ct)
+	{
+		char *ctz = ZeroTerminate(ct, ctcch, r->pool);
+		if (ctcch != 0)
+		{
+			if (0 == stricmp(ctz, "chunked"))
+			{
+				pHttpRequest->DeleteHeader(HttpHeaderTransferEncoding);
+			}
+		}
+	}
+	
+    hr = pHttpRequest->SetHeader(
+            HttpHeaderContentLength, 
+            szLength, 
+            (USHORT)strlen(szLength),
+            TRUE);
+
+    if(FAILED(hr))
+    {
+		// possible, but there's nothing we can do
     }
 
-    return RQ_NOTIFICATION_CONTINUE;
+	// since we clean the APR pool at the end of OnSendRequest, we must get IIS-managed memory chunk
+	//
+	void *reqbuf = pHttpContext->AllocateRequestMemory(length);
+
+	memcpy(reqbuf, buf, length);
+
+	pHttpRequest->InsertEntityBody(reqbuf, length);
+
+	return APR_SUCCESS;
 }
 
-CMyHttpModule::CMyHttpModule()
+apr_status_t ReadResponseCallback(request_rec *r, char *buf, unsigned int length, unsigned int *readcnt, int *is_eos)
+{
+	REQUEST_STORED_CONTEXT *rsc = RetrieveIISContext(r);
+
+	*readcnt = 0;
+
+	if(rsc == NULL || rsc->m_pResponseBuffer == NULL)
+	{
+		*is_eos = 1;
+		return APR_SUCCESS;
+	}
+
+	unsigned int size = length;
+
+	if(size > rsc->m_pResponseLength - rsc->m_pResponsePosition)
+		size = rsc->m_pResponseLength - rsc->m_pResponsePosition;
+
+	memcpy(buf, rsc->m_pResponseBuffer + rsc->m_pResponsePosition, size);
+
+	*readcnt = size;
+	rsc->m_pResponsePosition += size;
+
+	if(rsc->m_pResponsePosition >= rsc->m_pResponseLength)
+		*is_eos = 1;
+
+	return APR_SUCCESS;
+}
+
+apr_status_t WriteResponseCallback(request_rec *r, char *buf, unsigned int length)
 {
-    modsecSetLogHook(this, Log);
+	REQUEST_STORED_CONTEXT *rsc = RetrieveIISContext(r);
+
+	if(rsc == NULL || rsc->m_pRequestRec == NULL || rsc->m_pResponseBuffer == NULL)
+		return APR_SUCCESS;
+
+	IHttpContext *pHttpContext = rsc->m_pHttpContext;
+	IHttpResponse *pHttpResponse = pHttpContext->GetResponse();
+	HTTP_RESPONSE *pRawHttpResponse = pHttpResponse->GetRawHttpResponse();
+	HTTP_DATA_CHUNK *pDataChunk = (HTTP_DATA_CHUNK *)apr_palloc(rsc->m_pRequestRec->pool, sizeof(HTTP_DATA_CHUNK));
+
+	pRawHttpResponse->EntityChunkCount = 0;
+
+	// since we clean the APR pool at the end of OnSendRequest, we must get IIS-managed memory chunk
+	//
+	void *reqbuf = pHttpContext->AllocateRequestMemory(length);
+
+	memcpy(reqbuf, buf, length);
+
+	pDataChunk->DataChunkType = HttpDataChunkFromMemory;
+	pDataChunk->FromMemory.pBuffer = reqbuf;
+	pDataChunk->FromMemory.BufferLength = length;
 
-    server_rec* s = modsecInit();
-    DWORD size = MAX_COMPUTERNAME_LENGTH + 1;
-    char* compname = static_cast<char *>(malloc(size));
-    if (compname == nullptr)
+    CHAR szLength[21]; //Max length for a 64 bit int is 20
+
+    ZeroMemory(szLength, sizeof(szLength));
+
+    HRESULT hr = StringCchPrintfA(
+            szLength, 
+            sizeof(szLength) / sizeof(CHAR) - 1, "%d", 
+            length);
+
+    if(FAILED(hr))
     {
-        throw std::bad_alloc();
+		// not possible
     }
-    GetComputerName(compname, &size);
-    s->server_hostname = compname;
 
-    modsecStartConfig();
-    modsecFinalizeConfig();
-    modsecInitProcess();
+    hr = pHttpResponse->SetHeader(
+            HttpHeaderContentLength, 
+            szLength, 
+            (USHORT)strlen(szLength),
+            TRUE);
+
+    if(FAILED(hr))
+    {
+		// possible, but there's nothing we can do
+    }
+
+	pHttpResponse->WriteEntityChunkByReference(pDataChunk);
+
+	return APR_SUCCESS;
+}
+
+
+CMyHttpModule::CMyHttpModule()
+{
+    // Open a handle to the Event Viewer.
+    m_hEventLog = RegisterEventSource( NULL, "ModSecurity" );
+
+    SYSTEM_INFO         sysInfo;
+
+    GetSystemInfo(&sysInfo);
+    m_dwPageSize = sysInfo.dwPageSize;
+
+    this->status_call_already_sent = false;
+
+	InitializeCriticalSection(&m_csLock);
+
+	modsecSetLogHook(this, Log);
+
+	modsecSetReadBody(ReadBodyCallback);
+	modsecSetReadResponse(ReadResponseCallback);
+	modsecSetWriteBody(WriteBodyCallback);
+	modsecSetWriteResponse(WriteResponseCallback);
+
+	server_rec *s = modsecInit();
+	char *compname = (char *)malloc(128);
+	DWORD size = 128;
+
+	GetComputerName(compname, &size);
+
+	s->server_hostname = compname;
+
+	modsecStartConfig();
+
+	modsecFinalizeConfig();
+
+	modsecInitProcess();
+}
+
+CMyHttpModule::~CMyHttpModule()
+{
+	// ModSecurity registers APR pool cleanups, which interfere with APR pool tear down process
+	// this causes crashes and since we are exiting the process here, so this is a temporary solution
+	//
+	//modsecTerminate();
+
+	//WriteEventViewerLog("Module deleted.");
+
+	// Test whether the handle for the Event Viewer is open.
+    if (NULL != m_hEventLog)
+    {
+        // Close the handle to the Event Viewer.
+        DeregisterEventSource( m_hEventLog );
+        m_hEventLog = NULL;
+
+		DeleteCriticalSection(&m_csLock);
+    }
 }
 
 void CMyHttpModule::Dispose()
@@ -711,5 +1338,14 @@ void CMyHttpModule::Dispose()
 
 BOOL CMyHttpModule::WriteEventViewerLog(LPCSTR szNotification, WORD category)
 {
-    return logger.Log(szNotification, category);
+    // Test whether the handle for the Event Viewer is open.
+    if (NULL != m_hEventLog)
+    {
+        // Write any strings to the Event Viewer and return.
+        return ReportEvent(
+            m_hEventLog,
+            category, 0, 0x1,
+            NULL, 1, 0, &szNotification, NULL );
+    }
+    return FALSE;
 }
diff --git a/iis/mymodule.def b/iis/mymodule.def
index 2bd6d14cdb..cb37d10b0a 100644
--- a/iis/mymodule.def
+++ b/iis/mymodule.def
@@ -1,4 +1,4 @@
-LIBRARY    "ModSecurityIIS"
+LIBRARY	"ModSecurityIIS"
 
 EXPORTS
     RegisterModule
diff --git a/iis/mymodule.h b/iis/mymodule.h
index 8b339b3796..eb7a4b0163 100644
--- a/iis/mymodule.h
+++ b/iis/mymodule.h
@@ -12,32 +12,47 @@
 * directly using the email address security@modsecurity.org.
 */
 
-#pragma once
-
-#include "critical_section.h"
-#include "event_logger.h"
+#ifndef __MY_MODULE_H__
+#define __MY_MODULE_H__
 
 //  The module implementation.
 //  This class is responsible for implementing the 
 //  module functionality for each of the server events
 //  that it registers for.
-class CMyHttpModule 
-    : public CHttpModule
+class CMyHttpModule : public CHttpModule
 {
 public:
-    CMyHttpModule();
+    HANDLE				m_hEventLog;
+    DWORD				m_dwPageSize;
+	CRITICAL_SECTION	m_csLock;
 
     REQUEST_NOTIFICATION_STATUS
-    OnBeginRequest(IHttpContext*, IHttpEventProvider*) override;
+    OnBeginRequest(
+        IN IHttpContext * pHttpContext,
+        IN IHttpEventProvider * pProvider
+    );
 
-    void Dispose() override;
+    REQUEST_NOTIFICATION_STATUS
+    OnSendResponse(
+    IN IHttpContext * pHttpContext,
+        IN ISendResponseProvider * pProvider
+    );
 
-    BOOL WriteEventViewerLog(LPCSTR szNotification, WORD category = EVENTLOG_INFORMATION_TYPE);
+    REQUEST_NOTIFICATION_STATUS
+    OnPostEndRequest(
+    IN IHttpContext * pHttpContext,
+    IN IHttpEventProvider * pProvider
+    );
 
-private:
-    CriticalSection cs;
-    EventLogger logger;
-    DWORD pageSize = 0;
-    bool statusCallAlreadySent = false;
+    HRESULT ReadFileChunk(HTTP_DATA_CHUNK *chunk, char *buf);
+
+    CMyHttpModule();
+    ~CMyHttpModule();
+
+    void Dispose();
+
+    BOOL WriteEventViewerLog(LPCSTR szNotification, WORD category = EVENTLOG_INFORMATION_TYPE);
+    BOOL status_call_already_sent;
 };
 
+#endif
diff --git a/iis/mymodulefactory.h b/iis/mymodulefactory.h
index d8c63528e1..2e5a28f3aa 100644
--- a/iis/mymodulefactory.h
+++ b/iis/mymodulefactory.h
@@ -12,55 +12,75 @@
 * directly using the email address security@modsecurity.org.
 */
 
-#pragma once
-
-#include <memory>
-#include <mutex>
+#ifndef __MODULE_FACTORY_H__
+#define __MODULE_FACTORY_H__
 
 // Factory class for CMyHttpModule.
 // This class is responsible for creating instances
 // of CMyHttpModule for each request.
 class CMyHttpModuleFactory : public IHttpModuleFactory
 {
+        CMyHttpModule *				m_pModule;
+		CRITICAL_SECTION			m_csLock;
+
 public:
-    CMyHttpModuleFactory() /* noexcept */ = default;
+	CMyHttpModuleFactory()
+	{
+		m_pModule = NULL;
 
-    HRESULT GetHttpModule(CHttpModule** ppModule, IModuleAllocator*) override
+		InitializeCriticalSection(&m_csLock);
+	}
+
+	virtual
+    HRESULT
+    GetHttpModule(
+        OUT CHttpModule            **ppModule, 
+        IN IModuleAllocator        *
+    )
     {
-        if (ppModule == nullptr)
-        {
-            return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
-        }
+        HRESULT                    hr = S_OK;
 
-        try
-        {
-            // In the unlikely case if the module allocation fails,
-            // the init_flag will not be set and the next time another
-            // attempt will be made to initialize the module.
-            std::call_once(init_flag, [this] {
-                this->module = std::make_unique<CMyHttpModule>();
-            });
-        }
-        catch (const std::bad_alloc&) 
+	    if ( ppModule == NULL )
         {
-            return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
+            hr = HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
+            goto Finished;
         }
 
-        *ppModule = module.get();
-        return S_OK;
+		EnterCriticalSection(&m_csLock);
+
+		if(m_pModule == NULL)
+		{
+			m_pModule = new CMyHttpModule();
+
+			if ( m_pModule == NULL )
+			{
+				hr = HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
+				goto Finished;
+			}
+		}
+
+		LeaveCriticalSection(&m_csLock);
+
+        *ppModule = m_pModule;
+
+	Finished:
+
+        return hr;
     }
 
-    void Terminate() override
+    virtual 
+    void
+    Terminate()
     {
-        if (module)
+        if ( m_pModule != NULL )
         {
-            module.reset();
+			//m_pModule->WriteEventViewerLog("Module terminated.");
+            delete m_pModule;
+            m_pModule = NULL;
         }
 
         delete this;
     }
+};
 
-private:
-    std::unique_ptr<CMyHttpModule> module;
-    std::once_flag init_flag;
-};
\ No newline at end of file
+#endif
diff --git a/mlogc/mlogc.c b/mlogc/mlogc.c
index 400f6ec51a..e650452dc4 100644
--- a/mlogc/mlogc.c
+++ b/mlogc/mlogc.c
@@ -815,20 +815,20 @@ static void init_configuration(void)
     /* TLS Protocol - TLSv1(0) TLSv1.1(1) TLSv1.2(2) (SSLv3 not supported) */
     s = apr_table_get(conf, "TLSProtocol");
     if (s != NULL) {
-        int num = atoi(s);
-        switch (num) {
-        case 0:
-            tlsprotocol = 0;
-            break;
-        case 1:
-            tlsprotocol = 1;
-            break;
-        case 2:
-            tlsprotocol = 2;
-            break;
-        default:
-            tlsprotocol = 2; /* Default is TLSv1.2 */
-        }
+    	int num = atoi(s);
+    	switch (num) {
+    	case 0:
+    		tlsprotocol = 0;
+    		break;
+    	case 1:
+    		tlsprotocol = 1;
+    		break;
+    	case 2:
+    		tlsprotocol = 2;
+    		break;
+    	default:
+    		tlsprotocol = 2; /* Default is TLSv1.2 */
+    	}
     }
     curlversion = curl_version_info(CURLVERSION_NOW);
 
@@ -1278,24 +1278,24 @@ static void logc_init(void)
          */
         switch (tlsprotocol) {
         case 0:
-            curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_0);
-            break;
+        	curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_0);
+        	break;
         case 1:
-            curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_1);
-            break;
+        	curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_1);
+        	break;
         case 2:
-            curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2);
-            break;
+        	curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2);
+        	break;
         default:
-            curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2);
-            break;
+        	curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2);
+        	break;
         }
         cmaj = curlversion->version_num >> 16;
         cmin = (curlversion->version_num & 0x00ff00) >> 8;
         cpat = (curlversion->version_num & 0x0000ff);
         /* If cURL version < v7.34.0, use TLS v1.x */
         if (cmaj <= 7 && cmin < 34) {
-            curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1);
+        	curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1);
         }
 
         curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 15);
@@ -1308,7 +1308,7 @@ static void logc_init(void)
     }
 
     if (cmaj <= 7 && cmin < 34) {
-        error_log(LOG_DEBUG2, NULL, "TLSv1.2 is unsupported in cURL %d.%d.%d",  cmaj, cmin, cpat);
+    	error_log(LOG_DEBUG2, NULL, "TLSv1.2 is unsupported in cURL %d.%d.%d",  cmaj, cmin, cpat);
     }
 
     logline_regex = pcre_compile(logline_pattern, PCRE_CASELESS,
@@ -2322,12 +2322,12 @@ int main(int argc, const char * const argv[]) {
     logc_pid = getpid();
     apr_pool_create(&pool, NULL);
     apr_pool_create(&recv_pool, NULL);
-    
+	
 #ifndef WIN32
     apr_setup_signal_thread();
 #else
-    apr_signal(SIGINT, handle_signals);
-    apr_signal(SIGTERM, handle_signals);
+	apr_signal(SIGINT, handle_signals);
+	apr_signal(SIGTERM, handle_signals);
 #endif /* WIN32 */
 
     if (argc < 2) {
diff --git a/standalone/api.c b/standalone/api.c
index 355fdc6d3d..389ffb5aba 100755
--- a/standalone/api.c
+++ b/standalone/api.c
@@ -270,43 +270,43 @@ directory_config *modsecGetDefaultConfig()  {
 const char *modsecProcessConfig(directory_config *config, const char *file, const char *dir)  {
     apr_pool_t *ptemp = NULL;
     const char *err;
-    apr_status_t status;
-    const char *rootpath, *incpath;
+	apr_status_t status;
+	const char *rootpath, *incpath;
 
-    if(dir == NULL || strlen(dir) == 0)
-#ifdef    WIN32
-        dir = "\\";
+	if(dir == NULL || strlen(dir) == 0)
+#ifdef	WIN32
+		dir = "\\";
 #else
-        dir = "/";
+		dir = "/";
 #endif
 
-    incpath = file;
+	incpath = file;
 
-    /* locate the start of the directories proper */
-    status = apr_filepath_root(&rootpath, &incpath, APR_FILEPATH_TRUENAME | APR_FILEPATH_NATIVE, config->mp);
+	/* locate the start of the directories proper */
+	status = apr_filepath_root(&rootpath, &incpath, APR_FILEPATH_TRUENAME | APR_FILEPATH_NATIVE, config->mp);
 
-    /* we allow APR_SUCCESS and APR_EINCOMPLETE */
-    if (APR_ERELATIVE == status) {
-        int li = strlen(dir) - 1;
+	/* we allow APR_SUCCESS and APR_EINCOMPLETE */
+	if (APR_ERELATIVE == status) {
+		int li = strlen(dir) - 1;
 
-        if(dir[li] != '/' && dir[li] != '\\')
-#ifdef    WIN32
-            file = apr_pstrcat(config->mp, dir, "\\", file, NULL);
+		if(dir[li] != '/' && dir[li] != '\\')
+#ifdef	WIN32
+			file = apr_pstrcat(config->mp, dir, "\\", file, NULL);
 #else
-            file = apr_pstrcat(config->mp, dir, "/", file, NULL);
+			file = apr_pstrcat(config->mp, dir, "/", file, NULL);
 #endif
-        else
-            file = apr_pstrcat(config->mp, dir, file, NULL);
-    }
-    else if (APR_EBADPATH == status) {
-        return apr_pstrcat(config->mp, "Config file has a bad path, ", file, NULL);
-    }
+		else
+			file = apr_pstrcat(config->mp, dir, file, NULL);
+	}
+	else if (APR_EBADPATH == status) {
+		return apr_pstrcat(config->mp, "Config file has a bad path, ", file, NULL);
+	}
 
-    apr_pool_create(&ptemp, config->mp);
+	apr_pool_create(&ptemp, config->mp);
 
     err = process_command_config(server, config, config->mp, ptemp, file);
 #ifdef MEMORY_DATABASE_ENABLE
-    config->root_config = config;
+	config->root_config = config;
 #endif
     apr_pool_destroy(ptemp);
 
@@ -471,9 +471,9 @@ int modsecProcessRequestBody(request_rec *r) {
 
     ap_remove_input_filter(f);
 
-    if (status != DECLINED) {
-        return status;
-    }
+	if (status != DECLINED) {
+		return status;
+	}
 
     hookfn_insert_filter(r);
 
diff --git a/standalone/api.h b/standalone/api.h
index bcad5230db..86e3c745a8 100644
--- a/standalone/api.h
+++ b/standalone/api.h
@@ -44,7 +44,7 @@
 #define inline __inline
 #endif
 
-#ifdef    __cplusplus
+#ifdef	__cplusplus
 extern "C"
 {
 #endif
diff --git a/standalone/buckets.c b/standalone/buckets.c
index 76a628162e..bf8d9d4959 100644
--- a/standalone/buckets.c
+++ b/standalone/buckets.c
@@ -50,7 +50,7 @@ AP_DECLARE(apr_status_t) ap_get_brigade(ap_filter_t *next,
                                                readbytes);
     }
 
-    return AP_NOBODY_READ;
+	return AP_NOBODY_READ;
 }
 
 AP_DECLARE(apr_status_t) ap_pass_brigade(ap_filter_t *next,
diff --git a/standalone/config.c b/standalone/config.c
index 6ffc6f8950..191123fb83 100644
--- a/standalone/config.c
+++ b/standalone/config.c
@@ -348,12 +348,12 @@ static int cfg_trim_line(char *buf)
 }
 
 AP_DECLARE(apr_status_t) ap_cfg_getline(char *buf, apr_size_t bufsize,
-        ap_configfile_t *cfp)
+		ap_configfile_t *cfp)
 {
-    apr_status_t rc = ap_cfg_getline_core(buf, bufsize, cfp);
-    if (rc == APR_SUCCESS)
-        cfg_trim_line(buf);
-    return rc;
+	apr_status_t rc = ap_cfg_getline_core(buf, bufsize, cfp);
+	if (rc == APR_SUCCESS)
+		cfg_trim_line(buf);
+	return rc;
 }
 #endif
 
@@ -765,7 +765,7 @@ int fnmatch_test(const char *pattern)
             if (*++pattern == '\0') {
                 return 0;
             }
-            break;*/        // this breaks on Windows
+            break;*/		// this breaks on Windows
 
         case '[':         /* '[' is only a glob if it has a matching ']' */
             ++nesting;
@@ -785,7 +785,7 @@ AP_DECLARE(const char *) process_resource_config(const char *fname,
                                                     apr_array_header_t *ari,
                                                     apr_pool_t *ptemp)
 {
-    *(char **)apr_array_push(ari) = (char *)fname;
+	*(char **)apr_array_push(ari) = (char *)fname;
 
     return NULL;
 }
@@ -794,7 +794,7 @@ static const char *process_resource_config_nofnmatch(const char *fname,
                                                      apr_array_header_t *ari,
                                                      apr_pool_t *p,
                                                      apr_pool_t *ptemp,
-                                                     unsigned depth,
+													 unsigned depth,
                                                      int optional)
 {
     const char *error;
@@ -882,10 +882,10 @@ static const char *process_resource_config_fnmatch(const char *path,
     /* find the first part of the filename */
     rest = ap_strchr_c(fname, '/');
 
-    if(rest == NULL)
-        rest = ap_strchr_c(fname, '\\');
+	if(rest == NULL)
+		rest = ap_strchr_c(fname, '\\');
 
-    if (rest) {
+	if (rest) {
         fname = apr_pstrndup(ptemp, fname, rest - fname);
         rest++;
     }
@@ -1007,198 +1007,198 @@ AP_DECLARE(const char *) process_fnmatch_configs(apr_array_header_t *ari,
 
 const char *populate_include_files(apr_pool_t *p, apr_pool_t *ptemp, apr_array_header_t *ari, const char *fname, int optional)
 {
-    return process_fnmatch_configs(ari, fname, p, ptemp, optional);
+	return process_fnmatch_configs(ari, fname, p, ptemp, optional);
 }
 
 const char *process_command_config(server_rec *s,
                                           void *mconfig,
                                           apr_pool_t *p,
                                           apr_pool_t *ptemp,
-                                          const char *filename)
+										  const char *filename)
 {
     const char *errmsg;
     char *l = apr_palloc (ptemp, MAX_STRING_LEN);
     const char *args = l;
     char *cmd_name, *w;
-    const command_rec *cmd;
-    apr_array_header_t *arr = apr_array_make(p, 1, sizeof(cmd_parms));
-    apr_array_header_t *ari = apr_array_make(p, 1, sizeof(char *));
+	const command_rec *cmd;
+	apr_array_header_t *arr = apr_array_make(p, 1, sizeof(cmd_parms));
+	apr_array_header_t *ari = apr_array_make(p, 1, sizeof(char *));
     cmd_parms *parms;
-    apr_status_t status;
-    ap_directive_t *newdir;
-    int optional;
-    char *err = NULL;
-    char *rootpath, *incpath;
-    int li;
-
-    errmsg = populate_include_files(p, ptemp, ari, filename, 0);
-
-    if(errmsg != NULL)
-        goto Exit;
-
-    while(ari->nelts != 0 || arr->nelts != 0)
-    {
-        if(ari->nelts > 0)
-        {
-            char *fn = *(char **)apr_array_pop(ari);
-
-            parms = (cmd_parms *)apr_array_push(arr);
-            *parms = default_parms;
-            parms->pool = p;
-            parms->temp_pool = ptemp;
-            parms->server = s;
-            parms->override = (RSRC_CONF | OR_ALL) & ~(OR_AUTHCFG | OR_LIMIT);
-            parms->override_opts = OPT_ALL | OPT_SYM_OWNER | OPT_MULTI;
-
-            status = ap_pcfg_openfile(&parms->config_file, p, fn);
-
-            if(status != APR_SUCCESS)
-            {
-                apr_array_pop(arr);
-                errmsg = apr_pstrcat(p, "Cannot open config file: ", fn, NULL);
-                goto Exit;
-            }
-        }
-
-        if (arr->nelts > 1024) {
+	apr_status_t status;
+	ap_directive_t *newdir;
+	int optional;
+	char *err = NULL;
+	char *rootpath, *incpath;
+	int li;
+
+	errmsg = populate_include_files(p, ptemp, ari, filename, 0);
+
+	if(errmsg != NULL)
+		goto Exit;
+
+	while(ari->nelts != 0 || arr->nelts != 0)
+	{
+		if(ari->nelts > 0)
+		{
+			char *fn = *(char **)apr_array_pop(ari);
+
+			parms = (cmd_parms *)apr_array_push(arr);
+			*parms = default_parms;
+			parms->pool = p;
+			parms->temp_pool = ptemp;
+			parms->server = s;
+			parms->override = (RSRC_CONF | OR_ALL) & ~(OR_AUTHCFG | OR_LIMIT);
+			parms->override_opts = OPT_ALL | OPT_SYM_OWNER | OPT_MULTI;
+
+			status = ap_pcfg_openfile(&parms->config_file, p, fn);
+
+			if(status != APR_SUCCESS)
+			{
+				apr_array_pop(arr);
+				errmsg = apr_pstrcat(p, "Cannot open config file: ", fn, NULL);
+				goto Exit;
+			}
+		}
+
+		if (arr->nelts > 1024) {
             errmsg = "Exceeded the maximum include directory nesting level. You have "
                                 "probably a recursion somewhere.";
-            goto Exit;
+			goto Exit;
         }
 
-        parms = (cmd_parms *)apr_array_pop(arr);
+		parms = (cmd_parms *)apr_array_pop(arr);
 
-        if(parms == NULL)
-            break;
+		if(parms == NULL)
+			break;
 
-        while (!(ap_cfg_getline(l, MAX_STRING_LEN, parms->config_file))) {
-            if (*l == '#' || *l == '\0')
-                continue;
+		while (!(ap_cfg_getline(l, MAX_STRING_LEN, parms->config_file))) {
+			if (*l == '#' || *l == '\0')
+				continue;
 
-            args = l;
+			args = l;
 
-            cmd_name = ap_getword_conf(p, &args);
+			cmd_name = ap_getword_conf(p, &args);
 
-            if (*cmd_name == '\0')
-                continue;
+			if (*cmd_name == '\0')
+				continue;
 
-            if (!strcasecmp(cmd_name, "IncludeOptional"))
-            {
-                optional = 1;
-                goto ProcessInclude;
-            }
+			if (!strcasecmp(cmd_name, "IncludeOptional"))
+			{
+				optional = 1;
+				goto ProcessInclude;
+			}
 
-            if (!strcasecmp(cmd_name, "Include"))
-            {
-                optional = 0;
+			if (!strcasecmp(cmd_name, "Include"))
+			{
+				optional = 0;
 ProcessInclude:
-                w = ap_getword_conf(parms->pool, &args);
+				w = ap_getword_conf(parms->pool, &args);
 
-                if (*w == '\0' || *args != 0)
-                {
-                    ap_cfg_closefile(parms->config_file);
-                    errmsg = apr_pstrcat(parms->pool, "Include takes one argument", NULL);
-                    goto Exit;
-                }
+				if (*w == '\0' || *args != 0)
+				{
+					ap_cfg_closefile(parms->config_file);
+					errmsg = apr_pstrcat(parms->pool, "Include takes one argument", NULL);
+					goto Exit;
+				}
 
-                incpath = w;
+				incpath = w;
 
-                /* locate the start of the directories proper */
-                status = apr_filepath_root((const char **)&rootpath, (const char **)&incpath, APR_FILEPATH_TRUENAME | APR_FILEPATH_NATIVE, ptemp);
+				/* locate the start of the directories proper */
+				status = apr_filepath_root((const char **)&rootpath, (const char **)&incpath, APR_FILEPATH_TRUENAME | APR_FILEPATH_NATIVE, ptemp);
 
-                /* we allow APR_SUCCESS and APR_EINCOMPLETE */
-                if (APR_ERELATIVE == status) {
-                    rootpath = apr_pstrdup(ptemp, parms->config_file->name);
-                    li = strlen(rootpath) - 1;
+				/* we allow APR_SUCCESS and APR_EINCOMPLETE */
+				if (APR_ERELATIVE == status) {
+					rootpath = apr_pstrdup(ptemp, parms->config_file->name);
+					li = strlen(rootpath) - 1;
 
-                    while(li >= 0 && rootpath[li] != '/' && rootpath[li] != '\\')
-                        rootpath[li--] = 0;
+					while(li >= 0 && rootpath[li] != '/' && rootpath[li] != '\\')
+						rootpath[li--] = 0;
 
-                    w = apr_pstrcat(p, rootpath, w, NULL);
-                }
-                else if (APR_EBADPATH == status) {
-                    ap_cfg_closefile(parms->config_file);
-                    errmsg = apr_pstrcat(p, "Include file has a bad path, ", w, NULL);
-                    goto Exit;
-                }
+					w = apr_pstrcat(p, rootpath, w, NULL);
+				}
+				else if (APR_EBADPATH == status) {
+					ap_cfg_closefile(parms->config_file);
+					errmsg = apr_pstrcat(p, "Include file has a bad path, ", w, NULL);
+					goto Exit;
+				}
 
-                errmsg = populate_include_files(p, ptemp, ari, w, optional);
+				errmsg = populate_include_files(p, ptemp, ari, w, optional);
 
-                *(cmd_parms *)apr_array_push(arr) = *parms;
+				*(cmd_parms *)apr_array_push(arr) = *parms;
 
-                if(errmsg != NULL)
-                    goto Exit;
+				if(errmsg != NULL)
+					goto Exit;
 
-                // we don't want to close the current file yet
-                //
-                parms = NULL;
-                break;
-            }
+				// we don't want to close the current file yet
+				//
+				parms = NULL;
+				break;
+			}
 
-            cmd = ap_find_command(cmd_name, security2_module.cmds);
+			cmd = ap_find_command(cmd_name, security2_module.cmds);
 
-            if(cmd == NULL)
-            {
-                // unknown command, should error
-                //
-                ap_cfg_closefile(parms->config_file);
-                errmsg = apr_pstrcat(p, "Unknown command in config: ", cmd_name, NULL);
-                goto Exit;
-            }
+			if(cmd == NULL)
+			{
+				// unknown command, should error
+				//
+				ap_cfg_closefile(parms->config_file);
+				errmsg = apr_pstrcat(p, "Unknown command in config: ", cmd_name, NULL);
+				goto Exit;
+			}
 
-            newdir = apr_pcalloc(p, sizeof(ap_directive_t));
-            newdir->filename = parms->config_file->name;
-            newdir->line_num = parms->config_file->line_number;
-            newdir->directive = cmd_name;
-            newdir->args = apr_pstrdup(p, args);
+			newdir = apr_pcalloc(p, sizeof(ap_directive_t));
+			newdir->filename = parms->config_file->name;
+			newdir->line_num = parms->config_file->line_number;
+			newdir->directive = cmd_name;
+			newdir->args = apr_pstrdup(p, args);
 
-            parms->directive = newdir;
+			parms->directive = newdir;
 
 #ifdef WIN32
-            // some config commands fail in APR when there are file
-            // permission issues or other OS-specific problems
-            //
-            __try
-            {
+			// some config commands fail in APR when there are file
+			// permission issues or other OS-specific problems
+			//
+			__try
+			{
 #endif
-                errmsg = invoke_cmd(cmd, parms, mconfig, args);
+				errmsg = invoke_cmd(cmd, parms, mconfig, args);
 #ifdef WIN32
-            }
-            __except(EXCEPTION_EXECUTE_HANDLER)
-            {
-                errmsg = "Command failed to execute (check file/folder permissions, syntax, etc.).";
-            }
+			}
+			__except(EXCEPTION_EXECUTE_HANDLER)
+			{
+				errmsg = "Command failed to execute (check file/folder permissions, syntax, etc.).";
+			}
 #endif
 
-            if(errmsg != NULL)
-                break;
-        }
+			if(errmsg != NULL)
+				break;
+		}
 
-        if(parms != NULL)
-            ap_cfg_closefile(parms->config_file);
+		if(parms != NULL)
+			ap_cfg_closefile(parms->config_file);
 
-        if(errmsg != NULL)
-            break;
-    }
+		if(errmsg != NULL)
+			break;
+	}
 
     if (errmsg) {
-        err = (char *)apr_palloc(p, 1024);
+		err = (char *)apr_palloc(p, 1024);
 
-        if(parms != NULL)
-            apr_snprintf(err, 1024, "Syntax error in config file %s, line %d: %s", parms->config_file->name,
-                            parms->config_file->line_number, errmsg);
-        else
-            apr_snprintf(err, 1024, "Syntax error in config file: %s", errmsg);
+		if(parms != NULL)
+			apr_snprintf(err, 1024, "Syntax error in config file %s, line %d: %s", parms->config_file->name,
+							parms->config_file->line_number, errmsg);
+		else
+			apr_snprintf(err, 1024, "Syntax error in config file: %s", errmsg);
     }
 
     errmsg = err;
 
 Exit:
-    while((parms = (cmd_parms *)apr_array_pop(arr)) != NULL)
-    {
-        ap_cfg_closefile(parms->config_file);
-    }
+	while((parms = (cmd_parms *)apr_array_pop(arr)) != NULL)
+	{
+		ap_cfg_closefile(parms->config_file);
+	}
 
-    return errmsg;
+	return errmsg;
 }
 
diff --git a/standalone/filters.c b/standalone/filters.c
index 9d113caa6d..c0c1564868 100644
--- a/standalone/filters.c
+++ b/standalone/filters.c
@@ -37,7 +37,7 @@
 #include "ap_config.h"
 #include "http_config.h"
 
-#define    FILTER_POOL    apr_hook_global_pool
+#define	FILTER_POOL	apr_hook_global_pool
 #include "apr_hooks.h"
 
 /*
@@ -56,11 +56,11 @@ apr_table_t *ms_output_filters = NULL;
 
 void init_filter_tables()
 {
-    if(ms_input_filters == NULL)
-    {
-        ms_input_filters = apr_table_make(FILTER_POOL, 10);
-        ms_output_filters = apr_table_make(FILTER_POOL, 10);
-    }
+	if(ms_input_filters == NULL)
+	{
+		ms_input_filters = apr_table_make(FILTER_POOL, 10);
+		ms_output_filters = apr_table_make(FILTER_POOL, 10);
+	}
 }
 
 AP_DECLARE(ap_filter_rec_t *) ap_register_input_filter(const char *name,
@@ -68,20 +68,20 @@ AP_DECLARE(ap_filter_rec_t *) ap_register_input_filter(const char *name,
                                           ap_init_filter_func filter_init,
                                           ap_filter_type ftype)
 {
-    ap_filter_rec_t *f;
+	ap_filter_rec_t *f;
 
-    init_filter_tables();
-    
-    f = apr_palloc(FILTER_POOL, sizeof(ap_filter_rec_t));
+	init_filter_tables();
+	
+	f = apr_palloc(FILTER_POOL, sizeof(ap_filter_rec_t));
 
-    f->filter_func.in_func = filter_func;
-    f->filter_init_func = filter_init;
-    f->ftype = ftype;
-    f->name = name;
+	f->filter_func.in_func = filter_func;
+	f->filter_init_func = filter_init;
+	f->ftype = ftype;
+	f->name = name;
 
-    apr_table_setn(ms_input_filters, name, (const char *)f);
+	apr_table_setn(ms_input_filters, name, (const char *)f);
 
-    return f;
+	return f;
 }
 
 AP_DECLARE(ap_filter_rec_t *) ap_register_output_filter(const char *name,
@@ -89,20 +89,20 @@ AP_DECLARE(ap_filter_rec_t *) ap_register_output_filter(const char *name,
                                             ap_init_filter_func filter_init,
                                             ap_filter_type ftype)
 {
-    ap_filter_rec_t *f;
-    
-    init_filter_tables();
-    
-    f = apr_palloc(FILTER_POOL, sizeof(ap_filter_rec_t));
+	ap_filter_rec_t *f;
+	
+	init_filter_tables();
+	
+	f = apr_palloc(FILTER_POOL, sizeof(ap_filter_rec_t));
 
-    f->filter_func.out_func = filter_func;
-    f->filter_init_func = filter_init;
-    f->ftype = ftype;
-    f->name = name;
+	f->filter_func.out_func = filter_func;
+	f->filter_init_func = filter_init;
+	f->ftype = ftype;
+	f->name = name;
 
-    apr_table_setn(ms_output_filters, name, (const char *)f);
+	apr_table_setn(ms_output_filters, name, (const char *)f);
 
-    return f;
+	return f;
 }
 
 static ap_filter_t *add_any_filter_handle(ap_filter_rec_t *frec, void *ctx,
@@ -187,12 +187,12 @@ static ap_filter_t *add_any_filter_handle(ap_filter_rec_t *frec, void *ctx,
 AP_DECLARE(ap_filter_t *) ap_add_input_filter(const char *name, void *ctx,
                                               request_rec *r, conn_rec *c)
 {
-    ap_filter_rec_t *f = (ap_filter_rec_t *)apr_table_get(ms_input_filters, name);
+	ap_filter_rec_t *f = (ap_filter_rec_t *)apr_table_get(ms_input_filters, name);
 
-    if(f == NULL)
-        return NULL;
+	if(f == NULL)
+		return NULL;
 
-    return add_any_filter_handle(f, ctx, r, c,
+	return add_any_filter_handle(f, ctx, r, c,
                           r ? &r->input_filters : NULL,
                           r ? &r->proto_input_filters : NULL, &c->input_filters);
 }
@@ -200,10 +200,10 @@ AP_DECLARE(ap_filter_t *) ap_add_input_filter(const char *name, void *ctx,
 AP_DECLARE(ap_filter_t *) ap_add_output_filter(const char *name, void *ctx, 
                                                request_rec *r, conn_rec *c)
 {
-    ap_filter_rec_t *f = (ap_filter_rec_t *)apr_table_get(ms_output_filters, name);
+	ap_filter_rec_t *f = (ap_filter_rec_t *)apr_table_get(ms_output_filters, name);
 
-    if(f == NULL)
-        return NULL;
+	if(f == NULL)
+		return NULL;
 
     return add_any_filter_handle(f, ctx, r, c,
                           r ? &r->output_filters : NULL,
diff --git a/standalone/hooks.c b/standalone/hooks.c
index 0cc8e4c73c..dae77b81bf 100755
--- a/standalone/hooks.c
+++ b/standalone/hooks.c
@@ -44,11 +44,11 @@ link##_DECLARE(void) ns##_hook_##name(ns##_HOOK_##name##_t *pf, \
                                       const char * const *aszPre, \
                                       const char * const *aszSucc, int nOrder) \
 { \
-    hookfn_##name = pf; \
+	hookfn_##name = pf; \
 }
 
 #define DECLARE_HOOK(ret,name,args) \
-    DECLARE_EXTERNAL_HOOK(ap,AP,ret,name,args)
+	DECLARE_EXTERNAL_HOOK(ap,AP,ret,name,args)
 
 
 DECLARE_HOOK(int,pre_config,(apr_pool_t *pconf,apr_pool_t *plog, apr_pool_t *ptemp))
diff --git a/standalone/server.c b/standalone/server.c
index ae1a16fc7a..31b12a6dbc 100644
--- a/standalone/server.c
+++ b/standalone/server.c
@@ -250,17 +250,17 @@ AP_DECLARE(char *) ap_escape_html(apr_pool_t *p, const char *s)
 
 AP_DECLARE(const char *) ap_psignature(const char *prefix, request_rec *r)
 {
-    return prefix;
+	return prefix;
 }
 
 AP_DECLARE(const char *) ap_document_root(request_rec *r) /* Don't use this! */
 {
-    return "\\";
+	return "\\";
 }
 
 AP_DECLARE(apr_port_t) ap_get_server_port(const request_rec *r)
 {
-    return 80;
+	return 80;
 }
 
 /////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -269,7 +269,7 @@ AP_DECLARE(apr_port_t) ap_get_server_port(const request_rec *r)
 AP_DECLARE(void) ap_log_error(const char *file, int line, int level, 
                              apr_status_t status, const server_rec *s, 
                              const char *fmt, ...)
-//                __attribute__((format(printf,6,7)))
+//			    __attribute__((format(printf,6,7)))
 #else
 AP_DECLARE(void) ap_log_error_(const char *file, int line, int module_index,
                                int level, apr_status_t status,
@@ -284,10 +284,10 @@ AP_DECLARE(void) ap_log_error_(const char *file, int line, int module_index,
 
     apr_vsnprintf(errstr, MAX_STRING_LEN, fmt, args);
 
-    va_end(args);
+	va_end(args);
 
-    if(modsecLogHook != NULL)
-        modsecLogHook(modsecLogObj, level, errstr);
+	if(modsecLogHook != NULL)
+		modsecLogHook(modsecLogObj, level, errstr);
 }
 
 
@@ -295,7 +295,7 @@ AP_DECLARE(void) ap_log_error_(const char *file, int line, int module_index,
 AP_DECLARE(void) ap_log_cerror(const char *file, int line, int level,
                              apr_status_t status, const conn_rec *r,
                              const char *fmt, ...)
-//                __attribute__((format(printf,6,7)))
+//			    __attribute__((format(printf,6,7)))
 #else
 AP_DECLARE(void) ap_log_cerror_(const char *file, int line, int module_index,
                                 int level, apr_status_t status,
@@ -310,10 +310,10 @@ AP_DECLARE(void) ap_log_cerror_(const char *file, int line, int module_index,
 
     apr_vsnprintf(errstr, MAX_STRING_LEN, fmt, args);
 
-    va_end(args);
+	va_end(args);
 
-    if(modsecLogHook != NULL)
-        modsecLogHook(modsecLogObj, level, errstr);
+	if(modsecLogHook != NULL)
+		modsecLogHook(modsecLogObj, level, errstr);
 }
 
 
@@ -321,7 +321,7 @@ AP_DECLARE(void) ap_log_cerror_(const char *file, int line, int module_index,
 AP_DECLARE(void) ap_log_rerror(const char *file, int line, int level,
                              apr_status_t status, const request_rec *r,
                              const char *fmt, ...)
-//                __attribute__((format(printf,6,7)))
+//			    __attribute__((format(printf,6,7)))
 #else
 AP_DECLARE(void) ap_log_rerror_(const char *file, int line, int module_index,
                                int level, apr_status_t status,
@@ -336,17 +336,17 @@ AP_DECLARE(void) ap_log_rerror_(const char *file, int line, int module_index,
 
     apr_vsnprintf(errstr, MAX_STRING_LEN, fmt, args);
 
-    va_end(args);
+	va_end(args);
 
-    if(modsecLogHook != NULL)
-        modsecLogHook(modsecLogObj, level, errstr);
+	if(modsecLogHook != NULL)
+		modsecLogHook(modsecLogObj, level, errstr);
 }
 
 #if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER < 3
 AP_DECLARE(void) ap_log_perror(const char *file, int line, int level, 
                              apr_status_t status, apr_pool_t *p, 
                              const char *fmt, ...)
-//                __attribute__((format(printf,6,7)))
+//			    __attribute__((format(printf,6,7)))
 #else
 AP_DECLARE(void) ap_log_perror_(const char *file, int line, int module_index,
                                 int level, apr_status_t status, apr_pool_t *p,
@@ -360,28 +360,28 @@ AP_DECLARE(void) ap_log_perror_(const char *file, int line, int module_index,
 
     apr_vsnprintf(errstr, MAX_STRING_LEN, fmt, args);
 
-    va_end(args);
+	va_end(args);
 
-    if(modsecLogHook != NULL)
-        modsecLogHook(modsecLogObj, level, errstr);
+	if(modsecLogHook != NULL)
+		modsecLogHook(modsecLogObj, level, errstr);
 }
 
 AP_DECLARE(module *) ap_find_linked_module(const char *name)
 {
-    // only used for ACTION_PROXY to find mod_proxy.c; see mod_security2.c, perform_interception()
-    //
-    return NULL;
+	// only used for ACTION_PROXY to find mod_proxy.c; see mod_security2.c, perform_interception()
+	//
+	return NULL;
 }
 
 AP_DECLARE(const char *) ap_get_server_name(request_rec *r)
 {
-    return r->server->server_hostname;
+	return r->server->server_hostname;
 }
 
 AP_DECLARE(void) ap_add_version_component(apr_pool_t *pconf, const char *component)
 {
-    // appends string to server description string
-    //
+	// appends string to server description string
+	//
 }
 
 AP_DECLARE(const char *) ap_get_status_line(int status)
@@ -467,7 +467,7 @@ AP_DECLARE(apr_status_t) ap_mpm_query(int query_code, int *result)
 
 AP_DECLARE(const char *) ap_get_server_banner(void)
 {
-    return "ModSecurity Standalone";
+	return "ModSecurity Standalone";
 }
 
 /* Code from Harald Hanche-Olsen <hanche@imf.unit.no> */
@@ -493,7 +493,7 @@ static APR_INLINE void do_double_reverse (conn_rec *conn)
 #if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER < 3
             if (apr_sockaddr_equal(sa, conn->remote_addr)) {
 #else
-        if (apr_sockaddr_equal(sa, conn->client_addr)) {
+	    if (apr_sockaddr_equal(sa, conn->client_addr)) {
 #endif
                 conn->double_reverse = 1;
                 return;
@@ -507,10 +507,10 @@ static APR_INLINE void do_double_reverse (conn_rec *conn)
 }
 
 #ifndef HOSTNAME_LOOKUP_OFF
-#define HOSTNAME_LOOKUP_OFF    0
-#define HOSTNAME_LOOKUP_ON    1
-#define HOSTNAME_LOOKUP_DOUBLE    2
-#define HOSTNAME_LOOKUP_UNSET    3
+#define HOSTNAME_LOOKUP_OFF	0
+#define HOSTNAME_LOOKUP_ON	1
+#define HOSTNAME_LOOKUP_DOUBLE	2
+#define HOSTNAME_LOOKUP_UNSET	3
 #endif
 
 AP_DECLARE(void) ap_str_tolower(char *str)
@@ -593,7 +593,7 @@ AP_DECLARE(const char *) ap_get_remote_host(conn_rec *conn, void *dir_config, in
 #if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER < 3
             return conn->remote_ip;
 #else
-        return conn->client_ip;
+	    return conn->client_ip;
 #endif
         }
     }
@@ -617,7 +617,7 @@ AP_DECLARE(char *) ap_server_root_relative(apr_pool_t *p, const char *file)
 
 AP_DECLARE(piped_log *) ap_open_piped_log(apr_pool_t *p, const char *program)
 {
-    return NULL;
+	return NULL;
 }
 
 #if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER > 3

From d61d8bfdb61983323a46e6d0312723a833fcf052 Mon Sep 17 00:00:00 2001
From: Vladimir Krivopalov <vlkrivop@microsoft.com>
Date: Tue, 27 Aug 2019 15:41:42 -0700
Subject: [PATCH 55/58] Add WAF policy context info directives to
 configuration.

Signed-off-by: Vladimir Krivopalov <vlkrivop@microsoft.com>
---
 apache2/apache2_config.c | 115 +++++++++++++++++++++++++++++++++++++++
 apache2/modsecurity.h    |   5 ++
 2 files changed, 120 insertions(+)

diff --git a/apache2/apache2_config.c b/apache2/apache2_config.c
index a105b1cef6..28323d91ba 100755
--- a/apache2/apache2_config.c
+++ b/apache2/apache2_config.c
@@ -125,6 +125,11 @@ void *create_directory_config(apr_pool_t *mp, char *path)
     dcfg->stream_inbody_inspection = NOT_SET;
     dcfg->stream_outbody_inspection = NOT_SET;
 
+    /* WAF policy identification information */
+    dcfg->waf_policy_id = NOT_SET_P;
+    dcfg->waf_policy_scope = NOT_SET_P;
+    dcfg->waf_policy_scope_name = NOT_SET_P;
+
     /* Geo Lookups */
     dcfg->geo = NOT_SET_P;
 
@@ -568,6 +573,14 @@ void *merge_directory_configs(apr_pool_t *mp, void *_parent, void *_child)
     merged->stream_outbody_inspection = (child->stream_outbody_inspection == NOT_SET
         ? parent->stream_outbody_inspection : child->stream_outbody_inspection);
 
+    /* WAF policy identification information */
+    merged->waf_policy_id = (child->waf_policy_id == NOT_SET_P
+        ? parent->waf_policy_id : child->waf_policy_id);
+    merged->waf_policy_scope = (child->waf_policy_scope == NOT_SET_P
+        ? parent->waf_policy_scope : child->waf_policy_scope);
+    merged->waf_policy_scope_name = (child->waf_policy_scope_name == NOT_SET_P
+        ? parent->waf_policy_scope_name : child->waf_policy_scope_name);
+
     /* Geo Lookup */
     merged->geo = (child->geo == NOT_SET_P
         ? parent->geo : child->geo);
@@ -730,6 +743,11 @@ void init_directory_config(directory_config *dcfg)
     if (dcfg->stream_inbody_inspection == NOT_SET) dcfg->stream_inbody_inspection = 0;
     if (dcfg->stream_outbody_inspection == NOT_SET) dcfg->stream_outbody_inspection = 0;
 
+    /* WAF policy identification information */
+    if (dcfg->waf_policy_id == NOT_SET_P) dcfg->waf_policy_id = "";
+    if (dcfg->waf_policy_scope == NOT_SET_P) dcfg->waf_policy_scope = "";
+    if (dcfg->waf_policy_scope_name == NOT_SET_P) dcfg->waf_policy_scope_name = "";
+
     /* Geo Lookup */
     if (dcfg->geo == NOT_SET_P) dcfg->geo = NULL;
 
@@ -1788,6 +1806,79 @@ static const char *cmd_stream_outbody_inspection(cmd_parms *cmd, void *_dcfg, in
     dcfg->stream_outbody_inspection = flag;
     return NULL;
 }
+
+/**
+* \brief Add SecWafPolicyId configuration option
+*
+* \param cmd Pointer to configuration data
+* \param _dcfg Pointer to directory configuration
+* \param p1 Pointer to configuration option
+*
+* \retval NULL On Success
+* \retval apr_psprintf On Failue
+*/
+static const char *cmd_waf_policy_id(cmd_parms *cmd, void *_dcfg, const char *p1)
+{
+    directory_config *dcfg = (directory_config *)_dcfg;
+    if (dcfg == NULL) {
+        return NULL;
+    }
+    if (p1 == NULL) {
+        return apr_psprintf(cmd->pool, "ModSecurity: No valid SecWafPolicyId specified.");
+    }
+
+    dcfg->waf_policy_id = p1;
+    return NULL;
+}
+
+/**
+* \brief Add SecWafPolicyScope configuration option
+*
+* \param cmd Pointer to configuration data
+* \param _dcfg Pointer to directory configuration
+* \param p1 Pointer to configuration option
+*
+* \retval NULL On Success
+* \retval apr_psprintf On Failue
+*/
+static const char *cmd_waf_policy_scope(cmd_parms *cmd, void *_dcfg, const char *p1)
+{
+    directory_config *dcfg = (directory_config *)_dcfg;
+    if (dcfg == NULL) {
+        return NULL;
+    }
+    if (p1 == NULL) {
+        return apr_psprintf(cmd->pool, "ModSecurity: No valid SecWafPolicyScope specified.");
+    }
+
+    dcfg->waf_policy_scope = p1;
+    return NULL;
+}
+
+/**
+* \brief Add SecWafPolicyScopeName configuration option
+*
+* \param cmd Pointer to configuration data
+* \param _dcfg Pointer to directory configuration
+* \param p1 Pointer to configuration option
+*
+* \retval NULL On Success
+* \retval apr_psprintf On Failue
+*/
+static const char *cmd_waf_policy_scope_name(cmd_parms *cmd, void *_dcfg, const char *p1)
+{
+    directory_config *dcfg = (directory_config *)_dcfg;
+    if (dcfg == NULL) {
+        return NULL;
+    }
+    if (p1 == NULL) {
+        return apr_psprintf(cmd->pool, "ModSecurity: No valid SecWafPolicyScopeName specified.");
+    }
+
+    dcfg->waf_policy_scope_name = p1;
+    return NULL;
+}
+
 /**
 * \brief Add SecRulePerfTime configuration option
 *
@@ -3448,6 +3539,30 @@ const command_rec module_directives[] = {
         "On or Off"
     ),
 
+    AP_INIT_TAKE1 (
+        "SecWafPolicyId",
+        cmd_waf_policy_id,
+        NULL,
+        CMD_SCOPE_ANY,
+        "WAF policy identifier"
+    ),
+
+    AP_INIT_TAKE1 (
+        "SecWafPolicyScope",
+        cmd_waf_policy_scope,
+        NULL,
+        CMD_SCOPE_ANY,
+        "WAF policy application scope"
+    ),
+
+    AP_INIT_TAKE1 (
+        "SecWafPolicyScopeName",
+        cmd_waf_policy_scope_name,
+        NULL,
+        CMD_SCOPE_ANY,
+        "name of the scope the WAF policy is assigned to"
+    ),
+
     AP_INIT_FLAG (
         "SecStreamInBodyInspection",
         cmd_stream_inbody_inspection,
diff --git a/apache2/modsecurity.h b/apache2/modsecurity.h
index cdd707300a..83c213f430 100755
--- a/apache2/modsecurity.h
+++ b/apache2/modsecurity.h
@@ -615,6 +615,11 @@ struct directory_config {
     int                 stream_inbody_inspection;
     int                 stream_outbody_inspection;
 
+    /* WAF policy identification information */
+    const char          *waf_policy_id;
+    const char          *waf_policy_scope;
+    const char          *waf_policy_scope_name;
+
     /* Geo Lookup */
     geo_db              *geo;
 

From 9ff15de3f6fab5fc8ec43a0f2fc02e56fe8c44f1 Mon Sep 17 00:00:00 2001
From: Vladimir Krivopalov <vlkrivop@microsoft.com>
Date: Tue, 27 Aug 2019 17:44:57 -0700
Subject: [PATCH 56/58] Log WAF policy context for ModSecurity messages.

Signed-off-by: Vladimir Krivopalov <vlkrivop@microsoft.com>
---
 apache2/apache2_util.c              |  6 +++---
 apache2/waf_logging/waf_log_util.cc | 18 +++++++++++++-----
 apache2/waf_logging/waf_log_util.h  |  3 ++-
 3 files changed, 18 insertions(+), 9 deletions(-)

diff --git a/apache2/apache2_util.c b/apache2/apache2_util.c
index cabc64b3ea..fd738d3570 100755
--- a/apache2/apache2_util.c
+++ b/apache2/apache2_util.c
@@ -318,7 +318,7 @@ static int write_file_with_lock(struct waf_lock* lock, apr_file_t* fd, char* str
 /**
  * send all waf fields in json format to a file.
  */
-static void send_waf_log(struct waf_lock* lock, apr_file_t* fd, const char* str1, const char* ip_port, const char* uri, int mode, const char* hostname, char* unique_id, request_rec *r) {
+static void send_waf_log(struct waf_lock* lock, apr_file_t* fd, const char* str1, const char* ip_port, const char* uri, int mode, const char* hostname, char* unique_id, request_rec *r, const char* waf_policy_id, const char* waf_policy_scope, const char* waf_policy_scope_name) {
     char waf_filename[1024] = "";
     char waf_line[1024] = "";
     char waf_id[1024] = "";
@@ -344,7 +344,7 @@ static void send_waf_log(struct waf_lock* lock, apr_file_t* fd, const char* str1
     get_short_filename(waf_filename);
     get_ruleset_type_version(waf_ruleset_info, waf_ruleset_type, waf_ruleset_version); 
 
-    char* json_str = generate_json(msc_waf_resourceId, WAF_LOG_UTIL_OPERATION_NAME, WAF_LOG_UTIL_CATEGORY, msc_waf_instanceId, waf_ip, waf_port, uri, waf_ruleset_type, waf_ruleset_version, waf_id, waf_message, mode, 0, waf_detail_message, waf_data, waf_filename, waf_line, hostname, waf_unique_id);
+    char* json_str = generate_json(msc_waf_resourceId, WAF_LOG_UTIL_OPERATION_NAME, WAF_LOG_UTIL_CATEGORY, msc_waf_instanceId, waf_ip, waf_port, uri, waf_ruleset_type, waf_ruleset_version, waf_id, waf_message, mode, 0, waf_detail_message, waf_data, waf_filename, waf_line, hostname, waf_unique_id, waf_policy_id, waf_policy_scope, waf_policy_scope_name);
     if (!json_str) {
 #if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER > 2
        ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r,
@@ -478,7 +478,7 @@ static void internal_log_ex(request_rec *r, directory_config *dcfg, modsec_rec *
             msc_waf_log_reopened = 0;
         }
 
-        send_waf_log(msr->modsecurity->wafjsonlog_lock, msc_waf_log_fd, str1, r->useragent_ip ? r->useragent_ip : r->connection->client_ip, log_escape(msr->mp, r->uri), dcfg->is_enabled, r->hostname, unique_id, r);
+        send_waf_log(msr->modsecurity->wafjsonlog_lock, msc_waf_log_fd, str1, r->useragent_ip ? r->useragent_ip : r->connection->client_ip, log_escape(msr->mp, r->uri), dcfg->is_enabled, r->hostname, unique_id, r, dcfg->waf_policy_id, dcfg->waf_policy_scope, dcfg->waf_policy_scope_name);
 #endif
 
 #if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER > 2
diff --git a/apache2/waf_logging/waf_log_util.cc b/apache2/waf_logging/waf_log_util.cc
index 0b6a50bccb..2c8e83c02e 100755
--- a/apache2/waf_logging/waf_log_util.cc
+++ b/apache2/waf_logging/waf_log_util.cc
@@ -33,6 +33,9 @@ struct property
     detail details;
     jsoncons::string_view hostname;
     jsoncons::string_view transactionId;
+    jsoncons::string_view policyId;
+    jsoncons::string_view policyScope;
+    jsoncons::string_view policyScopeName;
 };
 
 struct waf_log
@@ -46,7 +49,7 @@ struct waf_log
 }   // namespace waf_logging
 
 JSONCONS_TYPE_TRAITS_DECL(waf_logging::detail, message, data, file, line);
-JSONCONS_TYPE_TRAITS_DECL(waf_logging::property, instanceId, clientIp, clientPort, requestUri, ruleSetType, ruleSetVersion, ruleId, message, action, site, details, hostname, transactionId);
+JSONCONS_TYPE_TRAITS_DECL(waf_logging::property, instanceId, clientIp, clientPort, requestUri, ruleSetType, ruleSetVersion, ruleId, message, action, site, details, hostname, transactionId, policyId, policyScope, policyScopeName);
 JSONCONS_TYPE_TRAITS_DECL(waf_logging::waf_log, resourceId, operationName, category, properties);
 
 static std::string to_json_string(const waf_logging::waf_log& log) {
@@ -125,7 +128,8 @@ static std::string get_json_log_message(const char* resource_id, const char* ope
         const char* instance_id, const char* client_ip, const char* client_port, const char* request_uri,
         const char* rule_set_type, const char* rule_set_version, const char* rule_id, const char* messages,
         const int action, const int site, const char* details_messages, const char* details_data,
-        const char* details_file, const char* details_line, const char* hostname, const char* waf_unique_id) {
+        const char* details_file, const char* details_line, const char* hostname, const char* waf_unique_id,
+        const char* waf_policy_id, const char* waf_policy_scope, const char* waf_policy_scope_name) {
 
     using str_view = jsoncons::string_view;
     const auto make_string_view_strip_quotes = [] (const char* str) -> str_view {
@@ -198,7 +202,10 @@ static std::string get_json_log_message(const char* resource_id, const char* ope
                     details_line_str
                 },
             hostname,
-            waf_unique_id_str
+            waf_unique_id_str,
+            waf_policy_id,
+            waf_policy_scope,
+            waf_policy_scope_name
         }
     });
 }
@@ -208,13 +215,14 @@ char* generate_json(const char* resource_id, const char* operation_name, const c
         const char* instance_id, const char* client_ip, const char* client_port, const char* request_uri,
         const char* rule_set_type, const char* rule_set_version, const char* rule_id, const char* messages,
         const int action, const int site, const char* details_messages, const char* details_data,
-        const char* details_file, const char* details_line, const char* hostname, const char* waf_unique_id) {
+        const char* details_file, const char* details_line, const char* hostname, const char* waf_unique_id,
+        const char* waf_policy_id, const char* waf_policy_scope, const char* waf_policy_scope_name) {
     
     try {
         const std::string json_string = get_json_log_message(resource_id, operation_name, category,
                 instance_id, client_ip, client_port, request_uri, rule_set_type, rule_set_version,
                 rule_id, messages, action, site, details_messages, details_data, details_file,
-                details_line, hostname, waf_unique_id);
+                details_line, hostname, waf_unique_id, waf_policy_id, waf_policy_scope, waf_policy_scope_name);
         char* result = static_cast<char*>(std::malloc(json_string.length() + 2)); // Two extra bytes for \n and \0
         std::copy(json_string.begin(), json_string.end(), result);
         result[json_string.length()] = '\n';
diff --git a/apache2/waf_logging/waf_log_util.h b/apache2/waf_logging/waf_log_util.h
index 9b137c4940..636a4f28a8 100755
--- a/apache2/waf_logging/waf_log_util.h
+++ b/apache2/waf_logging/waf_log_util.h
@@ -17,7 +17,8 @@
 #ifdef __cplusplus
 extern "C" {
 #endif
-char* generate_json(const char* resourceId, const char* operationName, const char* category, const char* instanceId, const char* clientIP, const char* clientPort, const char* requestUri, const char* ruleSetType, const char* ruleSetVersion, const char* ruleId, const char* messages, const int action, const int site, const char* details_messages, const char* details_data, const char* details_file, const char* details_line, const char* hostname, const char* waf_unique_id);
+char* generate_json(const char* resourceId, const char* operationName, const char* category, const char* instanceId, const char* clientIP, const char* clientPort, const char* requestUri, const char* ruleSetType, const char* ruleSetVersion, const char* ruleId, const char* messages, const int action, const int site, const char* details_messages, const char* details_data, const char* details_file, const char* details_line, const char* hostname, const char* waf_unique_id,
+const char* waf_policy_id, const char* waf_policy_scope, const char* waf_policy_scope_name);
 void free_json(char* str);
 // Returns 0 if succeeded, non-zero code otherwise
 int init_appgw_rules_id_hash();

From ac9aed7b4c833f7f6cf8830576115dfa01f96a35 Mon Sep 17 00:00:00 2001
From: Vladimir Krivopalov <vlkrivop@microsoft.com>
Date: Fri, 30 Aug 2019 09:53:38 -0700
Subject: [PATCH 57/58] Add comment explaining the deprecated status of 'site'
 property in logs

Signed-off-by: Vladimir Krivopalov <vlkrivop@microsoft.com>
---
 apache2/waf_logging/waf_log_util.cc | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/apache2/waf_logging/waf_log_util.cc b/apache2/waf_logging/waf_log_util.cc
index 2c8e83c02e..146303e261 100755
--- a/apache2/waf_logging/waf_log_util.cc
+++ b/apache2/waf_logging/waf_log_util.cc
@@ -173,6 +173,10 @@ static std::string get_json_log_message(const char* resource_id, const char* ope
         }
     }
 
+    /* For historical reasons, the "site" property is included in log messages.
+     * However, it does not carry any useful meaning.
+     * We keep it around for compatibility reasons but may consider removing it at some point in the future.
+     */
     const str_view site_str = (site == 0) ? "Global" : str_view{};
 
     const str_view details_file_str = details_file ? str_view {details_file, strlen(details_file) - 1} : str_view{};

From 42dccd67ef4ec7456069d56a00038537f06f17c1 Mon Sep 17 00:00:00 2001
From: Yanshu <yanshu.zhao7@gmail.com>
Date: Thu, 12 Sep 2019 14:30:59 -0700
Subject: [PATCH 58/58] Fix allow action for logging  (#127)

* fix logging allow action

* Add source comments for the define
---
 apache2/apache2_util.c              | 2 +-
 apache2/waf_logging/waf_log_util.cc | 8 +++++---
 apache2/waf_logging/waf_log_util.h  | 6 ++++++
 3 files changed, 12 insertions(+), 4 deletions(-)

diff --git a/apache2/apache2_util.c b/apache2/apache2_util.c
index fd738d3570..f462b3379c 100755
--- a/apache2/apache2_util.c
+++ b/apache2/apache2_util.c
@@ -478,7 +478,7 @@ static void internal_log_ex(request_rec *r, directory_config *dcfg, modsec_rec *
             msc_waf_log_reopened = 0;
         }
 
-        send_waf_log(msr->modsecurity->wafjsonlog_lock, msc_waf_log_fd, str1, r->useragent_ip ? r->useragent_ip : r->connection->client_ip, log_escape(msr->mp, r->uri), dcfg->is_enabled, r->hostname, unique_id, r, dcfg->waf_policy_id, dcfg->waf_policy_scope, dcfg->waf_policy_scope_name);
+        send_waf_log(msr->modsecurity->wafjsonlog_lock, msc_waf_log_fd, str1, r->useragent_ip ? r->useragent_ip : r->connection->client_ip, log_escape(msr->mp, r->uri), (!msr->allow_scope) ? dcfg->is_enabled : msr->allow_scope, r->hostname, unique_id, r, dcfg->waf_policy_id, dcfg->waf_policy_scope, dcfg->waf_policy_scope_name);
 #endif
 
 #if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER > 2
diff --git a/apache2/waf_logging/waf_log_util.cc b/apache2/waf_logging/waf_log_util.cc
index 146303e261..d3d8bb6eb7 100755
--- a/apache2/waf_logging/waf_log_util.cc
+++ b/apache2/waf_logging/waf_log_util.cc
@@ -111,6 +111,7 @@ static std::map<rule_set_info, rule_ids_vector> disableable_rule_ids_map;
 static const std::string WAF_ACTION_BLOCKED {"Blocked"};
 static const std::string WAF_ACTION_DETECTED {"Detected"};
 static const std::string WAF_ACTION_MATCHED {"Matched"};
+static const std::string WAF_ACTION_ALLOWED {"Allowed"};
 
 static bool is_mandatory_rule(const rule_set_types type, const rule_set_versions version, const int current_id) {
     const auto contains_current_id = [current_id] (const rule_ids_vector& rule_ids) {
@@ -150,9 +151,10 @@ static std::string get_json_log_message(const char* resource_id, const char* ope
     const bool is_mandatory = is_mandatory_rule(type, version, current_id);
 
     const str_view action_str =
-        (version != rule_set_versions::VERSION_2_2_9 && !is_mandatory)  ? WAF_ACTION_MATCHED :
-        action == MODSEC_MODE_DETECT                                    ? WAF_ACTION_DETECTED :
-        action == MODSEC_MODE_PREVENT                                   ? WAF_ACTION_BLOCKED :
+        (action == ACTION_ALLOW || action == ACTION_ALLOW_REQUEST || action == ACTION_ALLOW_PHASE) ? WAF_ACTION_ALLOWED :
+        (version != rule_set_versions::VERSION_2_2_9 && !is_mandatory)                             ? WAF_ACTION_MATCHED :
+        action == MODSEC_MODE_DETECT                                                               ? WAF_ACTION_DETECTED :
+        action == MODSEC_MODE_PREVENT                                                              ? WAF_ACTION_BLOCKED :
         str_view{};
 
     #define MANDATORY_RULE_MESSAGE ("Mandatory rule. Cannot be disabled. ")
diff --git a/apache2/waf_logging/waf_log_util.h b/apache2/waf_logging/waf_log_util.h
index 636a4f28a8..9fb95a8140 100755
--- a/apache2/waf_logging/waf_log_util.h
+++ b/apache2/waf_logging/waf_log_util.h
@@ -5,6 +5,12 @@
 #define WAF_LOG_UTIL_SUCCESS 0
 #define MODSEC_MODE_DETECT 1
 #define MODSEC_MODE_PREVENT 2
+
+// ACTION_ALLOW/ACTION_ALLOW_REQUEST/ACTION_ALLOW_PHASE are defined in the modsecurity.h and copied here
+#define ACTION_ALLOW 5
+#define ACTION_ALLOW_REQUEST 6
+#define ACTION_ALLOW_PHASE 7
+
 #define WAF_RULESET_PREFIX "/RuleSets/"
 #define WAF_LOG_UTIL_FILE "waf_json.log"
 #define WAF_LOG_UTIL_OPERATION_NAME "ApplicationGatewayFirewall"
