delete app
[bottlenecks.git] / rubbos / app / tomcat-connectors-1.2.32-src / native / iis / jk_isapi_plugin.c
diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/iis/jk_isapi_plugin.c b/rubbos/app/tomcat-connectors-1.2.32-src/native/iis/jk_isapi_plugin.c
deleted file mode 100644 (file)
index 7c9f67b..0000000
+++ /dev/null
@@ -1,3495 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one or more
- *  contributor license agreements.  See the NOTICE file distributed with
- *  this work for additional information regarding copyright ownership.
- *  The ASF licenses this file to You under the Apache License, Version 2.0
- *  (the "License"); 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
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-/***************************************************************************
- * Description: ISAPI plugin for IIS/PWS                                   *
- * Author:      Gal Shachor <shachor@il.ibm.com>                           *
- * Author:      Larry Isaacs <larryi@apache.org>                           *
- * Author:      Ignacio J. Ortega <nacho@apache.org>                       *
- * Author:      Mladen Turk <mturk@apache.org>                             *
- * Version:     $Revision: 1129429 $                                        *
- ***************************************************************************/
-
-// This define is needed to include wincrypt,h, needed to get client certificates
-#ifndef _WIN32_WINNT
-#define _WIN32_WINNT 0x0500
-#endif
-#include <winsock2.h>
-#include <httpext.h>
-#include <httpfilt.h>
-#include <wininet.h>
-
-#include "jk_global.h"
-#include "jk_url.h"
-#include "jk_util.h"
-#include "jk_map.h"
-#include "jk_pool.h"
-#include "jk_service.h"
-#include "jk_worker.h"
-#include "jk_uri_worker_map.h"
-#include "jk_shm.h"
-#include "jk_ajp13.h"
-#include "pcre.h"
-
-#ifndef POSIX_MALLOC_THRESHOLD
-#define POSIX_MALLOC_THRESHOLD (10)
-#endif
-
-#include <strsafe.h>
-
-#define VERSION_STRING "Jakarta/ISAPI/" JK_EXPOSED_VERSION
-#define FULL_VERSION_STRING "Jakarta/ISAPI/" JK_FULL_EXPOSED_VERSION
-#define SHM_DEF_NAME   "JKISAPISHMEM"
-#define DEFAULT_WORKER_NAME ("ajp13")
-
-/*
- * This is default value found inside httpd.conf
- * for MaxClients
- */
-#define DEFAULT_WORKER_THREADS  250
-
-/*
- * We use special headers to pass values from the filter to the
- * extension. These values are:
- *
- * 1. The real URI before redirection took place
- * 2. The name of the worker to be used.
- * 3. The contents of the Translate header, if any
- *
- */
-#define URI_HEADER_NAME_BASE              ("TOMCATURI")
-#define QUERY_HEADER_NAME_BASE            ("TOMCATQUERY")
-#define WORKER_HEADER_NAME_BASE           ("TOMCATWORKER")
-#define WORKER_HEADER_INDEX_BASE          ("TOMCATWORKERIDX")
-#define TOMCAT_TRANSLATE_HEADER_NAME_BASE ("TOMCATTRANSLATE")
-#ifndef USE_CGI_HEADERS
-#define CONTENT_LENGTH                    ("CONTENT-LENGTH:")
-#else
-#define CONTENT_LENGTH                    ("CONTENT_LENGTH:")
-#endif
-
-/* The HTTP_ form of the header for use in ExtensionProc */
-#define HTTP_HEADER_PREFIX       "HTTP_"
-#ifdef USE_CGI_HEADERS
-#define HTTP_HEADER_PREFIX_LEN   5
-#endif
-
-/* The template used to construct our unique headers
- * from the base name and module instance
- */
-#define HEADER_TEMPLATE      "%s%p:"
-#define HTTP_HEADER_TEMPLATE HTTP_HEADER_PREFIX "%s%p"
-
-static char URI_HEADER_NAME[MAX_PATH];
-static char QUERY_HEADER_NAME[MAX_PATH];
-static char WORKER_HEADER_NAME[MAX_PATH];
-static char TOMCAT_TRANSLATE_HEADER_NAME[MAX_PATH];
-static char WORKER_HEADER_INDEX[MAX_PATH];
-
-/* The variants of the special headers after IIS adds
- * "HTTP_" to the front of them
- */
-static char HTTP_URI_HEADER_NAME[MAX_PATH];
-static char HTTP_QUERY_HEADER_NAME[MAX_PATH];
-static char HTTP_WORKER_HEADER_NAME[MAX_PATH];
-static char HTTP_WORKER_HEADER_INDEX[MAX_PATH];
-
-#define REGISTRY_LOCATION       ("Software\\Apache Software Foundation\\Jakarta Isapi Redirector\\1.0")
-#define W3SVC_REGISTRY_KEY      ("SYSTEM\\CurrentControlSet\\Services\\W3SVC\\Parameters")
-#define EXTENSION_URI_TAG       ("extension_uri")
-
-#define URI_SELECT_TAG              ("uri_select")
-#define URI_SELECT_PARSED_VERB      ("parsed")
-#define URI_SELECT_UNPARSED_VERB    ("unparsed")
-#define URI_SELECT_ESCAPED_VERB     ("escaped")
-#define URI_SELECT_PROXY_VERB       ("proxy")
-#define URI_REWRITE_TAG             ("rewrite_rule_file")
-#define SHM_SIZE_TAG                ("shm_size")
-#define WORKER_MOUNT_RELOAD_TAG     ("worker_mount_reload")
-#define STRIP_SESSION_TAG           ("strip_session")
-#ifndef AUTOMATIC_AUTH_NOTIFICATION
-#define AUTH_COMPLETE_TAG           ("auth_complete")
-#endif
-#define REJECT_UNSAFE_TAG           ("reject_unsafe")
-#define WATCHDOG_INTERVAL_TAG       ("watchdog_interval")
-#define ENABLE_CHUNKED_ENCODING_TAG ("enable_chunked_encoding")
-#define ERROR_PAGE_TAG              ("error_page")
-
-#define LOG_ROTATION_TIME_TAG       ("log_rotationtime")
-#define LOG_FILESIZE_TAG            ("log_filesize")
-
-/* HTTP standard headers */
-#define TRANSFER_ENCODING_CHUNKED_HEADER_COMPLETE     ("Transfer-Encoding: chunked")
-#define TRANSFER_ENCODING_CHUNKED_HEADER_COMPLETE_LEN (26)
-#define TRANSFER_ENCODING_HEADER_NAME                 ("Transfer-Encoding")
-#define TRANSFER_ENCODING_HEADER_NAME_LEN             (17)
-#define TRANSFER_ENCODING_IDENTITY_VALUE              ("identity")
-#define TRANSFER_ENCODING_CHUNKED_VALUE               ("chunked")
-#define TRANSFER_ENCODING_CHUNKED_VALUE_LEN           (7)
-
-#define CONTENT_LENGTH_HEADER_NAME                    ("Content-Length")
-#define CONTENT_LENGTH_HEADER_NAME_LEN                (14)
-
-#define CONNECTION_HEADER_NAME      ("Connection")
-#define CONNECTION_CLOSE_VALUE      ("Close")
-
-#define TRANSLATE_HEADER            ("Translate:")
-#define TRANSLATE_HEADER_NAME       ("Translate")
-#define TRANSLATE_HEADER_NAME_LC    ("translate")
-
-/* HTTP protocol CRLF */
-#define CRLF                        ("\r\n")
-#define CRLF_LEN                    (2)
-
-/* Transfer-Encoding: chunked content trailer */
-#define CHUNKED_ENCODING_TRAILER     ("0\r\n\r\n")
-#define CHUNKED_ENCODING_TRAILER_LEN (5)
-
-/* Hex of chunk length (one char per byte) + CRLF + terminator. */
-#define CHUNK_HEADER_BUFFER_SIZE     (sizeof(unsigned int)*2+CRLF_LEN+1)
-
-#define BAD_REQUEST     -1
-#define BAD_PATH        -2
-#define MAX_SERVERNAME  128
-#define MAX_INSTANCEID  32
-#define MAX_PACKET_SIZE 65536
-
-char HTML_ERROR_HEAD[] =        "<!--\n"
-                                "  Licensed to the Apache Software Foundation (ASF) under one or more\n"
-                                "  contributor license agreements.  See the NOTICE file distributed with\n"
-                                "  this work for additional information regarding copyright ownership.\n"
-                                "  The ASF licenses this file to You under the Apache License, Version 2.0\n"
-                                "  (the \"License\"); you may not use this file except in compliance with\n"
-                                "  the License.  You may obtain a copy of the License at\n\n"
-                                "      http://www.apache.org/licenses/LICENSE-2.0\n\n"
-                                "  Unless required by applicable law or agreed to in writing, software\n"
-                                "  distributed under the License is distributed on an \"AS IS\" BASIS,\n"
-                                "  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n"
-                                "  See the License for the specific language governing permissions and\n"
-                                "  limitations under the License.\n"
-                                "  -->\n"
-                                "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\"\n"
-                                "\"http://www.w3c.org/TR/REC-html40/loose.dtd\">\n"
-                                "<HTML>\n<HEAD>\n"
-                                "<META http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\">\n"
-                                "<STYLE TYPE=\"text/css\">\n"
-                                "    body {\n"
-                                "       color: #000000;\n"
-                                "       background-color: #FFFFFF;\n"
-                                "       font-family: Verdana, Tahoma, Arial, Helvetica, sans-serif;\n"
-                                "       font-size: 9pt;\n"
-                                "       margin: 10px 10px;\n"
-                                "    }\n"
-                                "    p#footer {\n"
-                                "       text-align: right;\n"
-                                "       font-size: 80%;\n"
-                                "    }\n"
-                                "</STYLE>\n";
-
-#define HTML_ERROR_BODY_FMT     "<TITLE>%s!</TITLE>\n</HEAD>\n<BODY>\n<H1>%s!</H1>\n<P>\n%s\n</P>\n"
-
-char HTML_ERROR_TAIL[] =        "<P>\n<BR/>&nbsp;<BR/>&nbsp;<BR/>&nbsp;<BR/>&nbsp;\n"
-                                FULL_VERSION_STRING "\n"
-                                "<BR/>&nbsp;\n"
-                                "<HR/>\n"
-                                "<P id=\"footer\">\n"
-                                "Copyright &copy; 1999-2011 Apache Software Foundation<BR/>\n"
-                                "All Rights Reserved\n"
-                                "</P>\n</BODY>\n</HTML>\n";
-
-static struct error_reasons {
-    int status;
-    const char *reason;
-    const char *title;
-    const char *description;
-} error_reasons[] = {
-    { 100,
-      "Continue",
-      NULL,
-      NULL
-    },
-    { 101,
-      "Switching Protocols",
-      NULL,
-      NULL
-    },
-    { 200,
-      "OK",
-      NULL,
-      NULL
-    },
-    { 201,
-      "Created",
-      NULL,
-      NULL
-    },
-    { 202,
-      "Accepted",
-      NULL,
-      NULL
-    },
-    { 203,
-      "Non-Authoritative Information",
-      NULL,
-      NULL
-    },
-    { 204,
-      "No Content",
-      NULL,
-      NULL
-    },
-    { 205,
-      "Reset Content",
-      NULL,
-      NULL
-    },
-    { 206,
-      "Partial Content",
-      NULL,
-      NULL
-    },
-    { 300,
-      "Multiple Choices",
-      NULL,
-      NULL
-    },
-    { 301,
-      "Moved Permanently",
-      NULL,
-      NULL
-    },
-    { 302,
-      "Moved Temporarily",
-      NULL,
-      NULL
-    },
-    { 303,
-      "See Other",
-      NULL,
-      NULL
-    },
-    { 304,
-      "Not Modified",
-      NULL,
-      NULL
-    },
-    { 305,
-      "Use Proxy",
-      NULL,
-      NULL
-    },
-    { 400,
-      "Bad Request",
-      "Bad Request",
-      "Your browser (or proxy) sent a request that "
-      "this server could not understand."
-    },
-    { 401,
-      "Unauthorized",
-      "Access is denied due to invalid credentials",
-      "You do not have permission to view this directory or "
-      "page using the credentials that you supplied."
-    },
-    { 402,
-      "Payment Required",
-      NULL,
-      NULL
-    },
-    { 403,
-      "Forbidden",
-      "Access is denied",
-      "You do not have permission to view this directory or page "
-      "using the credentials that you supplied."
-    },
-    { 404,
-      "Not Found",
-      "The requested URL was not found on this server",
-      "If you entered the URL manually please check your"
-      "spelling and try again."
-    },
-    { 405,
-      "Method Not Allowed",
-      "HTTP method used to access this page is not allowed",
-      "The page you are looking for cannot be displayed because an "
-      "invalid method (HTTP method) was used to attempt access."
-    },
-    { 406,
-      "Not Acceptable",
-      "Client browser does not accept the MIME type of the requested page",
-      "The page you are looking for cannot be opened by your browser "
-      "because it has a file name extension that your browser "
-      "does not accept."
-    },
-    { 407,
-      "Proxy Authentication Required",
-      NULL,
-      "The client must first authenticate itself with the proxy"
-    },
-    { 408,
-      "Request Timeout",
-      NULL,
-      "The client did not produce a request within the time "
-      "that the server was prepared to wait."
-    },
-    { 409,
-      "Conflict",
-      NULL,
-      "The request could not be completed due to a conflict with "
-      "the current state of the resource."
-    },
-    { 410,
-      "Gone",
-      NULL,
-      "The requested resource is no longer available at the "
-      "server and no forwarding address is known."
-    },
-    { 411,
-      "Length Required",
-      NULL,
-      "The server refuses to accept the request without a "
-      "defined Content-Length."
-    },
-    { 412,
-      "Precondition Failed",
-      NULL,
-      "The precondition given in one or more of the request "
-      "header fields evaluated to false when it was tested on the server."
-    },
-    { 413,
-      "Request Entity Too Large",
-      NULL,
-      "The HTTP method does not allow the data transmitted, "
-      "or the data volume exceeds the capacity limit."
-    },
-    { 414,
-      "Request-URI Too Long",
-      "Submitted URI too large",
-      "The length of the requested URL exceeds the capacity limit "
-      "for this server. The request cannot be processed."
-    },
-    { 415,
-      "Unsupported Media Type",
-      NULL,
-      "The server is refusing to service the request because the "
-      "entity of the request is in a format not supported by the "
-      "requested resource for the requested method."
-    },
-    { 500,
-      "Internal Server Error",
-      NULL,
-      "The server encountered an internal error and was "
-      "unable to complete your request."
-    },
-    { 501,
-      "Not Implemented",
-      NULL,
-      "The server does not support the functionality required "
-      "to fulfill the request."
-    },
-    { 502,
-      "Bad Gateway",
-      NULL,
-      "There is a problem with the page you are looking for, "
-      "and it cannot be displayed. When the Web server (while "
-      "acting as a gateway or proxy) contacted the upstream content "
-      "server, it received an invalid response from the content server."
-    },
-    { 503,
-      "Service Unavailable",
-      "Service Temporary Unavailable",
-      "The server is temporarily unable to service your "
-      "request due to maintenance downtime or capacity problems. "
-      "Please try again later."
-    },
-    { 504,
-      "Gateway Timeout",
-      NULL,
-      "The server, while acting as a gateway or proxy, "
-      "did not receive a timely response from the upstream server"
-    },
-    { 505,
-      "HTTP Version Not Supported",
-      NULL,
-      "The server does not support, or refuses to support, the "
-      "HTTP protocol version that was used in the request message."
-    },
-    { 0,
-      NULL,
-      NULL,
-      NULL
-    }
-};
-
-
-
-#define STRNULL_FOR_NULL(x) ((x) ? (x) : "(null)")
-#ifdef USE_CGI_HEADERS
-#define JK_TOLOWER(x)   ((char)tolower((BYTE)(x)))
-#endif
-
-#define GET_SERVER_VARIABLE_VALUE(name, place)          \
-  do {                                                  \
-    (place) = NULL;                                     \
-    huge_buf_sz = MAX_PACKET_SIZE;                      \
-    if (get_server_value(private_data->lpEcb,           \
-                        (name),                         \
-                        huge_buf,                       \
-                        huge_buf_sz)) {                 \
-        (place) = jk_pool_strdup(&private_data->p,      \
-                                 huge_buf);             \
-  } } while(0)
-
-#define GET_SERVER_VARIABLE_VALUE_INT(name, place, def)     \
-  do {                                                      \
-    huge_buf_sz = MAX_PACKET_SIZE;                          \
-    if (get_server_value(private_data->lpEcb,               \
-                        (name),                             \
-                        huge_buf,                           \
-                        huge_buf_sz)) {                     \
-        (place) = atoi(huge_buf);                           \
-        if (((place) == 0) && (errno == EINVAL ||           \
-                               errno == ERANGE)) {          \
-            (place) = def;                                  \
-        }                                                   \
-    } else {                                                \
-        (place) = def;                                      \
-  } } while(0)
-
-static char dll_file_path[MAX_PATH];
-static char ini_file_name[MAX_PATH];
-static int using_ini_file = JK_FALSE;
-static JK_CRIT_SEC init_cs;
-static int is_inited = JK_FALSE;
-static int is_mapread = JK_FALSE;
-
-static jk_uri_worker_map_t *uw_map = NULL;
-static jk_map_t *workers_map = NULL;
-static jk_map_t *rewrite_map = NULL;
-static jk_map_t *rregexp_map = NULL;
-static jk_map_t *jk_environment_map = NULL;
-
-static jk_logger_t *logger = NULL;
-static JK_CRIT_SEC log_cs;
-static char *SERVER_NAME = "SERVER_NAME";
-static char *SERVER_SOFTWARE = "SERVER_SOFTWARE";
-static char *INSTANCE_ID = "INSTANCE_ID";
-static char *CONTENT_TYPE = "Content-Type:text/html\r\n\r\n";
-
-static char extension_uri[INTERNET_MAX_URL_LENGTH] =
-    "/jakarta/isapi_redirect.dll";
-static char log_file[MAX_PATH * 2];
-static char log_file_effective[MAX_PATH * 2];
-static int  log_level = JK_LOG_DEF_LEVEL;
-static long log_rotationtime = 0;
-static time_t log_next_rotate_time = 0;
-static ULONGLONG log_filesize = 0;
-
-static char worker_file[MAX_PATH * 2];
-static char worker_mount_file[MAX_PATH * 2] = {0};
-static int  worker_mount_reload = JK_URIMAP_DEF_RELOAD;
-static char rewrite_rule_file[MAX_PATH * 2] = {0};
-static size_t shm_config_size = 0;
-static int  strip_session = 0;
-#ifndef AUTOMATIC_AUTH_NOTIFICATION
-static int  use_auth_notification_flags = 1;
-#endif
-static int  chunked_encoding_enabled = JK_FALSE;
-static int  reject_unsafe = 0;
-static int  watchdog_interval = 0;
-static HANDLE watchdog_handle = NULL;
-static char error_page_buf[INTERNET_MAX_URL_LENGTH] = {0};
-static char *error_page = NULL;
-
-#define URI_SELECT_OPT_PARSED       0
-#define URI_SELECT_OPT_UNPARSED     1
-#define URI_SELECT_OPT_ESCAPED      2
-#define URI_SELECT_OPT_PROXY        3
-
-static int uri_select_option = URI_SELECT_OPT_PROXY;
-
-static jk_worker_env_t worker_env;
-
-typedef struct isapi_private_data_t isapi_private_data_t;
-struct isapi_private_data_t
-{
-    jk_pool_t p;
-
-    unsigned int bytes_read_so_far;
-    int chunk_content;          /* Whether we're responding with Transfer-Encoding: chunked content */
-    LPEXTENSION_CONTROL_BLOCK lpEcb;
-};
-
-typedef struct isapi_log_data_t isapi_log_data_t;
-struct isapi_log_data_t {
-    char uri[INTERNET_MAX_URL_LENGTH];
-    char query[INTERNET_MAX_URL_LENGTH];
-    int request_matched;        /* Whether this request (within a multi-request connection)
-                                   was handled and needs the log values adjusted */
-};
-
-typedef struct iis_info_t iis_info_t;
-struct iis_info_t {
-    int major;                  /* The major version */
-    int minor;                  /* The minor version */
-    DWORD filter_notify_event;  /* The primary filter SF_NOTIFY_* event */
-};
-
-static iis_info_t iis_info;
-
-static int JK_METHOD start_response(jk_ws_service_t *s,
-                                    int status,
-                                    const char *reason,
-                                    const char *const *header_names,
-                                    const char *const *header_values,
-                                    unsigned int num_of_headers);
-
-static int JK_METHOD iis_read(jk_ws_service_t *s,
-                          void *b, unsigned int l, unsigned int *a);
-
-static int JK_METHOD iis_write(jk_ws_service_t *s, const void *b, unsigned int l);
-
-static int JK_METHOD iis_done(jk_ws_service_t *s);
-
-static int init_ws_service(isapi_private_data_t * private_data,
-                           jk_ws_service_t *s, char **worker_name);
-
-static int init_jk(char *serverName);
-
-
-static int JK_METHOD iis_log_to_file(jk_logger_t *l, int level,
-                                    int used, char *what);
-
-static BOOL initialize_extension(void);
-
-static int read_registry_init_data(void);
-
-static int get_config_parameter(LPVOID src, const char *tag,
-                                char *val, DWORD sz);
-
-static int get_config_bool(LPVOID src, const char *tag, int def);
-
-static int get_config_int(LPVOID src, const char *tag, int def);
-
-static int get_registry_config_parameter(HKEY hkey,
-                                         const char *tag, char *b, DWORD sz);
-
-static int get_registry_config_number(HKEY hkey, const char *tag,
-                                      int *val);
-
-
-static int get_server_value(LPEXTENSION_CONTROL_BLOCK lpEcb,
-                            char *name,
-                            char *buf, DWORD bufsz);
-
-static int base64_encode_cert_len(int len);
-
-static int base64_encode_cert(char *encoded,
-                              const char *string, int len);
-
-static int get_iis_info(iis_info_t *info);
-
-static int isapi_write_client(isapi_private_data_t *p, const char *buf, unsigned int write_length);
-
-static char x2c(const char *what)
-{
-    register char digit;
-
-    digit =
-        ((what[0] >= 'A') ? ((what[0] & 0xdf) - 'A') + 10 : (what[0] - '0'));
-    digit *= 16;
-    digit +=
-        (what[1] >= 'A' ? ((what[1] & 0xdf) - 'A') + 10 : (what[1] - '0'));
-    return (digit);
-}
-
-static int unescape_url(char *url)
-{
-    register int x, y, badesc, badpath;
-
-    badesc = 0;
-    badpath = 0;
-    for (x = 0, y = 0; url[y]; ++x, ++y) {
-        if (url[y] != '%')
-            url[x] = url[y];
-        else {
-            if (!isxdigit(url[y + 1]) || !isxdigit(url[y + 2])) {
-                badesc = 1;
-                url[x] = '%';
-            }
-            else {
-                url[x] = x2c(&url[y + 1]);
-                y += 2;
-                if (url[x] == '/' || url[x] == '\0')
-                    badpath = 1;
-            }
-        }
-    }
-    url[x] = '\0';
-    if (badesc)
-        return BAD_REQUEST;
-    else if (badpath)
-        return BAD_PATH;
-    else
-        return 0;
-}
-
-static void getparents(char *name)
-{
-    int l, w;
-
-    /* Four paseses, as per RFC 1808 */
-    /* a) remove ./ path segments */
-
-    for (l = 0, w = 0; name[l] != '\0';) {
-        if (name[l] == '.' && name[l + 1] == '/'
-            && (l == 0 || name[l - 1] == '/'))
-            l += 2;
-        else
-            name[w++] = name[l++];
-    }
-
-    /* b) remove trailing . path, segment */
-    if (w == 1 && name[0] == '.')
-        w--;
-    else if (w > 1 && name[w - 1] == '.' && name[w - 2] == '/')
-        w--;
-    name[w] = '\0';
-
-    /* c) remove all xx/../ segments. (including leading ../ and /../) */
-    l = 0;
-
-    while (name[l] != '\0') {
-        if (name[l] == '.' && name[l + 1] == '.' && name[l + 2] == '/' &&
-            (l == 0 || name[l - 1] == '/')) {
-            register int m = l + 3, n;
-
-            l = l - 2;
-            if (l >= 0) {
-                while (l >= 0 && name[l] != '/')
-                    l--;
-                l++;
-            }
-            else
-                l = 0;
-            n = l;
-            while ((name[n] = name[m]) != '\0') {
-                n++;
-                m++;
-            }
-        }
-        else
-            ++l;
-    }
-
-    /* d) remove trailing xx/.. segment. */
-    if (l == 2 && name[0] == '.' && name[1] == '.')
-        name[0] = '\0';
-    else if (l > 2 && name[l - 1] == '.' && name[l - 2] == '.'
-             && name[l - 3] == '/') {
-        l = l - 4;
-        if (l >= 0) {
-            while (l >= 0 && name[l] != '/')
-                l--;
-            l++;
-        }
-        else
-            l = 0;
-        name[l] = '\0';
-    }
-}
-
-/* Apache code to escape a URL */
-
-#define T_OS_ESCAPE_PATH    (4)
-
-static const BYTE test_char_table[256] = {
-     0, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 14, 14, 14, 14, 14,
-    14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
-    14,  0,  7,  6,  1,  6,  1,  1,  9,  9,  1,  0,  8,  0,  0, 10,
-     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  8, 15, 15,  8, 15, 15,
-     8,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 15, 15, 15,  7,  0,
-     7,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 15,  7, 15,  1, 14,
-     6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,
-     6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,
-     6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,
-     6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,
-     6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,
-     6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,
-     6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,
-     6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6
-};
-
-#define TEST_CHAR(c, f) (test_char_table[(unsigned int)(c)] & (f))
-
-static const char c2x_table[] = "0123456789abcdef";
-
-static BYTE *c2x(unsigned int what, BYTE *where)
-{
-    *where++ = '%';
-    *where++ = c2x_table[what >> 4];
-    *where++ = c2x_table[what & 0xf];
-    return where;
-}
-
-static const char *status_reason(int status)
-{
-    struct error_reasons *r;
-
-    r = error_reasons;
-    while (r->status <= status) {
-        if (r->status == status)
-            return r->reason;
-        else
-            r++;
-    }
-    return "No Reason";
-}
-
-static const char *status_title(int status)
-{
-    struct error_reasons *r;
-
-    r = error_reasons;
-    while (r->status <= status) {
-        if (r->status == status) {
-            if (r->title)
-                return r->title;
-            else
-                return r->reason;
-        }
-        else
-            r++;
-    }
-    return "Unknown Error";
-}
-
-static const char *status_description(int status)
-{
-    struct error_reasons *r;
-
-    r = error_reasons;
-    while (r->status <= status) {
-        if (r->status == status) {
-            if (r->description)
-                return r->description;
-            else
-                return r->reason;
-        }
-        else
-            r++;
-    }
-    return "Unknown Error";
-}
-
-static int escape_url(const char *path, char *dest, int destsize)
-{
-    const BYTE *s = (const BYTE *)path;
-    BYTE *d = (BYTE *)dest;
-    BYTE *e = d + destsize - 1;
-    BYTE *ee = d + destsize - 3;
-
-    while (*s) {
-        if (TEST_CHAR(*s, T_OS_ESCAPE_PATH)) {
-            if (d >= ee)
-                return JK_FALSE;
-            d = c2x(*s, d);
-        }
-        else {
-            if (d >= e)
-                return JK_FALSE;
-            *d++ = *s;
-        }
-        ++s;
-    }
-    *d = '\0';
-    return JK_TRUE;
-}
-
-/*
- * Find the first occurrence of find in s.
- */
-static char *stristr(const char *s, const char *find)
-{
-    char c, sc;
-    size_t len;
-
-    if ((c = tolower((unsigned char)(*find++))) != 0) {
-        len = strlen(find);
-        do {
-            do {
-                if ((sc = tolower((unsigned char)(*s++))) == 0)
-                    return (NULL);
-            } while (sc != c);
-        } while (strnicmp(s, find, len) != 0);
-        s--;
-    }
-    return ((char *)s);
-}
-
-static int uri_is_web_inf(const char *uri)
-{
-    if (stristr(uri, "/web-inf")) {
-        return JK_TRUE;
-    }
-    if (stristr(uri, "/meta-inf")) {
-        return JK_TRUE;
-    }
-
-    return JK_FALSE;
-}
-
-static void write_error_response(PHTTP_FILTER_CONTEXT pfc, int err)
-{
-    char status[MAX_PATH];
-    char body[8192] = "";
-    DWORD len;
-
-    /* reject !!! */
-    pfc->AddResponseHeaders(pfc, CONTENT_TYPE, 0);
-    StringCbPrintf(status, MAX_PATH, "%d %s", err, status_reason(err));
-    pfc->ServerSupportFunction(pfc,
-                               SF_REQ_SEND_RESPONSE_HEADER,
-                               status, 0, 0);
-    len = (DWORD)(sizeof(HTML_ERROR_HEAD) - 1);
-    pfc->WriteClient(pfc, HTML_ERROR_HEAD, &len,
-                     HSE_IO_SYNC);
-    StringCbPrintf(body, sizeof(body), HTML_ERROR_BODY_FMT,
-                   status_reason(err), status_title(err),
-                   status_description(err));
-    len = (DWORD)(strlen(body));
-    pfc->WriteClient(pfc, body, &len,
-                     HSE_IO_SYNC);
-    len = (DWORD)(sizeof(HTML_ERROR_TAIL) - 1);
-    pfc->WriteClient(pfc, HTML_ERROR_TAIL, &len,
-                     HSE_IO_SYNC);
-}
-
-static void write_error_message(LPEXTENSION_CONTROL_BLOCK lpEcb, int err)
-{
-    DWORD len;
-    char status[MAX_PATH];
-    char body[8192] = "";
-
-    if (error_page) {
-        char error_page_url[INTERNET_MAX_URL_LENGTH] = "";
-        int len_of_error_page;
-        StringCbPrintf(error_page_url, INTERNET_MAX_URL_LENGTH,
-                       (LPCSTR)error_page, err);
-        len_of_error_page = (int)strlen(error_page_url);
-        if (!lpEcb->ServerSupportFunction(lpEcb->ConnID,
-                                          HSE_REQ_SEND_URL_REDIRECT_RESP,
-                                          error_page_url,
-                                          (LPDWORD)&len_of_error_page,
-                                          (LPDWORD)NULL)) {
-            lpEcb->dwHttpStatusCode = err;
-        }
-        else {
-            return;
-        }
-    }
-    lpEcb->dwHttpStatusCode = err;
-
-    StringCbPrintf(status, MAX_PATH, "%d %s", err, status_reason(err));
-    lpEcb->ServerSupportFunction(lpEcb->ConnID,
-                                 HSE_REQ_SEND_RESPONSE_HEADER,
-                                 status,
-                                 0,
-                                 (LPDWORD)CONTENT_TYPE);
-    /* First write the HEAD */
-    len = (DWORD)(sizeof(HTML_ERROR_HEAD) - 1);
-    lpEcb->WriteClient(lpEcb->ConnID,
-                       HTML_ERROR_HEAD, &len,
-                       HSE_IO_SYNC);
-    StringCbPrintf(body, sizeof(body), HTML_ERROR_BODY_FMT,
-                   status_reason(err), status_title(err),
-                   status_description(err));
-    len = (DWORD)(strlen(body));
-    lpEcb->WriteClient(lpEcb->ConnID,
-                       body, &len,
-                       HSE_IO_SYNC);
-    len = (DWORD)(sizeof(HTML_ERROR_TAIL) - 1);
-    lpEcb->WriteClient(lpEcb->ConnID,
-                       HTML_ERROR_TAIL, &len,
-                       HSE_IO_SYNC);
-
-}
-
-
-static int JK_METHOD start_response(jk_ws_service_t *s,
-                                    int status,
-                                    const char *reason,
-                                    const char *const *header_names,
-                                    const char *const *header_values,
-                                    unsigned int num_of_headers)
-{
-    JK_TRACE_ENTER(logger);
-    if (status < 100 || status > 1000) {
-        jk_log(logger, JK_LOG_ERROR,
-               "invalid status %d",
-               status);
-        JK_TRACE_EXIT(logger);
-        return JK_FALSE;
-    }
-
-    if (s && s->ws_private) {
-        int rv = JK_TRUE;
-        isapi_private_data_t *p = s->ws_private;
-
-        /* If we use proxy error pages, still pass
-         * through context headers needed for special status codes.
-         */
-        if (s->extension.use_server_error_pages &&
-            status >= s->extension.use_server_error_pages) {
-            if (status == JK_HTTP_UNAUTHORIZED) {
-                int found = JK_FALSE;
-                unsigned int h;
-                for (h = 0; h < num_of_headers; h++) {
-                    if (!strcasecmp(header_names[h], "WWW-Authenticate")) {
-                        /*
-                         * TODO: we need to save a copy of header_values[h]
-                         * for later reuse in write_error_message()
-                         * which is called later on form HttpExtensionProc
-                         * because of use_server_error_pages.
-                         */
-                        found = JK_TRUE;
-                    }
-                }
-                if (found == JK_FALSE) {
-                    jk_log(logger, JK_LOG_INFO,
-                           "origin server sent 401 without"
-                           " WWW-Authenticate header");
-                }
-            }
-            return JK_TRUE;
-        }
-
-        if (!s->response_started) {
-            char *status_str = NULL;
-            char *headers_str = NULL;
-            BOOL keep_alive = FALSE;     /* Whether the downstream or us can supply content length */
-            BOOL rc;
-            size_t i, len_of_headers = 0;
-
-            s->response_started = JK_TRUE;
-
-            if (JK_IS_DEBUG_LEVEL(logger)) {
-                jk_log(logger, JK_LOG_DEBUG, "Starting response for URI '%s' (protocol %s)",
-                       s->req_uri, s->protocol);
-            }
-
-            /*
-             * Create the status line
-             */
-            if (!reason) {
-                reason = status_reason(status);
-            }
-            status_str = (char *)malloc((6 + strlen(reason)));
-            StringCbPrintf(status_str, 6 + strlen(reason), "%d %s", status, reason);
-
-            if (chunked_encoding_enabled) {
-                /* Check if we've got an HTTP/1.1 response */
-                if (!strcasecmp(s->protocol, "HTTP/1.1")) {
-                    keep_alive = TRUE;
-                    /* Chunking only when HTTP/1.1 client and enabled */
-                    p->chunk_content = JK_TRUE;
-                }
-            }
-
-            /*
-             * Create response headers string
-             */
-
-            /* Calculate length of headers block */
-            for (i = 0; i < num_of_headers; i++) {
-                len_of_headers += strlen(header_names[i]);
-                len_of_headers += strlen(header_values[i]);
-                len_of_headers += 4;   /* extra for colon, space and crlf */
-            }
-
-            /*
-             * Exclude status codes that MUST NOT include message bodies
-             */
-            if ((status == 204) || (status == 205) || (status == 304)) {
-                p->chunk_content = JK_FALSE;
-                /* Keep alive is still possible */
-                if (JK_IS_DEBUG_LEVEL(logger))
-                    jk_log(logger, JK_LOG_DEBUG, "Response status %d implies no message body", status );
-            }
-            if (p->chunk_content) {
-                for (i = 0; i < num_of_headers; i++) {
-                    /* Check the downstream response to see whether
-                     * it's appropriate to chunk the response content
-                     * and whether it supports keeping the connection open.
-
-                     * This implements the rules for HTTP/1.1 message length determination
-                     * with the exception of multipart/byteranges media types.
-                     * http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.4
-                     */
-                    if (!strcasecmp(CONTENT_LENGTH_HEADER_NAME, header_names[i])) {
-                        p->chunk_content = JK_FALSE;
-                        if (JK_IS_DEBUG_LEVEL(logger))
-                            jk_log(logger, JK_LOG_DEBUG, "Response specifies Content-Length" );
-                    }
-                    else if (!strcasecmp(CONNECTION_HEADER_NAME, header_names[i])
-                            && !strcasecmp(CONNECTION_CLOSE_VALUE, header_values[i])) {
-                        keep_alive = FALSE;
-                        p->chunk_content = JK_FALSE;
-                        if (JK_IS_DEBUG_LEVEL(logger))
-                            jk_log(logger, JK_LOG_DEBUG, "Response specifies Connection: Close" );
-                    }
-                    else if (!strcasecmp(TRANSFER_ENCODING_HEADER_NAME, header_names[i])
-                            && !strcasecmp(TRANSFER_ENCODING_IDENTITY_VALUE, header_values[i])) {
-                        /* HTTP states that this must include 'chunked' as the last value.
-                            * 'identity' is the same as absence of the header */
-                        p->chunk_content = JK_FALSE;
-                        if (JK_IS_DEBUG_LEVEL(logger))
-                            jk_log(logger, JK_LOG_DEBUG, "Response specifies Transfer-Encoding" );
-                    }
-                }
-
-                /* Provide room in the buffer for the Transfer-Encoding header if we use it. */
-                len_of_headers += TRANSFER_ENCODING_CHUNKED_HEADER_COMPLETE_LEN + 2;
-            }
-
-            /* Allocate and init the headers string */
-            len_of_headers += 3;       /* crlf and terminating null char */
-            headers_str = (char *)malloc(len_of_headers);
-            headers_str[0] = '\0';
-
-            /* Copy headers into headers block for sending */
-            for (i = 0; i < num_of_headers; i++) {
-                StringCbCat(headers_str, len_of_headers, header_names[i]);
-                StringCbCat(headers_str, len_of_headers, ": ");
-                StringCbCat(headers_str, len_of_headers, header_values[i]);
-                StringCbCat(headers_str, len_of_headers, CRLF);
-            }
-
-            if (p->chunk_content) {
-                /* Configure the response if chunked encoding is used */
-                if (JK_IS_DEBUG_LEVEL(logger))
-                    jk_log(logger, JK_LOG_DEBUG, "Using Transfer-Encoding: chunked");
-
-                /** We will supply the transfer-encoding to allow IIS to keep the connection open */
-                keep_alive = TRUE;
-
-                /* Indicate to the client that the content will be chunked
-                - We've already reserved space for this */
-                StringCbCat(headers_str, len_of_headers, TRANSFER_ENCODING_CHUNKED_HEADER_COMPLETE);
-                StringCbCat(headers_str, len_of_headers, CRLF);
-            }
-
-            /* Terminate the headers */
-            StringCbCat(headers_str, len_of_headers, CRLF);
-
-            if (JK_IS_DEBUG_LEVEL(logger))
-                jk_log(logger, JK_LOG_DEBUG, "%ssing Keep-Alive", (keep_alive ? "U" : "Not u"));
-
-            if (keep_alive) {
-                HSE_SEND_HEADER_EX_INFO hi;
-
-                /* Fill in the response */
-                hi.pszStatus = status_str;
-                hi.pszHeader = headers_str;
-                hi.cchStatus = (DWORD)strlen(status_str);
-                hi.cchHeader = (DWORD)strlen(headers_str);
-
-                /*
-                 * Using the extended form of the API means we have to get this right,
-                 * i.e. IIS won't keep connections open if there's a Content-Length and close them if there isn't.
-                 */
-                hi.fKeepConn = keep_alive;
-
-                /* Send the response to the client */
-                rc = p->lpEcb->ServerSupportFunction(p->lpEcb->ConnID,
-                                                      HSE_REQ_SEND_RESPONSE_HEADER_EX,
-                                                      &hi,
-                                                      NULL, NULL);
-            }
-            else {
-                DWORD status_str_len = (DWORD)strlen(status_str);
-                /* Old style response - forces Connection: close if Tomcat response doesn't
-                   specify necessary details to allow keep alive */
-                rc = p->lpEcb->ServerSupportFunction(p->lpEcb->ConnID,
-                                                      HSE_REQ_SEND_RESPONSE_HEADER,
-                                                      status_str,
-                                                      &status_str_len,
-                                                      (LPDWORD)headers_str);
-            }
-
-            if (!rc) {
-                jk_log(logger, JK_LOG_ERROR,
-                       "HSE_REQ_SEND_RESPONSE_HEADER%s failed with error=%d (0x%08x)",
-                       (keep_alive ? "_EX" : ""), GetLastError(), GetLastError());
-                rv = JK_FALSE;
-            }
-            if (headers_str)
-                free(headers_str);
-            if (status_str)
-                free(status_str);
-        }
-        JK_TRACE_EXIT(logger);
-        return rv;
-    }
-
-    JK_LOG_NULL_PARAMS(logger);
-    JK_TRACE_EXIT(logger);
-    return JK_FALSE;
-}
-
-static int JK_METHOD iis_read(jk_ws_service_t *s,
-                          void *b, unsigned int l, unsigned int *a)
-{
-    JK_TRACE_ENTER(logger);
-
-    if (s && s->ws_private && b && a) {
-        isapi_private_data_t *p = s->ws_private;
-
-        if (JK_IS_DEBUG_LEVEL(logger)) {
-            jk_log(logger, JK_LOG_DEBUG,
-                   "Preparing to read %d bytes. "
-                   "ECB reports %d bytes total, with %d available.",
-                   l, p->lpEcb->cbTotalBytes, p->lpEcb->cbAvailable);
-        }
-
-        *a = 0;
-        if (l) {
-            char *buf = b;
-            DWORD already_read = p->lpEcb->cbAvailable - p->bytes_read_so_far;
-
-            if (already_read >= l) {
-                if (JK_IS_DEBUG_LEVEL(logger)) {
-                    jk_log(logger, JK_LOG_DEBUG,
-                           "Already read %d bytes - supplying %d bytes from buffer",
-                           already_read, l);
-                }
-                memcpy(buf, p->lpEcb->lpbData + p->bytes_read_so_far, l);
-                p->bytes_read_so_far += l;
-                *a = l;
-            }
-            else {
-                /*
-                 * Try to copy what we already have
-                 */
-                if (already_read > 0) {
-                    if (JK_IS_DEBUG_LEVEL(logger)) {
-                        jk_log(logger, JK_LOG_DEBUG,
-                               "Supplying %d bytes from buffer",
-                               already_read);
-                    }
-                    memcpy(buf, p->lpEcb->lpbData + p->bytes_read_so_far,
-                           already_read);
-                    buf += already_read;
-                    l -= already_read;
-                    p->bytes_read_so_far = p->lpEcb->cbAvailable;
-
-                    *a = already_read;
-                }
-
-                /*
-                 * Now try to read from the client ...
-                 */
-                if (JK_IS_DEBUG_LEVEL(logger)) {
-                    jk_log(logger, JK_LOG_DEBUG,
-                           "Attempting to read %d bytes from client", l);
-                }
-                if (p->lpEcb->ReadClient(p->lpEcb->ConnID, buf, (LPDWORD)&l)) {
-                    /* ReadClient will succeed with dwSize == 0 for last chunk 
-                       if request chunk encoded */
-                    *a += l;
-                }
-                else {
-                    jk_log(logger, JK_LOG_ERROR,
-                           "ReadClient failed with %d (0x%08x)", GetLastError(), GetLastError());
-                    JK_TRACE_EXIT(logger);
-                    return JK_FALSE;
-                }
-            }
-        }
-        JK_TRACE_EXIT(logger);
-        return JK_TRUE;
-    }
-
-    JK_LOG_NULL_PARAMS(logger);
-    JK_TRACE_EXIT(logger);
-    return JK_FALSE;
-}
-
-/*
- * Writes a buffer to the ISAPI response.
- */
-static int isapi_write_client(isapi_private_data_t *p, const char *buf, unsigned int write_length)
-{
-    unsigned int written = 0;
-    DWORD try_to_write = 0;
-
-    JK_TRACE_ENTER(logger);
-
-    if (JK_IS_DEBUG_LEVEL(logger))
-        jk_log(logger, JK_LOG_DEBUG, "Writing %d bytes of data to client", write_length);
-
-    while (written < write_length) {
-        try_to_write = write_length - written;
-        if (!p->lpEcb->WriteClient(p->lpEcb->ConnID,
-                                   (LPVOID)(buf + written), &try_to_write, HSE_IO_SYNC)) {
-            jk_log(logger, JK_LOG_ERROR,
-                   "WriteClient failed with %d (0x%08x)", GetLastError(), GetLastError());
-            JK_TRACE_EXIT(logger);
-            return JK_FALSE;
-        }
-        written += try_to_write;
-        if (JK_IS_DEBUG_LEVEL(logger))
-            jk_log(logger, JK_LOG_DEBUG, "Wrote %d bytes of data successfully", try_to_write);
-    }
-    JK_TRACE_EXIT(logger);
-    return JK_TRUE;
-}
-
-/*
- * Write content to the response.
- * If chunked encoding has been enabled and the client supports it
- *(and it's appropriate for the response), then this will write a
- * single "Transfer-Encoding: chunked" chunk
- */
-static int JK_METHOD iis_write(jk_ws_service_t *s, const void *b, unsigned int l)
-{
-    JK_TRACE_ENTER(logger);
-
-    if (!l) {
-        JK_TRACE_EXIT(logger);
-        return JK_TRUE;
-    }
-
-    if (s && s->ws_private && b) {
-        isapi_private_data_t *p = s->ws_private;
-        const char *buf = (const char *)b;
-
-        if (!p) {
-            JK_TRACE_EXIT(logger);
-            return JK_FALSE;
-        }
-
-        if (!s->response_started) {
-            start_response(s, 200, NULL, NULL, NULL, 0);
-        }
-
-        if (p->chunk_content == JK_FALSE) {
-            if (isapi_write_client(p, buf, l) == JK_FALSE) {
-                JK_TRACE_EXIT(logger);
-                return JK_FALSE;
-            }
-        }
-        else {
-            char chunk_header[CHUNK_HEADER_BUFFER_SIZE];
-
-            /* Construct chunk header : HEX CRLF*/
-            StringCbPrintf(chunk_header, CHUNK_HEADER_BUFFER_SIZE, "%X%s", l, CRLF);
-
-            if (iis_info.major >= 6) {
-                HSE_RESPONSE_VECTOR response_vector;
-                HSE_VECTOR_ELEMENT response_elements[3];
-
-                response_elements[0].ElementType = HSE_VECTOR_ELEMENT_TYPE_MEMORY_BUFFER;
-                response_elements[0].pvContext = chunk_header;
-                response_elements[0].cbOffset = 0;
-                response_elements[0].cbSize = strlen(chunk_header);
-
-                response_elements[1].ElementType = HSE_VECTOR_ELEMENT_TYPE_MEMORY_BUFFER;
-                response_elements[1].pvContext = (PVOID)buf;
-                response_elements[1].cbOffset = 0;
-                response_elements[1].cbSize = l;
-
-                response_elements[2].ElementType = HSE_VECTOR_ELEMENT_TYPE_MEMORY_BUFFER;
-                response_elements[2].pvContext = CRLF;
-                response_elements[2].cbOffset = 0;
-                response_elements[2].cbSize = CRLF_LEN;
-
-                response_vector.dwFlags = HSE_IO_SYNC;
-                response_vector.pszStatus = NULL;
-                response_vector.pszHeaders = NULL;
-                response_vector.nElementCount = 3;
-                response_vector.lpElementArray = response_elements;
-
-                if (JK_IS_DEBUG_LEVEL(logger))
-                    jk_log(logger, JK_LOG_DEBUG,
-                           "Using vector write for chunk encoded %d byte chunk", l);
-
-                if (!p->lpEcb->ServerSupportFunction(p->lpEcb->ConnID,
-                    HSE_REQ_VECTOR_SEND,
-                    &response_vector,
-                    (LPDWORD)NULL,
-                    (LPDWORD)NULL)) {
-                        jk_log(logger, JK_LOG_ERROR,
-                               "Vector write of chunk encoded response failed with %d (0x%08x)",
-                               GetLastError(), GetLastError());
-                        JK_TRACE_EXIT(logger);
-                        return JK_FALSE;
-                }
-            } else {
-                /* Write chunk header */
-                if (JK_IS_DEBUG_LEVEL(logger))
-                    jk_log(logger, JK_LOG_DEBUG,
-                    "Using chunked encoding - writing chunk header for %d byte chunk", l);
-
-                if (!isapi_write_client(p, chunk_header, (unsigned int)strlen(chunk_header))) {
-                    jk_log(logger, JK_LOG_ERROR, "WriteClient for chunk header failed");
-                    JK_TRACE_EXIT(logger);
-                    return JK_FALSE;
-                }
-
-                /* Write chunk body (or simple body block) */
-                if (JK_IS_DEBUG_LEVEL(logger)) {
-                    jk_log(logger, JK_LOG_DEBUG, "Writing %s of size %d",
-                           (p->chunk_content ? "chunk body" : "simple response"), l);
-                }
-                if (!isapi_write_client(p, buf, l)) {
-                    jk_log(logger, JK_LOG_ERROR, "WriteClient for response body chunk failed");
-                    JK_TRACE_EXIT(logger);
-                    return JK_FALSE;
-                }
-                /* Write chunk trailer */
-                if (JK_IS_DEBUG_LEVEL(logger)) {
-                    jk_log(logger, JK_LOG_DEBUG, "Using chunked encoding - writing chunk trailer");
-                }
-
-                if (!isapi_write_client(p, CRLF, CRLF_LEN)) {
-                    jk_log(logger, JK_LOG_ERROR, "WriteClient for chunk trailer failed");
-                    JK_TRACE_EXIT(logger);
-                    return JK_FALSE;
-                }
-            }
-        }
-
-        JK_TRACE_EXIT(logger);
-        return JK_TRUE;
-
-    }
-
-    JK_LOG_NULL_PARAMS(logger);
-    JK_TRACE_EXIT(logger);
-    return JK_FALSE;
-}
-
-/**
- * In the case of a Transfer-Encoding: chunked response, this will write the terminator chunk.
- */
-static int JK_METHOD iis_done(jk_ws_service_t *s)
-{
-    JK_TRACE_ENTER(logger);
-
-    if (s && s->ws_private) {
-        isapi_private_data_t *p = s->ws_private;
-
-        if (p->chunk_content == JK_FALSE) {
-            JK_TRACE_EXIT(logger);
-            return JK_TRUE;
-        }
-
-        /* Write last chunk + terminator */
-        if (iis_info.major >= 6) {
-            HSE_RESPONSE_VECTOR response_vector;
-            HSE_VECTOR_ELEMENT response_elements[1];
-
-            response_elements[0].ElementType = HSE_VECTOR_ELEMENT_TYPE_MEMORY_BUFFER;
-            response_elements[0].pvContext = CHUNKED_ENCODING_TRAILER;
-            response_elements[0].cbOffset = 0;
-            response_elements[0].cbSize = CHUNKED_ENCODING_TRAILER_LEN;
-
-            /* HSE_IO_FINAL_SEND lets IIS process the response to the client before we return */
-            response_vector.dwFlags = HSE_IO_SYNC | HSE_IO_FINAL_SEND;
-            response_vector.pszStatus = NULL;
-            response_vector.pszHeaders = NULL;
-            response_vector.nElementCount = 1;
-            response_vector.lpElementArray = response_elements;
-
-            if (JK_IS_DEBUG_LEVEL(logger))
-                jk_log(logger, JK_LOG_DEBUG,
-                       "Using vector write to terminate chunk encoded response.");
-
-            if (!p->lpEcb->ServerSupportFunction(p->lpEcb->ConnID,
-                                                 HSE_REQ_VECTOR_SEND,
-                                                 &response_vector,
-                                                 (LPDWORD)NULL,
-                                                 (LPDWORD)NULL)) {
-                    jk_log(logger, JK_LOG_ERROR,
-                           "Vector termination of chunk encoded response failed with %d (0x%08x)",
-                           GetLastError(), GetLastError());
-                    JK_TRACE_EXIT(logger);
-                    return JK_FALSE;
-            }
-        }
-        else {
-            if (JK_IS_DEBUG_LEVEL(logger))
-                jk_log(logger, JK_LOG_DEBUG, "Terminating chunk encoded response");
-
-            if (!isapi_write_client(p, CHUNKED_ENCODING_TRAILER, CHUNKED_ENCODING_TRAILER_LEN)) {
-                jk_log(logger, JK_LOG_ERROR,
-                       "WriteClient for chunked response terminator failed with %d (0x%08x)",
-                       GetLastError(), GetLastError());
-                JK_TRACE_EXIT(logger);
-                return JK_FALSE;
-            }
-        }
-
-        JK_TRACE_EXIT(logger);
-        return JK_TRUE;
-    }
-
-    JK_LOG_NULL_PARAMS(logger);
-    JK_TRACE_EXIT(logger);
-    return JK_FALSE;
-}
-
-BOOL WINAPI GetFilterVersion(PHTTP_FILTER_VERSION pVer)
-{
-    int rc;
-    BOOL rv = TRUE;
-    ULONG http_filter_revision = HTTP_FILTER_REVISION;
-
-    pVer->dwFilterVersion = pVer->dwServerFilterVersion;
-
-    if (pVer->dwFilterVersion > http_filter_revision) {
-        pVer->dwFilterVersion = http_filter_revision;
-    }
-    JK_ENTER_CS(&(init_cs), rc);
-    if (!is_inited) {
-        rv = initialize_extension();
-    }
-    JK_LEAVE_CS(&(init_cs), rc);
-    pVer->dwFlags = SF_NOTIFY_ORDER_HIGH |
-                    SF_NOTIFY_SECURE_PORT |
-                    SF_NOTIFY_NONSECURE_PORT |
-                    SF_NOTIFY_LOG |
-                    iis_info.filter_notify_event;
-
-    StringCbCopy(pVer->lpszFilterDesc, SF_MAX_FILTER_DESC_LEN, (VERSION_STRING));
-    return rv;
-}
-
-
-#define AP_REG_ICASE    0x01 /** use a case-insensitive match */
-#define AP_REG_NEWLINE  0x02 /** don't match newlines against '.' etc */
-#define AP_REG_NOTBOL   0x04 /** ^ will not match against start-of-string */
-#define AP_REG_NOTEOL   0x08 /** $ will not match against end-of-string */
-
-#define AP_REG_EXTENDED (0)  /** unused */
-#define AP_REG_NOSUB    (0)  /** unused */
-/** The max number of regex captures that can be expanded by ap_pregsub */
-#define AP_MAX_REG_MATCH 10
-
-/* Error values: */
-enum {
-    AP_REG_ASSERT = 1,  /** internal error ? */
-    AP_REG_ESPACE,      /** failed to get memory */
-    AP_REG_INVARG,      /** invalid argument */
-    AP_REG_NOMATCH      /** match failed */
-};
-
-/* The structure representing a compiled regular expression. */
-typedef struct {
-    void *re_pcre;
-    size_t re_nsub;
-    size_t re_erroffset;
-    const char *real;
-    const char *fake;
-} ap_regex_t;
-
-/* The structure in which a captured offset is returned. */
-typedef struct {
-    int rm_so;
-    int rm_eo;
-} ap_regmatch_t;
-
-
-/* Table of error strings corresponding to POSIX error codes; must be
- * kept in synch with include/ap_regex.h's AP_REG_E* definitions. */
-
-static const char *const pstring[] = {
-  "",                                /* Dummy for value 0 */
-  "internal error",                  /* AP_REG_ASSERT */
-  "failed to get memory",            /* AP_REG_ESPACE */
-  "bad argument",                    /* AP_REG_INVARG */
-  "match failed"                     /* AP_REG_NOMATCH */
-};
-
-static size_t ap_regerror(int errcode, const ap_regex_t *preg,
-                          char *errbuf, size_t errbuf_size)
-{
-    const char *message, *addmessage;
-    size_t length, addlength;
-
-    message = (errcode >= (int)(sizeof(pstring)/sizeof(char *))) ?
-                                "unknown error code" : pstring[errcode];
-    length = strlen(message) + 1;
-
-    addmessage = " at offset ";
-    addlength = (preg != NULL && (int)preg->re_erroffset != -1)?
-                                        strlen(addmessage) + 6 : 0;
-
-    if (errbuf_size > 0) {
-        if (addlength > 0 && errbuf_size >= length + addlength)
-            StringCbPrintf(errbuf, sizeof(errbuf), "%s%s%-6d",
-                          message, addmessage,
-                          (int)preg->re_erroffset);
-        else {
-            strncpy(errbuf, message, errbuf_size - 1);
-            errbuf[errbuf_size-1] = 0;
-        }
-    }
-
-    return length + addlength;
-}
-
-/*************************************************
- *           Free store held by a regex          *
- *************************************************/
-
-static void ap_regfree(ap_regex_t *preg)
-{
-    (pcre_free)(preg->re_pcre);
-}
-
-
-
-
-/*************************************************
- *            Compile a regular expression       *
- *************************************************/
-
-/*
-Arguments:
-  preg        points to a structure for recording the compiled expression
-  pattern     the pattern to compile
-  cflags      compilation flags
-
-Returns:      0 on success
-              various non-zero codes on failure
-*/
-
-static int ap_regcomp(ap_regex_t *preg, const char *pattern, int cflags)
-{
-    const char *errorptr;
-    int erroffset;
-    int options = 0;
-
-    if ((cflags & AP_REG_ICASE) != 0) options |= PCRE_CASELESS;
-    if ((cflags & AP_REG_NEWLINE) != 0) options |= PCRE_MULTILINE;
-
-    preg->re_pcre = pcre_compile(pattern, options, &errorptr, &erroffset, NULL);
-    preg->re_erroffset = erroffset;
-
-    if (preg->re_pcre == NULL) return AP_REG_INVARG;
-
-    preg->re_nsub = pcre_info((const pcre *)preg->re_pcre, NULL, NULL);
-    return 0;
-}
-
-/*************************************************
- *              Match a regular expression       *
- *************************************************/
-
-/* Unfortunately, PCRE requires 3 ints of working space for each captured
-substring, so we have to get and release working store instead of just using
-the POSIX structures as was done in earlier releases when PCRE needed only 2
-ints. However, if the number of possible capturing brackets is small, use a
-block of store on the stack, to reduce the use of malloc/free. The threshold is
-in a macro that can be changed at configure time. */
-
-static int ap_regexec(const ap_regex_t *preg, const char *string,
-                      int nmatch, ap_regmatch_t pmatch[],
-                      int eflags)
-{
-    int rc;
-    int options = 0;
-    int *ovector = NULL;
-    int small_ovector[POSIX_MALLOC_THRESHOLD * 3];
-    int allocated_ovector = 0;
-
-    if ((eflags & AP_REG_NOTBOL) != 0) options |= PCRE_NOTBOL;
-    if ((eflags & AP_REG_NOTEOL) != 0) options |= PCRE_NOTEOL;
-
-    ((ap_regex_t *)preg)->re_erroffset = (size_t)(-1);  /* Only has meaning after compile */
-
-    if (nmatch > 0) {
-        if (nmatch <= POSIX_MALLOC_THRESHOLD) {
-            ovector = &(small_ovector[0]);
-        }
-        else {
-            ovector = (int *)malloc(sizeof(int) * nmatch * 3);
-            if (ovector == NULL)
-                return AP_REG_ESPACE;
-            allocated_ovector = 1;
-        }
-    }
-
-    rc = pcre_exec((const pcre *)preg->re_pcre, NULL, string,
-                   (int)strlen(string),
-                    0, options, ovector, nmatch * 3);
-
-    if (rc == 0)
-        rc = nmatch;    /* All captured slots were filled in */
-    if (rc >= 0) {
-        int i;
-        for (i = 0; i < rc; i++) {
-            pmatch[i].rm_so = ovector[i*2];
-            pmatch[i].rm_eo = ovector[i*2+1];
-        }
-        if (allocated_ovector)
-            free(ovector);
-        for (; i < nmatch; i++)
-            pmatch[i].rm_so = pmatch[i].rm_eo = -1;
-        return 0;
-    }
-    else {
-        if (allocated_ovector)
-            free(ovector);
-        switch(rc) {
-            case PCRE_ERROR_NOMATCH: return AP_REG_NOMATCH;
-            case PCRE_ERROR_NULL: return AP_REG_INVARG;
-            case PCRE_ERROR_BADOPTION: return AP_REG_INVARG;
-            case PCRE_ERROR_BADMAGIC: return AP_REG_INVARG;
-            case PCRE_ERROR_UNKNOWN_NODE: return AP_REG_ASSERT;
-            case PCRE_ERROR_NOMEMORY: return AP_REG_ESPACE;
-#ifdef PCRE_ERROR_MATCHLIMIT
-            case PCRE_ERROR_MATCHLIMIT: return AP_REG_ESPACE;
-#endif
-#ifdef PCRE_ERROR_BADUTF8
-            case PCRE_ERROR_BADUTF8: return AP_REG_INVARG;
-#endif
-#ifdef PCRE_ERROR_BADUTF8_OFFSET
-            case PCRE_ERROR_BADUTF8_OFFSET: return AP_REG_INVARG;
-#endif
-            default: return AP_REG_ASSERT;
-        }
-    }
-}
-
-/* This function substitutes for $0-$9, filling in regular expression
- * submatches. Pass it the same nmatch and pmatch arguments that you
- * passed ap_regexec(). pmatch should not be greater than the maximum number
- * of subexpressions - i.e. one more than the re_nsub member of ap_regex_t.
- *
- * input should be the string with the $-expressions, source should be the
- * string that was matched against.
- *
- * It returns the substituted string, or NULL on error.
- *
- * Parts of this code are based on Henry Spencer's regsub(), from his
- * AT&T V8 regexp package.
- */
-
-static char *ap_pregsub(const char *input,
-                        const char *source, size_t nmatch,
-                        ap_regmatch_t pmatch[])
-{
-    const char *src = input;
-    char *dest, *dst;
-    char c;
-    size_t no;
-    int len;
-
-    if (!source)
-        return NULL;
-    if (!nmatch)
-        return strdup(src);
-
-    /* First pass, find the size */
-    len = 0;
-
-    while ((c = *src++) != '\0') {
-        if (c == '&')
-            no = 0;
-        else if (c == '$' && isdigit((unsigned char)*src))
-            no = *src++ - '0';
-        else
-            no = 10;
-
-        if (no > 9) {                /* Ordinary character. */
-            if (c == '\\' && (*src == '$' || *src == '&'))
-                c = *src++;
-            len++;
-        }
-        else if (no < nmatch && pmatch[no].rm_so < pmatch[no].rm_eo) {
-            len += pmatch[no].rm_eo - pmatch[no].rm_so;
-        }
-
-    }
-
-    dest = dst = calloc(1, len + 1);
-
-    /* Now actually fill in the string */
-
-    src = input;
-
-    while ((c = *src++) != '\0') {
-        if (c == '&')
-            no = 0;
-        else if (c == '$' && isdigit((unsigned char)*src))
-            no = *src++ - '0';
-        else
-            no = 10;
-
-        if (no > 9) {                /* Ordinary character. */
-            if (c == '\\' && (*src == '$' || *src == '&'))
-                c = *src++;
-            *dst++ = c;
-        }
-        else if (no < nmatch && pmatch[no].rm_so < pmatch[no].rm_eo) {
-            len = pmatch[no].rm_eo - pmatch[no].rm_so;
-            memcpy(dst, source + pmatch[no].rm_so, len);
-            dst += len;
-        }
-
-    }
-    *dst = '\0';
-    return dest;
-}
-
-static int simple_rewrite(char *uri)
-{
-    if (rewrite_map) {
-        int i;
-        char buf[INTERNET_MAX_URL_LENGTH];
-        for (i = 0; i < jk_map_size(rewrite_map); i++) {
-            const char *src = jk_map_name_at(rewrite_map, i);
-            if (*src == '~')
-                continue;   /* Skip regexp rewrites */
-            if (strncmp(uri, src, strlen(src)) == 0) {
-                StringCbCopy(buf, INTERNET_MAX_URL_LENGTH, jk_map_value_at(rewrite_map, i));
-                StringCbCat(buf,  INTERNET_MAX_URL_LENGTH, uri + strlen(src));
-                StringCbCopy(uri, INTERNET_MAX_URL_LENGTH, buf);
-                return 1;
-            }
-        }
-    }
-    return 0;
-}
-
-static int rregex_rewrite(char *uri)
-{
-    ap_regmatch_t regm[AP_MAX_REG_MATCH];
-
-    if (rregexp_map) {
-        int i;
-        for (i = 0; i < jk_map_size(rregexp_map); i++) {
-            ap_regex_t *regexp = (ap_regex_t *)jk_map_value_at(rregexp_map, i);
-            if (!ap_regexec(regexp, uri, AP_MAX_REG_MATCH, regm, 0)) {
-                char *subs = ap_pregsub(regexp->fake, uri,
-                                       AP_MAX_REG_MATCH, regm);
-                if (subs) {
-                    char buf[INTERNET_MAX_URL_LENGTH];
-                    size_t diffsz = strlen(subs) - (regm[0].rm_eo - regm[0].rm_so);
-                    memcpy(&buf[0], uri, regm[0].rm_so);
-                    StringCbCopy(&buf[regm[0].rm_so], INTERNET_MAX_URL_LENGTH - regm[0].rm_so, subs);
-                    StringCbCat(&buf[0], INTERNET_MAX_URL_LENGTH, uri + regm[0].rm_eo);
-                    StringCbCopy(uri, INTERNET_MAX_URL_LENGTH, &buf[0]);
-                    free(subs);
-                    return 1;
-                }
-            }
-        }
-    }
-    return 0;
-}
-
-DWORD WINAPI HttpFilterProc(PHTTP_FILTER_CONTEXT pfc,
-                            DWORD dwNotificationType, LPVOID pvNotification)
-{
-    int rc;
-
-    /* Initialise jk */
-    if (is_inited && !is_mapread) {
-        char serverName[MAX_SERVERNAME] = "";
-        char instanceId[MAX_INSTANCEID] = "";
-        DWORD dwLen = MAX_SERVERNAME - MAX_INSTANCEID - 1;
-
-        if (pfc->GetServerVariable(pfc, SERVER_NAME, serverName, &dwLen)) {
-            if (dwLen > 0) {
-                serverName[dwLen - 1] = '\0';
-                dwLen = MAX_INSTANCEID;
-                if (pfc->GetServerVariable(pfc, INSTANCE_ID, instanceId, &dwLen)) {
-                    if (dwLen > 0) {
-                        instanceId[dwLen - 1] = '\0';
-                        StringCbCat(serverName, MAX_SERVERNAME, "_");
-                        StringCbCat(serverName, MAX_SERVERNAME, instanceId);
-                    }
-                }
-            }
-            JK_ENTER_CS(&(init_cs), rc);
-            if (!is_mapread && init_jk(serverName))
-                is_mapread = JK_TRUE;
-            JK_LEAVE_CS(&(init_cs), rc);
-        }
-        /* If we can't read the map we become dormant */
-        if (!is_mapread)
-            is_inited = JK_FALSE;
-    }
-    if (!is_inited) {
-        /* In case the initialization failed
-         * return error. This will make entire IIS
-         * unusable like with Apache servers
-         */
-         SetLastError(ERROR_INVALID_FUNCTION);
-         return SF_STATUS_REQ_ERROR;
-    }
-    if (iis_info.filter_notify_event == dwNotificationType) {
-        char uri[INTERNET_MAX_URL_LENGTH];
-        char snuri[INTERNET_MAX_URL_LENGTH] = "/";
-        char Host[INTERNET_MAX_URL_LENGTH] = "";
-        char Port[INTERNET_MAX_URL_LENGTH] = "";
-        char Translate[INTERNET_MAX_URL_LENGTH];
-        char squery[INTERNET_MAX_URL_LENGTH] = "";
-        char swindex[MAX_INSTANCEID] = "";
-        BOOL(WINAPI * GetHeader)
-            (struct _HTTP_FILTER_CONTEXT * pfc, LPSTR lpszName,
-             LPVOID lpvBuffer, LPDWORD lpdwSize);
-        BOOL(WINAPI * SetHeader)
-            (struct _HTTP_FILTER_CONTEXT * pfc, LPSTR lpszName,
-             LPSTR lpszValue);
-        BOOL(WINAPI * AddHeader)
-            (struct _HTTP_FILTER_CONTEXT * pfc, LPSTR lpszName,
-             LPSTR lpszValue);
-        char *query;
-        DWORD sz = sizeof(uri);
-        DWORD szHost = sizeof(Host);
-        DWORD szPort = sizeof(Port);
-        DWORD szTranslate = sizeof(Translate);
-
-        if (iis_info.filter_notify_event == SF_NOTIFY_AUTH_COMPLETE) {
-            GetHeader =
-                ((PHTTP_FILTER_AUTH_COMPLETE_INFO) pvNotification)->GetHeader;
-            SetHeader =
-                ((PHTTP_FILTER_AUTH_COMPLETE_INFO) pvNotification)->SetHeader;
-            AddHeader =
-                ((PHTTP_FILTER_AUTH_COMPLETE_INFO) pvNotification)->AddHeader;
-        }
-        else {
-            GetHeader =
-                ((PHTTP_FILTER_PREPROC_HEADERS) pvNotification)->GetHeader;
-            SetHeader =
-                ((PHTTP_FILTER_PREPROC_HEADERS) pvNotification)->SetHeader;
-            AddHeader =
-                ((PHTTP_FILTER_PREPROC_HEADERS) pvNotification)->AddHeader;
-        }
-
-        if (JK_IS_DEBUG_LEVEL(logger))
-            jk_log(logger, JK_LOG_DEBUG, "Filter started");
-
-        /*
-         * Just in case somebody set these headers in the request!
-         */
-        SetHeader(pfc, URI_HEADER_NAME, NULL);
-        SetHeader(pfc, QUERY_HEADER_NAME, NULL);
-        SetHeader(pfc, WORKER_HEADER_NAME, NULL);
-        SetHeader(pfc, WORKER_HEADER_INDEX, NULL);
-        SetHeader(pfc, TOMCAT_TRANSLATE_HEADER_NAME, NULL);
-
-        // Suppress logging of original uri/query when we don't map a URL
-        if (pfc->pFilterContext) {
-            isapi_log_data_t *ld = (isapi_log_data_t *)pfc->pFilterContext;
-            ld->request_matched = JK_FALSE;
-        }
-
-        if (!GetHeader(pfc, "url", (LPVOID) uri, (LPDWORD) & sz)) {
-            jk_log(logger, JK_LOG_ERROR,
-                   "error while getting the url");
-            return SF_STATUS_REQ_ERROR;
-        }
-
-        if (strlen(uri)) {
-            int rc;
-            const char *worker = NULL;
-            rule_extension_t *extensions;
-            int worker_index = -1;
-            query = strchr(uri, '?');
-            if (query) {
-                *query++ = '\0';
-                StringCbCopy(squery, INTERNET_MAX_URL_LENGTH, query);
-            }
-
-            rc = unescape_url(uri);
-            if (rc == BAD_REQUEST) {
-                jk_log(logger, JK_LOG_ERROR,
-                       "[%s] contains one or more invalid escape sequences.",
-                       uri);
-                write_error_response(pfc, 400);
-                return SF_STATUS_REQ_FINISHED;
-            }
-            else if (rc == BAD_PATH) {
-                jk_log(logger, JK_LOG_EMERG,
-                       "[%s] contains forbidden escape sequences.",
-                       uri);
-                write_error_response(pfc, 404);
-                return SF_STATUS_REQ_FINISHED;
-            }
-            getparents(uri);
-            if (pfc->
-                GetServerVariable(pfc, SERVER_NAME, (LPVOID) Host,
-                                  (LPDWORD) & szHost)) {
-                if (szHost > 0) {
-                    Host[szHost - 1] = '\0';
-                }
-            }
-            Port[0] = '\0';
-            if (pfc->
-                GetServerVariable(pfc, "SERVER_PORT", (LPVOID) Port,
-                                  (LPDWORD) & szPort)) {
-                if (szPort > 0) {
-                    Port[szPort - 1] = '\0';
-                }
-            }
-            szPort = atoi(Port);
-            if (szPort != 80 && szPort != 443 && szHost > 0) {
-                StringCbCat(Host, INTERNET_MAX_URL_LENGTH, ":");
-                StringCbCat(Host, INTERNET_MAX_URL_LENGTH, Port);
-            }
-            if (szHost > 0) {
-                StringCbCat(snuri, INTERNET_MAX_URL_LENGTH, Host);
-                worker = map_uri_to_worker_ext(uw_map, uri, snuri,
-                                               &extensions, &worker_index, logger);
-            }
-            else {
-                worker = map_uri_to_worker_ext(uw_map, uri, NULL,
-                                               &extensions, &worker_index, logger);
-            }
-            /*
-             * Check if somebody is feading us with his own TOMCAT data headers.
-             * We reject such postings !
-             */
-            if (worker) {
-                char *forwardURI;
-
-                if (JK_IS_DEBUG_LEVEL(logger))
-                    jk_log(logger, JK_LOG_DEBUG,
-                           "check if [%s] points to the web-inf directory",
-                        uri);
-
-                if (uri_is_web_inf(uri)) {
-                    jk_log(logger, JK_LOG_EMERG,
-                           "[%s] points to the web-inf or meta-inf directory. "
-                           "Somebody tries to hack into the site!!!",
-                           uri);
-
-                    write_error_response(pfc, 404);
-                    return SF_STATUS_REQ_FINISHED;
-                }
-
-                /* This is a servlet, should redirect ... */
-                if (JK_IS_DEBUG_LEVEL(logger))
-                    jk_log(logger, JK_LOG_DEBUG,
-                        "[%s] is a servlet url - should redirect to %s",
-                        uri, worker);
-
-                /* get URI we should forward */
-                if (uri_select_option == URI_SELECT_OPT_UNPARSED) {
-                    /* get original unparsed URI */
-                    GetHeader(pfc, "url", (LPVOID) uri, (LPDWORD) & sz);
-                    /* restore terminator for uri portion */
-                    if (query)
-                        *(query - 1) = '\0';
-                    if (JK_IS_DEBUG_LEVEL(logger))
-                        jk_log(logger, JK_LOG_DEBUG,
-                               "forwarding original URI [%s]",
-                               uri);
-                    forwardURI = uri;
-                }
-                else if (uri_select_option == URI_SELECT_OPT_ESCAPED) {
-                    if (!escape_url(uri, snuri, INTERNET_MAX_URL_LENGTH)) {
-                        jk_log(logger, JK_LOG_ERROR,
-                               "[%s] re-encoding request exceeds maximum buffer size.",
-                               uri);
-                        write_error_response(pfc, 400);
-                        return SF_STATUS_REQ_FINISHED;
-                    }
-                    if (JK_IS_DEBUG_LEVEL(logger))
-                        jk_log(logger, JK_LOG_DEBUG,
-                               "fowarding escaped URI [%s]",
-                               snuri);
-                    forwardURI = snuri;
-                }
-                else if (uri_select_option == URI_SELECT_OPT_PROXY) {
-                    if (!jk_canonenc(uri, snuri, INTERNET_MAX_URL_LENGTH)) {
-                        jk_log(logger, JK_LOG_ERROR,
-                               "[%s] re-encoding request exceeds maximum buffer size.",
-                               uri);
-                        write_error_response(pfc, 400);
-                        return SF_STATUS_REQ_FINISHED;
-                    }
-                    if (JK_IS_DEBUG_LEVEL(logger))
-                        jk_log(logger, JK_LOG_DEBUG,
-                               "fowarding escaped URI [%s]",
-                               snuri);
-                    forwardURI = snuri;
-                }
-                else {
-                    forwardURI = uri;
-                }
-                /* Do a simple rewrite .
-                 * Note that URI can be escaped, so thus the rule has
-                 * to be in that case.
-                 *
-                 * TODO: Add more advanced regexp rewrite.
-                 */
-                if (JK_IS_DEBUG_LEVEL(logger)) {
-                    char duri[INTERNET_MAX_URL_LENGTH];
-                    StringCbCopy(duri, INTERNET_MAX_URL_LENGTH, forwardURI);
-                    if (simple_rewrite(forwardURI)) {
-                        jk_log(logger, JK_LOG_DEBUG,
-                               "rewritten URI [%s]->[%s]",
-                               duri, forwardURI);
-                    }
-                    else if (rregex_rewrite(forwardURI)) {
-                        jk_log(logger, JK_LOG_DEBUG,
-                               "rewritten URI [%s]->[%s]",
-                               duri, forwardURI);
-                    }
-                }
-                else {
-                    if (!simple_rewrite(forwardURI))
-                        rregex_rewrite(forwardURI);
-                }
-
-                itoa(worker_index, swindex, 10);
-                if (!AddHeader(pfc, URI_HEADER_NAME, forwardURI) ||
-                    ((strlen(squery) > 0)
-                     ? !AddHeader(pfc, QUERY_HEADER_NAME, squery) : FALSE) ||
-                    !AddHeader(pfc, WORKER_HEADER_NAME, (LPSTR)worker) ||
-                    !AddHeader(pfc, WORKER_HEADER_INDEX, swindex) ||
-                    !SetHeader(pfc, "url", extension_uri)) {
-                    jk_log(logger, JK_LOG_ERROR,
-                           "error while adding request headers");
-                    SetLastError(ERROR_INVALID_PARAMETER);
-                    return SF_STATUS_REQ_ERROR;
-                }
-
-                /* Move Translate: header to a temporary header so
-                 * that the extension proc will be called.
-                 * This allows the servlet to handle 'Translate: f'.
-                 */
-                if (GetHeader
-                    (pfc, TRANSLATE_HEADER, (LPVOID) Translate,
-                     (LPDWORD) & szTranslate) && Translate != NULL
-                    && szTranslate > 0) {
-                    if (!AddHeader
-                        (pfc, TOMCAT_TRANSLATE_HEADER_NAME, Translate)) {
-                        jk_log(logger, JK_LOG_ERROR,
-                               "error while adding Tomcat-Translate headers");
-                        return SF_STATUS_REQ_ERROR;
-                    }
-                    SetHeader(pfc, "Translate:", NULL);
-                }
-                if (!pfc->pFilterContext) {
-                    isapi_log_data_t *ld = (isapi_log_data_t *)pfc->AllocMem(pfc, sizeof(isapi_log_data_t), 0);
-                    if (!ld) {
-                        jk_log(logger, JK_LOG_ERROR,
-                               "error while allocating memory");
-                        SetLastError(ERROR_NOT_ENOUGH_MEMORY);
-                        return SF_STATUS_REQ_ERROR;
-                    }
-                    memset(ld, 0, sizeof(isapi_log_data_t));
-                    StringCbCopy(ld->uri, INTERNET_MAX_URL_LENGTH, forwardURI);
-                    StringCbCopy(ld->query, INTERNET_MAX_URL_LENGTH, squery);
-                    ld->request_matched = JK_TRUE;
-                    pfc->pFilterContext = ld;
-                } else {
-                    isapi_log_data_t *ld = (isapi_log_data_t *)pfc->pFilterContext;
-                    memset(ld, 0, sizeof(isapi_log_data_t));
-                    StringCbCopy(ld->uri, INTERNET_MAX_URL_LENGTH, forwardURI);
-                    StringCbCopy(ld->query, INTERNET_MAX_URL_LENGTH, squery);
-                    ld->request_matched = JK_TRUE;
-                }
-            }
-            else {
-                if (JK_IS_DEBUG_LEVEL(logger))
-                    jk_log(logger, JK_LOG_DEBUG,
-                           "[%s] is not a servlet url", uri);
-                if (strip_session) {
-                    char *jsessionid = strstr(uri, JK_PATH_SESSION_IDENTIFIER);
-                    if (jsessionid) {
-                        if (JK_IS_DEBUG_LEVEL(logger))
-                            jk_log(logger, JK_LOG_DEBUG,
-                                   "removing session identifier [%s] for non servlet url [%s]",
-                                   jsessionid, uri);
-                        *jsessionid = '\0';
-                        SetHeader(pfc, "url", uri);
-                    }
-                }
-            }
-        }
-    }
-    else if (dwNotificationType == SF_NOTIFY_LOG) {
-        if (pfc->pFilterContext) {
-            isapi_log_data_t *ld = (isapi_log_data_t *)pfc->pFilterContext;
-            if (ld->request_matched) {
-                HTTP_FILTER_LOG  *pl = (HTTP_FILTER_LOG *)pvNotification;
-                pl->pszTarget = ld->uri;
-                pl->pszParameters = ld->query;
-            }
-        }
-    }
-    return SF_STATUS_REQ_NEXT_NOTIFICATION;
-}
-
-
-BOOL WINAPI GetExtensionVersion(HSE_VERSION_INFO * pVer)
-{
-    int rc;
-    BOOL rv = TRUE;
-
-    pVer->dwExtensionVersion = MAKELONG(HSE_VERSION_MINOR, HSE_VERSION_MAJOR);
-
-    StringCbCopy(pVer->lpszExtensionDesc, HSE_MAX_EXT_DLL_NAME_LEN, (VERSION_STRING));
-
-
-    JK_ENTER_CS(&(init_cs), rc);
-    if (!is_inited) {
-        rv = initialize_extension();
-    }
-    JK_LEAVE_CS(&(init_cs), rc);
-
-    return rv;
-}
-
-DWORD WINAPI HttpExtensionProc(LPEXTENSION_CONTROL_BLOCK lpEcb)
-{
-    int rv;
-    DWORD rc = HSE_STATUS_ERROR;
-
-    lpEcb->dwHttpStatusCode = HTTP_STATUS_SERVER_ERROR;
-
-    JK_TRACE_ENTER(logger);
-
-    /* Initialise jk */
-    if (is_inited && !is_mapread) {
-        char serverName[MAX_SERVERNAME] = "";
-        char instanceId[MAX_INSTANCEID] = "";
-
-        DWORD dwLen = MAX_SERVERNAME - MAX_INSTANCEID - 1;
-        if (lpEcb->GetServerVariable(lpEcb->ConnID,
-                    SERVER_NAME, serverName, &dwLen)) {
-            if (dwLen > 0) {
-                serverName[dwLen - 1] = '\0';
-                dwLen = MAX_INSTANCEID;
-                if (lpEcb->GetServerVariable(lpEcb->ConnID,
-                            INSTANCE_ID, instanceId, &dwLen)) {
-                    if (dwLen > 0) {
-                        instanceId[dwLen - 1] = '\0';
-                        StringCbCat(serverName, MAX_SERVERNAME, "_");
-                        StringCbCat(serverName, MAX_SERVERNAME, instanceId);
-                    }
-                }
-            }
-            JK_ENTER_CS(&(init_cs), rv);
-            if (!is_mapread && init_jk(serverName))
-                is_mapread = JK_TRUE;
-            JK_LEAVE_CS(&(init_cs), rv);
-        }
-        if (!is_mapread)
-            is_inited = JK_FALSE;
-    }
-
-    if (is_inited) {
-        isapi_private_data_t private_data;
-        jk_ws_service_t s;
-        jk_pool_atom_t buf[SMALL_POOL_SIZE];
-        char *worker_name;
-
-        if (!watchdog_interval)
-            wc_maintain(logger);
-        jk_init_ws_service(&s);
-        jk_open_pool(&private_data.p, buf, sizeof(buf));
-
-        private_data.bytes_read_so_far = 0;
-        private_data.lpEcb = lpEcb;
-        private_data.chunk_content = JK_FALSE;
-
-        s.ws_private = &private_data;
-        s.pool = &private_data.p;
-
-        if (init_ws_service(&private_data, &s, &worker_name)) {
-            jk_worker_t *worker = wc_get_worker_for_name(worker_name, logger);
-
-            if (JK_IS_DEBUG_LEVEL(logger))
-                jk_log(logger, JK_LOG_DEBUG,
-                       "%s a worker for name %s",
-                       worker ? "got" : "could not get", worker_name);
-
-            if (worker) {
-                jk_endpoint_t *e = NULL;
-                if (worker->get_endpoint(worker, &e, logger)) {
-                    int is_error = JK_HTTP_SERVER_ERROR;
-                    int result;
-                    if ((result = e->service(e, &s, logger, &is_error)) > 0) {
-                        if (s.extension.use_server_error_pages &&
-                            s.http_response_status >= s.extension.use_server_error_pages) {
-                            if (JK_IS_DEBUG_LEVEL(logger))
-                                jk_log(logger, JK_LOG_DEBUG, "Forwarding status=%d"
-                                       " for worker=%s",
-                                       s.http_response_status, worker_name);
-                            lpEcb->dwHttpStatusCode = s.http_response_status;
-                            write_error_message(lpEcb, s.http_response_status);
-                        }
-                        else {
-                            rc = HSE_STATUS_SUCCESS;
-                            lpEcb->dwHttpStatusCode = s.http_response_status;
-                            if (JK_IS_DEBUG_LEVEL(logger))
-                                jk_log(logger, JK_LOG_DEBUG,
-                                       "service() returned OK");
-                        }
-                    }
-                    else {
-                        if ((result == JK_CLIENT_ERROR) && (is_error == JK_HTTP_OK)) {
-                            jk_log(logger, JK_LOG_INFO,
-                                   "service() failed because client aborted connection");
-                        }
-                        else {
-                            jk_log(logger, JK_LOG_ERROR,
-                                   "service() failed with http error %d", is_error);
-                        }
-                        lpEcb->dwHttpStatusCode = is_error;
-                        write_error_message(lpEcb, is_error);
-                    }
-                    e->done(&e, logger);
-                }
-                else {
-                    jk_log(logger, JK_LOG_ERROR,
-                        "Failed to obtain an endpoint to service request - "
-                        "your connection_pool_size is probably less than the threads in your web server!");
-                }
-            }
-            else {
-                jk_log(logger, JK_LOG_ERROR,
-                       "could not get a worker for name %s",
-                       worker_name);
-            }
-        }
-        else {
-            jk_log(logger, JK_LOG_ERROR,
-                "failed to init service for request.");
-         }
-        jk_close_pool(&private_data.p);
-    }
-    else {
-        jk_log(logger, JK_LOG_ERROR,
-               "not initialized");
-    }
-
-    JK_TRACE_EXIT(logger);
-    return rc;
-}
-
-
-
-BOOL WINAPI TerminateExtension(DWORD dwFlags)
-{
-    return TerminateFilter(dwFlags);
-}
-
-BOOL WINAPI TerminateFilter(DWORD dwFlags)
-{
-    int rc;
-
-    UNREFERENCED_PARAMETER(dwFlags);
-
-    JK_ENTER_CS(&(init_cs), rc);
-    if (is_inited) {
-        jk_log(logger, JK_LOG_INFO, "%s stopping", (FULL_VERSION_STRING));
-        is_inited = JK_FALSE;
-        watchdog_interval = 0;
-        if (watchdog_handle) {
-            WaitForSingleObject(watchdog_handle, INFINITE);
-            CloseHandle(watchdog_handle);
-            watchdog_handle = NULL;
-        }
-        if (is_mapread) {
-            uri_worker_map_free(&uw_map, logger);
-            is_mapread = JK_FALSE;
-        }
-        if (workers_map) {
-            jk_map_free(&workers_map);
-        }
-        if (rewrite_map) {
-            jk_map_free(&rewrite_map);
-        }
-        if (rregexp_map) {
-            int i;
-            for (i = 0; i < jk_map_size(rregexp_map); i++) {
-                ap_regex_t *regexp = (ap_regex_t *)jk_map_value_at(rregexp_map, i);
-                if (regexp) {
-                    ap_regfree(regexp);
-                    free(regexp);
-                }
-            }
-            jk_map_free(&rregexp_map);
-        }
-        wc_close(logger);
-        jk_shm_close();
-        JK_ENTER_CS(&(log_cs), rc);
-        if (logger) {
-            jk_close_file_logger(&logger);
-        }
-        JK_LEAVE_CS(&(log_cs), rc);
-    }
-    JK_LEAVE_CS(&(init_cs), rc);
-
-    return TRUE;
-}
-
-
-BOOL WINAPI DllMain(HINSTANCE hInst,    // Instance Handle of the DLL
-                    ULONG ulReason,     // Reason why NT called this DLL
-                    LPVOID lpReserved)  // Reserved parameter for future use
-{
-    int rc;
-    BOOL fReturn = TRUE;
-    char fname[MAX_PATH];
-
-    UNREFERENCED_PARAMETER(lpReserved);
-
-    switch (ulReason) {
-    case DLL_PROCESS_ATTACH:
-        if (GetModuleFileName(hInst, fname, sizeof(fname))) {
-            char *p = strrchr(fname, '.');
-            if (p) {
-                *p = '\0';
-                StringCbCopy(ini_file_name, MAX_PATH, fname);
-                StringCbCat(ini_file_name, MAX_PATH, ".properties");
-            }
-            else {
-                /* Cannot obtain file name ? */
-                fReturn = JK_FALSE;
-            }
-            if ((p = strrchr(fname, '\\'))) {
-                *(p++) = '\0';
-                StringCbCopy(dll_file_path, MAX_PATH, fname);
-                jk_map_alloc(&jk_environment_map);
-                jk_map_add(jk_environment_map, "JKISAPI_PATH", dll_file_path);
-                jk_map_add(jk_environment_map, "JKISAPI_NAME", p);
-            }
-            else {
-                /* Cannot obtain file name ? */
-                fReturn = JK_FALSE;
-            }
-        }
-        else {
-            fReturn = JK_FALSE;
-        }
-        /* Construct redirector headers to use for this redirector instance */
-        StringCbPrintf(URI_HEADER_NAME, MAX_PATH, HEADER_TEMPLATE, URI_HEADER_NAME_BASE, hInst);
-        StringCbPrintf(QUERY_HEADER_NAME, MAX_PATH, HEADER_TEMPLATE, QUERY_HEADER_NAME_BASE, hInst);
-        StringCbPrintf(WORKER_HEADER_NAME, MAX_PATH, HEADER_TEMPLATE, WORKER_HEADER_NAME_BASE, hInst);
-        StringCbPrintf(WORKER_HEADER_INDEX, MAX_PATH, HEADER_TEMPLATE, WORKER_HEADER_INDEX_BASE, hInst);
-        StringCbPrintf(TOMCAT_TRANSLATE_HEADER_NAME, MAX_PATH, HEADER_TEMPLATE, TOMCAT_TRANSLATE_HEADER_NAME_BASE, hInst);
-
-        /* Construct the HTTP_ headers that will be seen in ExtensionProc */
-        StringCbPrintf(HTTP_URI_HEADER_NAME, MAX_PATH, HTTP_HEADER_TEMPLATE, URI_HEADER_NAME_BASE, hInst);
-        StringCbPrintf(HTTP_QUERY_HEADER_NAME, MAX_PATH, HTTP_HEADER_TEMPLATE, QUERY_HEADER_NAME_BASE, hInst);
-        StringCbPrintf(HTTP_WORKER_HEADER_NAME, MAX_PATH, HTTP_HEADER_TEMPLATE, WORKER_HEADER_NAME_BASE, hInst);
-        StringCbPrintf(HTTP_WORKER_HEADER_INDEX, MAX_PATH, HTTP_HEADER_TEMPLATE, WORKER_HEADER_INDEX_BASE, hInst);
-
-        JK_INIT_CS(&init_cs, rc);
-        JK_INIT_CS(&log_cs, rc);
-
-    break;
-    case DLL_PROCESS_DETACH:
-        __try {
-            TerminateFilter(HSE_TERM_MUST_UNLOAD);
-        }
-        __except(1) {
-        }
-        JK_DELETE_CS(&init_cs, rc);
-        JK_DELETE_CS(&log_cs, rc);
-        break;
-
-    default:
-        break;
-    }
-
-    return fReturn;
-}
-
-static DWORD WINAPI watchdog_thread(void *param)
-{
-    int i;
-    if (JK_IS_DEBUG_LEVEL(logger)) {
-        jk_log(logger, JK_LOG_DEBUG,
-               "Watchdog thread initialized with %u second interval",
-               watchdog_interval);
-    }
-    while (watchdog_interval) {
-        for (i = 0; i < (watchdog_interval * 10); i++) {
-            if (!watchdog_interval)
-                break;
-            Sleep(100);
-        }
-        if (!watchdog_interval)
-            break;
-        if (JK_IS_DEBUG_LEVEL(logger)) {
-            jk_log(logger, JK_LOG_DEBUG,
-                   "Watchdog thread running");
-        }
-        if (worker_mount_file[0]) {
-            jk_shm_lock();
-            uri_worker_map_update(uw_map, 0, logger);
-            jk_shm_unlock();
-        }
-        wc_maintain(logger);
-    }
-    if (JK_IS_DEBUG_LEVEL(logger)) {
-        jk_log(logger, JK_LOG_DEBUG,
-               "Watchdog thread finished");
-    }
-    return 0;
-}
-
-/*
- * Reinitializes the logger, formatting the log file name if rotation is enabled,
- * and calculating the next rotation time if applicable.
- */
-static int init_logger(int rotate, jk_logger_t **l)
-{
-    int rc = JK_TRUE;
-    int log_open = rotate;  /* log is assumed open if a rotate is requested */
-    char *log_file_name;
-    char log_file_name_buf[MAX_PATH*2];
-
-    /* If log rotation is enabled, format the log filename */
-    if ((log_rotationtime > 0) || (log_filesize > 0)) {
-        time_t t;
-        t = time(NULL);
-
-        if (log_rotationtime > 0) {
-            /* Align time to rotationtime intervals */
-            t = (t / log_rotationtime) * log_rotationtime;
-
-            /* Calculate rotate time */
-            log_next_rotate_time = t + log_rotationtime;
-        }
-
-        log_file_name = log_file_name_buf;
-        if (strchr(log_file, '%')) {
-            struct tm *tm_now;
-
-            /* If there are %s in the log file name, treat it as a sprintf format */
-            tm_now = localtime(&t);
-            strftime(log_file_name, sizeof(log_file_name_buf), log_file, tm_now);
-        } else {
-            /* Otherwise append the number of seconds to the base name */
-            StringCbPrintf(log_file_name, sizeof(log_file_name_buf), "%s.%d", log_file, (long)t);
-        }
-    } else {
-        log_file_name = log_file;
-    }
-
-    /* Close the current log file if required, and the effective log file name has changed */
-    if (log_open && strncmp(log_file_name, log_file_effective, strlen(log_file_name)) != 0) {
-        FILE* lf = ((jk_file_logger_t* )logger->logger_private)->logfile;
-        fprintf(lf, "Log rotated to %s\r\n", log_file_name);
-        fflush(lf);
-        rc = jk_close_file_logger(&logger);
-        log_open = JK_FALSE;
-    }
-
-    if (!log_open) {
-        if (jk_open_file_logger(&logger, log_file_name, log_level)) {
-            logger->log = iis_log_to_file;
-
-            /* Remember the current log file name for the next potential rotate */
-            StringCbCopy(log_file_effective, sizeof(log_file_effective), log_file_name);
-            rc = JK_TRUE;
-        } else {
-            logger = NULL;
-            rc = JK_FALSE;
-        }
-    }
-
-    /* Update logger being used for this log call so it occurs on new file */
-    (*l) = logger;
-    return rc;
-}
-
-/*
- * Checks whether the log needs to be rotated. Must be called while holding the log lock.
- * The behaviour here is based on the Apache rotatelogs program.
- * http://httpd.apache.org/docs/2.0/programs/rotatelogs.html
- */
-static int JK_METHOD rotate_log_file(jk_logger_t **l)
-{
-    int rc = JK_TRUE;
-    int rotate = JK_FALSE;
-
-    if (log_rotationtime > 0) {
-        time_t t = time(NULL);
-
-        if (t >= log_next_rotate_time) {
-            rotate = JK_TRUE;
-        }
-    } else if (log_filesize > 0) {
-        LARGE_INTEGER filesize;
-        HANDLE h = (HANDLE)_get_osfhandle(fileno(((jk_file_logger_t *)(*l)->logger_private)->logfile));
-        GetFileSizeEx(h, &filesize);
-
-        if ((ULONGLONG)filesize.QuadPart >= log_filesize) {
-            rotate = JK_TRUE;
-        }
-    }
-    if (rotate) {
-        rc = init_logger(JK_TRUE, l);
-    }
-    return rc;
-}
-
-/*
- * Log messages to the log file, rotating the log when required.
- */
-static int JK_METHOD iis_log_to_file(jk_logger_t *l, int level,
-                                    int used, char *what)
-{
-    int rc = JK_FALSE;
-
-    if (l &&
-        (l->level <= level || level == JK_LOG_REQUEST_LEVEL) &&
-        l->logger_private && what && used > 0) {
-        jk_file_logger_t *p = l->logger_private;
-        rc = JK_TRUE;
-
-        if (p->logfile) {
-            what[used++] = '\r';
-            what[used++] = '\n';
-            what[used] = '\0';
-
-            /* Perform logging within critical section to protect rotation */
-            JK_ENTER_CS(&(log_cs), rc);
-            if (rc && rotate_log_file(&l)) {
-                /* The rotation process will reallocate the jk_logger_t structure, so refetch */
-                FILE *rotated = ((jk_file_logger_t *)l->logger_private)->logfile;
-                fputs(what, rotated);
-                fflush(rotated);
-                JK_LEAVE_CS(&(log_cs), rc);
-            }
-        }
-    }
-    return rc;
-}
-
-static int init_jk(char *serverName)
-{
-    char shm_name[MAX_PATH];
-    int rc = JK_FALSE;
-
-    init_logger(JK_FALSE, &logger);
-    /* TODO: Use System logging to notify the user that
-     *       we cannot open the configured log file.
-     */
-
-    StringCbCopy(shm_name, MAX_PATH, SHM_DEF_NAME);
-
-    jk_log(logger, JK_LOG_INFO, "Starting %s", (FULL_VERSION_STRING));
-
-    if (*serverName) {
-        size_t i;
-        StringCbCat(shm_name, MAX_PATH, "_");
-        StringCbCat(shm_name, MAX_PATH, serverName);
-        for(i = 0; i < strlen(shm_name); i++) {
-            shm_name[i] = toupper(shm_name[i]);
-            if (!isalnum(shm_name[i]))
-                shm_name[i] = '_';
-        }
-    }
-
-    jk_set_worker_def_cache_size(DEFAULT_WORKER_THREADS);
-
-    /* Logging the initialization type: registry or properties file in virtual dir
-     */
-    if (JK_IS_DEBUG_LEVEL(logger)) {
-        jk_log(logger, JK_LOG_DEBUG, "Detected IIS version %d.%d", iis_info.major, iis_info.minor);
-        if (using_ini_file) {
-            jk_log(logger, JK_LOG_DEBUG, "Using ini file %s.", ini_file_name);
-        }
-        else {
-            jk_log(logger, JK_LOG_DEBUG, "Using registry.");
-        }
-
-        jk_log(logger, JK_LOG_DEBUG, "Using log file %s.", log_file);
-        jk_log(logger, JK_LOG_DEBUG, "Using log level %d.", log_level);
-        jk_log(logger, JK_LOG_DEBUG, "Using log rotation time %d seconds.", log_rotationtime);
-        jk_log(logger, JK_LOG_DEBUG, "Using log file size %d bytes.", log_filesize);
-
-        jk_log(logger, JK_LOG_DEBUG, "Using extension uri %s.", extension_uri);
-        jk_log(logger, JK_LOG_DEBUG, "Using worker file %s.", worker_file);
-        jk_log(logger, JK_LOG_DEBUG, "Using worker mount file %s.",
-               worker_mount_file);
-        jk_log(logger, JK_LOG_DEBUG, "Using rewrite rule file %s.",
-               rewrite_rule_file);
-        jk_log(logger, JK_LOG_DEBUG, "Using uri select %d.", uri_select_option);
-        jk_log(logger, JK_LOG_DEBUG, "Using%s chunked encoding.", (chunked_encoding_enabled ? "" : " no"));
-
-        jk_log(logger, JK_LOG_DEBUG, "Using notification event %s (0x%08x)",
-               (iis_info.filter_notify_event == SF_NOTIFY_AUTH_COMPLETE) ?
-               "SF_NOTIFY_AUTH_COMPLETE" :
-               ((iis_info.filter_notify_event == SF_NOTIFY_PREPROC_HEADERS) ?
-               "SF_NOTIFY_PREPROC_HEADERS" : "UNKNOWN"),
-               iis_info.filter_notify_event);
-
-        if (error_page) {
-            jk_log(logger, JK_LOG_DEBUG, "Using error page '%s'.", error_page);
-        }
-        jk_log(logger, JK_LOG_DEBUG, "Using uri header %s.", URI_HEADER_NAME);
-        jk_log(logger, JK_LOG_DEBUG, "Using query header %s.", QUERY_HEADER_NAME);
-        jk_log(logger, JK_LOG_DEBUG, "Using worker header %s.", WORKER_HEADER_NAME);
-        jk_log(logger, JK_LOG_DEBUG, "Using worker index %s.", WORKER_HEADER_INDEX);
-        jk_log(logger, JK_LOG_DEBUG, "Using translate header %s.", TOMCAT_TRANSLATE_HEADER_NAME);
-        jk_log(logger, JK_LOG_DEBUG, "Using a default of %d connections per pool.",
-                                     DEFAULT_WORKER_THREADS);
-    }
-
-    if ((log_rotationtime > 0) && (log_filesize > 0)) {
-        jk_log(logger, JK_LOG_WARNING,
-            "%s is defined in configuration, but will be ignored because %s is set. ",
-            LOG_FILESIZE_TAG, LOG_ROTATION_TIME_TAG);
-    }
-
-    if (rewrite_rule_file[0] && jk_map_alloc(&rewrite_map)) {
-        if (jk_map_read_properties(rewrite_map, NULL, rewrite_rule_file,
-                                   NULL, JK_MAP_HANDLE_RAW, logger)) {
-            int i;
-            if (JK_IS_DEBUG_LEVEL(logger)) {
-                jk_log(logger, JK_LOG_DEBUG, "Loaded rewrite rule file %s.",
-                       rewrite_rule_file);
-
-            }
-            jk_map_alloc(&rregexp_map);
-            for (i = 0; i < jk_map_size(rewrite_map); i++) {
-                const char *src = jk_map_name_at(rewrite_map, i);
-                if (*src == '~') {
-                    ap_regex_t *regexp = malloc(sizeof(ap_regex_t));
-                    const char *val = jk_map_value_at(rewrite_map, i);
-                    /* Skip leading tilde */
-                    regexp->real = src + 1;
-                    regexp->fake = val;
-                    if (!ap_regcomp(regexp, regexp->real, AP_REG_EXTENDED)) {
-                        jk_map_add(rregexp_map, regexp->real, regexp);
-                        if (JK_IS_DEBUG_LEVEL(logger)) {
-                            jk_log(logger, JK_LOG_DEBUG,
-                                   "Added regular expression rule %s -> %s",
-                                   regexp->real, regexp->fake);
-                        }
-                    }
-                    else {
-                        jk_log(logger, JK_LOG_ERROR,
-                               "Unable to compile regular expression %s",
-                               regexp->real);
-                        free(regexp);
-                    }
-                }
-            }
-        }
-        else {
-            jk_map_free(&rewrite_map);
-            rewrite_map = NULL;
-        }
-    }
-
-    if (uri_worker_map_alloc(&uw_map, NULL, logger)) {
-        rc = JK_FALSE;
-        if (reject_unsafe)
-            uw_map->reject_unsafe = 1;
-        else
-            uw_map->reject_unsafe = 0;
-        uw_map->reload = worker_mount_reload;
-        if (worker_mount_file[0]) {
-            uw_map->fname = worker_mount_file;
-            rc = uri_worker_map_load(uw_map, logger);
-        }
-    }
-    if (rc) {
-        rc = JK_FALSE;
-        if (jk_map_alloc(&workers_map)) {
-            if (jk_map_read_properties(workers_map, NULL, worker_file, NULL,
-                                       JK_MAP_HANDLE_DUPLICATES, logger)) {
-                int rv;
-
-                /* we add the URI->WORKER MAP since workers using AJP14 will feed it */
-
-                if (jk_map_resolve_references(workers_map, "worker.", 1, 1, logger) == JK_FALSE) {
-                    jk_log(logger, JK_LOG_ERROR, "Error in resolving configuration references");
-                }
-                /*
-                 * Create named shared memory for each server
-                 */
-                if (shm_config_size == 0)
-                    shm_config_size = jk_shm_calculate_size(workers_map, logger);
-                else {
-                    jk_log(logger, JK_LOG_WARNING,
-                           "The optimal shared memory size can now be determined automatically.");
-                    jk_log(logger, JK_LOG_WARNING,
-                           "You can remove the shm_size attribute if you want to use the optimal size.");
-                }
-                if ((rv = jk_shm_open(shm_name, shm_config_size, logger)) != 0) {
-                    /* TODO: Do not try to open the worker if we cannot create
-                     *       the shared memory segment.
-                     */
-                    jk_log(logger, JK_LOG_ERROR,
-                           "Initializing shm:%s errno=%d. Load balancing workers will not function properly.",
-                           jk_shm_name(), rv);
-                }
-                worker_env.uri_to_worker = uw_map;
-                worker_env.server_name = serverName;
-                worker_env.pool = NULL;
-
-                if (wc_open(workers_map, &worker_env, logger)) {
-                    rc = JK_TRUE;
-                }
-                uri_worker_map_ext(uw_map, logger);
-                uri_worker_map_switch(uw_map, logger);
-            }
-            else
-                jk_log(logger, JK_LOG_EMERG,
-                       "Unable to read worker file %s.", worker_file);
-            if (rc != JK_TRUE) {
-                jk_map_free(&workers_map);
-                workers_map = NULL;
-            }
-        }
-    }
-    if (rc) {
-        if (watchdog_interval) {
-            DWORD  wi;
-            watchdog_handle = CreateThread(NULL, 0, watchdog_thread,
-                                           NULL, 0, &wi);
-            if (!watchdog_handle) {
-                jk_log(logger, JK_LOG_EMERG, "Error %d (0x%08x) creating Watchdog thread",
-                       GetLastError(), GetLastError());
-                watchdog_interval = 0;
-            }
-        }
-        jk_log(logger, JK_LOG_INFO, "%s initialized", (FULL_VERSION_STRING));
-    }
-    return rc;
-}
-
-static BOOL initialize_extension(void)
-{
-
-    if (read_registry_init_data()) {
-        if (get_iis_info(&iis_info) != JK_TRUE) {
-            jk_log(logger, JK_LOG_ERROR, "Could not retrieve IIS version from registry");
-        }
-        is_inited = JK_TRUE;
-    }
-    return is_inited;
-}
-
-int parse_uri_select(const char *uri_select)
-{
-    if (0 == strcasecmp(uri_select, URI_SELECT_PARSED_VERB)) {
-        return URI_SELECT_OPT_PARSED;
-    }
-
-    if (0 == strcasecmp(uri_select, URI_SELECT_UNPARSED_VERB)) {
-        return URI_SELECT_OPT_UNPARSED;
-    }
-
-    if (0 == strcasecmp(uri_select, URI_SELECT_ESCAPED_VERB)) {
-        return URI_SELECT_OPT_ESCAPED;
-    }
-
-    if (0 == strcasecmp(uri_select, URI_SELECT_PROXY_VERB)) {
-        return URI_SELECT_OPT_PROXY;
-    }
-
-    return -1;
-}
-
-static int read_registry_init_data(void)
-{
-    char tmpbuf[MAX_PATH];
-    int ok = JK_TRUE;
-    LPVOID src;
-    HKEY hkey;
-    jk_map_t *map = NULL;
-
-    if (jk_map_alloc(&map)) {
-        if (jk_map_read_properties(map, jk_environment_map, ini_file_name, NULL,
-                                   JK_MAP_HANDLE_DUPLICATES, logger)) {
-            using_ini_file = JK_TRUE;
-            src = map;
-        }
-        else {
-            jk_map_free(&map);
-        }
-    }
-    if (!using_ini_file) {
-        long rc = RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGISTRY_LOCATION,
-                               (DWORD)0, KEY_READ, &hkey);
-        if (ERROR_SUCCESS != rc) {
-            return JK_FALSE;
-        }
-        else {
-            src = &hkey;
-        }
-    }
-    ok = ok && get_config_parameter(src, JK_LOG_FILE_TAG, log_file, sizeof(log_file));
-    if (get_config_parameter(src, JK_LOG_LEVEL_TAG, tmpbuf, sizeof(tmpbuf))) {
-        log_level = jk_parse_log_level(tmpbuf);
-    }
-    if (get_config_parameter(src, LOG_ROTATION_TIME_TAG, tmpbuf, sizeof(tmpbuf))) {
-        log_rotationtime = atol(tmpbuf);
-        if (log_rotationtime < 0) {
-            log_rotationtime = 0;
-        }
-    }
-    if (get_config_parameter(src, LOG_FILESIZE_TAG, tmpbuf, sizeof(tmpbuf))) {
-        size_t tl = strlen(tmpbuf);
-        if (tl > 0) {
-            /* rotatelogs has an 'M' suffix on filesize, which we optionally support for consistency */
-            if (tmpbuf[tl - 1] == 'M') {
-                tmpbuf[tl - 1] = '\0';
-            }
-            log_filesize = atol(tmpbuf);
-            if (log_filesize < 0) {
-                log_filesize = 0;
-            }
-            /* Convert to MB as per Apache rotatelogs */
-            log_filesize *= (1000 * 1000);
-        }
-    }
-
-    ok = ok && get_config_parameter(src, EXTENSION_URI_TAG, extension_uri, sizeof(extension_uri));
-    ok = ok && get_config_parameter(src, JK_WORKER_FILE_TAG, worker_file, sizeof(worker_file));
-    ok = ok && get_config_parameter(src, JK_MOUNT_FILE_TAG, worker_mount_file, sizeof(worker_mount_file));
-    get_config_parameter(src, URI_REWRITE_TAG, rewrite_rule_file, sizeof(rewrite_rule_file));
-    if (get_config_parameter(src, URI_SELECT_TAG, tmpbuf, sizeof(tmpbuf))) {
-        int opt = parse_uri_select(tmpbuf);
-        if (opt >= 0) {
-            uri_select_option = opt;
-        }
-        else {
-            ok = JK_FALSE;
-        }
-    }
-    shm_config_size = (size_t) get_config_int(src, SHM_SIZE_TAG, 0);
-    worker_mount_reload = get_config_int(src, WORKER_MOUNT_RELOAD_TAG, JK_URIMAP_DEF_RELOAD);
-    strip_session = get_config_bool(src, STRIP_SESSION_TAG, JK_FALSE);
-#ifndef AUTOMATIC_AUTH_NOTIFICATION
-    use_auth_notification_flags = get_config_int(src, AUTH_COMPLETE_TAG, 1);
-#endif
-    reject_unsafe = get_config_bool(src, REJECT_UNSAFE_TAG, JK_FALSE);
-    watchdog_interval = get_config_int(src, WATCHDOG_INTERVAL_TAG, 0);
-    if (watchdog_interval < 0)
-        watchdog_interval = 0;
-    chunked_encoding_enabled = get_config_bool(src, ENABLE_CHUNKED_ENCODING_TAG, JK_FALSE);
-    if (get_config_parameter(src, ERROR_PAGE_TAG, error_page_buf, sizeof(error_page_buf))) {
-        error_page = error_page_buf;
-    }
-
-    if (using_ini_file) {
-        jk_map_free(&map);
-    }
-    else {
-        RegCloseKey(hkey);
-    }
-    return ok;
-}
-
-static int get_config_parameter(LPVOID src, const char *tag,
-                                char *val, DWORD sz)
-{
-    const char *tmp = NULL;
-    if (using_ini_file) {
-        tmp = jk_map_get_string((jk_map_t*)src, tag, NULL);
-        if (tmp && (strlen(tmp) < sz)) {
-            StringCbCopy(val, sz, tmp);
-            return JK_TRUE;
-        }
-        else {
-            return JK_FALSE;
-        }
-    } else {
-        return get_registry_config_parameter(*((HKEY*)src), tag, val, sz);
-    }
-}
-
-static int get_config_int(LPVOID src, const char *tag, int def)
-{
-    if (using_ini_file) {
-        return jk_map_get_int((jk_map_t*)src, tag, def);
-    } else {
-        int val;
-        if (get_registry_config_number(*((HKEY*)src), tag, &val) ) {
-            return val;
-        }
-        else {
-            return def;
-        }
-    }
-}
-
-static int get_config_bool(LPVOID src, const char *tag, int def)
-{
-    if (using_ini_file) {
-        return jk_map_get_bool((jk_map_t*)src, tag, def);
-    } else {
-        char tmpbuf[128];
-        if (get_registry_config_parameter(*((HKEY*)src), tag,
-                                          tmpbuf, sizeof(tmpbuf))) {
-            return jk_get_bool_code(tmpbuf, def);
-        }
-        else {
-            return def;
-        }
-    }
-}
-
-static int get_registry_config_parameter(HKEY hkey,
-                                         const char *tag, char *b, DWORD sz)
-{
-    DWORD type = 0;
-    LONG lrc;
-
-    sz = sz - 1; /* Reserve space for RegQueryValueEx to add null terminator */
-    b[sz] = '\0'; /* Null terminate in case RegQueryValueEx doesn't */
-
-    lrc = RegQueryValueEx(hkey, tag, (LPDWORD) 0, &type, (LPBYTE) b, &sz);
-    if ((ERROR_SUCCESS != lrc) || (type != REG_SZ)) {
-        return JK_FALSE;
-    }
-
-    return JK_TRUE;
-}
-
-static int get_registry_config_number(HKEY hkey,
-                                      const char *tag, int *val)
-{
-    DWORD type = 0;
-    DWORD data = 0;
-    DWORD sz   = sizeof(DWORD);
-    LONG lrc;
-
-    lrc = RegQueryValueEx(hkey, tag, (LPDWORD)0, &type, (LPBYTE)&data, &sz);
-    if ((ERROR_SUCCESS != lrc) || (type != REG_DWORD)) {
-        return JK_FALSE;
-    }
-
-    *val = (int)data;
-
-    return JK_TRUE;
-}
-
-static int init_ws_service(isapi_private_data_t * private_data,
-                           jk_ws_service_t *s, char **worker_name)
-{
-    char *huge_buf = NULL;   /* should be enough for all */
-    int worker_index = -1;
-    rule_extension_t *e;
-    char  temp_buf[64];
-    DWORD huge_buf_sz;
-    BOOL  unknown_content_length = FALSE;
-
-    JK_TRACE_ENTER(logger);
-
-    s->start_response = start_response;
-    s->read  = iis_read;
-    s->write = iis_write;
-    s->done  = iis_done;
-
-    if (!(huge_buf = jk_pool_alloc(&private_data->p, MAX_PACKET_SIZE))) {
-        JK_TRACE_EXIT(logger);
-        return JK_FALSE;
-    }
-    huge_buf_sz = MAX_PACKET_SIZE;
-    GET_SERVER_VARIABLE_VALUE(HTTP_WORKER_HEADER_NAME, (*worker_name));
-    GET_SERVER_VARIABLE_VALUE(HTTP_URI_HEADER_NAME, s->req_uri);
-    GET_SERVER_VARIABLE_VALUE(HTTP_QUERY_HEADER_NAME, s->query_string);
-    GET_SERVER_VARIABLE_VALUE_INT(HTTP_WORKER_HEADER_INDEX, worker_index, -1);
-
-    if (JK_IS_DEBUG_LEVEL(logger)) {
-        jk_log(logger, JK_LOG_DEBUG, "Reading extension header %s: %s", HTTP_WORKER_HEADER_NAME, (*worker_name));
-        jk_log(logger, JK_LOG_DEBUG, "Reading extension header %s: %d", HTTP_WORKER_HEADER_INDEX, worker_index);
-        jk_log(logger, JK_LOG_DEBUG, "Reading extension header %s: %s", HTTP_URI_HEADER_NAME, s->req_uri);
-        jk_log(logger, JK_LOG_DEBUG, "Reading extension header %s: %s", HTTP_QUERY_HEADER_NAME, s->query_string);
-    }
-
-    if (s->req_uri == NULL) {
-        if (JK_IS_DEBUG_LEVEL(logger))
-            jk_log(logger, JK_LOG_DEBUG, "No URI header value provided. Defaulting to old behaviour" );
-        s->query_string = private_data->lpEcb->lpszQueryString;
-        *worker_name = DEFAULT_WORKER_NAME;
-        GET_SERVER_VARIABLE_VALUE("URL", s->req_uri);
-        if (unescape_url(s->req_uri) < 0) {
-            JK_TRACE_EXIT(logger);
-            return JK_FALSE;
-        }
-        getparents(s->req_uri);
-    }
-
-    GET_SERVER_VARIABLE_VALUE("AUTH_TYPE", s->auth_type);
-    GET_SERVER_VARIABLE_VALUE("REMOTE_USER", s->remote_user);
-    GET_SERVER_VARIABLE_VALUE("SERVER_PROTOCOL", s->protocol);
-    GET_SERVER_VARIABLE_VALUE("REMOTE_HOST", s->remote_host);
-    GET_SERVER_VARIABLE_VALUE("REMOTE_ADDR", s->remote_addr);
-    GET_SERVER_VARIABLE_VALUE("REMOTE_PORT", s->remote_port);
-    GET_SERVER_VARIABLE_VALUE(SERVER_NAME, s->server_name);
-    GET_SERVER_VARIABLE_VALUE_INT("SERVER_PORT", s->server_port, 80);
-    GET_SERVER_VARIABLE_VALUE(SERVER_SOFTWARE, s->server_software);
-    GET_SERVER_VARIABLE_VALUE_INT("SERVER_PORT_SECURE", s->is_ssl, 0);
-
-    s->method = private_data->lpEcb->lpszMethod;
-    /* Check for Transfer Encoding */
-    if (get_server_value(private_data->lpEcb,
-                         "HTTP_TRANSFER_ENCODING",
-                         temp_buf,
-                         (DWORD)sizeof(temp_buf))) {
-        if (strcasecmp(temp_buf, TRANSFER_ENCODING_CHUNKED_VALUE) == 0) {
-            s->is_chunked = JK_TRUE;
-            if (JK_IS_DEBUG_LEVEL(logger)) {
-                jk_log(logger, JK_LOG_DEBUG, "Request is Transfer-Encoding: chunked");
-            }
-        }
-        else {
-            /* XXX: What to do with non chunked T-E ?
-             */
-            if (JK_IS_DEBUG_LEVEL(logger))
-                jk_log(logger, JK_LOG_DEBUG, "Unsupported Transfer-Encoding: %s",
-                       temp_buf);
-        }
-    }
-    if (private_data->lpEcb->cbTotalBytes == 0xFFFFFFFF) {
-        /* We have size larger then 4Gb or Transfer-Encoding: chunked
-         * ReadClient should be called until no more data is returned
-         */
-        unknown_content_length = TRUE;
-    }
-    else {
-        /* Use the IIS provided content length */
-        s->content_length = (jk_uint64_t)private_data->lpEcb->cbTotalBytes;
-    }
-    e = get_uri_to_worker_ext(uw_map, worker_index);
-    if (e) {
-        if (JK_IS_DEBUG_LEVEL(logger))
-            jk_log(logger, JK_LOG_DEBUG, "Applying service extensions" );
-        s->extension.reply_timeout = e->reply_timeout;
-        s->extension.use_server_error_pages = e->use_server_error_pages;
-        if (e->activation) {
-            s->extension.activation = jk_pool_alloc(s->pool, e->activation_size * sizeof(int));
-            memcpy(s->extension.activation, e->activation, e->activation_size * sizeof(int));
-        }
-        if (e->fail_on_status_size > 0) {
-            s->extension.fail_on_status_size = e->fail_on_status_size;
-            s->extension.fail_on_status = jk_pool_alloc(s->pool, e->fail_on_status_size * sizeof(int));
-            memcpy(s->extension.fail_on_status, e->fail_on_status, e->fail_on_status_size * sizeof(int));
-        }
-    }
-
-    s->uw_map = uw_map;
-    /*
-     * Add SSL IIS environment
-     */
-    if (s->is_ssl) {
-        char *ssl_env_names[9] = {
-            "CERT_ISSUER",
-            "CERT_SUBJECT",
-            "CERT_COOKIE",
-            "HTTPS_SERVER_SUBJECT",
-            "CERT_FLAGS",
-            "HTTPS_SECRETKEYSIZE",
-            "CERT_SERIALNUMBER",
-            "HTTPS_SERVER_ISSUER",
-            "HTTPS_KEYSIZE"
-        };
-        char *ssl_env_values[9] = {
-            NULL,
-            NULL,
-            NULL,
-            NULL,
-            NULL,
-            NULL,
-            NULL,
-            NULL,
-            NULL
-        };
-        unsigned int i;
-        unsigned int num_of_vars = 0;
-
-        for (i = 0; i < 9; i++) {
-            GET_SERVER_VARIABLE_VALUE(ssl_env_names[i], ssl_env_values[i]);
-            if (ssl_env_values[i]) {
-                num_of_vars++;
-            }
-        }
-        /* XXX: To make the isapi plugin more consistent with the other web servers */
-        /* we should also set s->ssl_cipher, s->ssl_session, and s->ssl_key_size. */
-        if (num_of_vars) {
-            unsigned int j;
-
-            s->attributes_names =
-                jk_pool_alloc(&private_data->p, num_of_vars * sizeof(char *));
-            s->attributes_values =
-                jk_pool_alloc(&private_data->p, num_of_vars * sizeof(char *));
-
-            j = 0;
-            for (i = 0; i < 9; i++) {
-                if (ssl_env_values[i]) {
-                    s->attributes_names[j] = ssl_env_names[i];
-                    s->attributes_values[j] = ssl_env_values[i];
-                    j++;
-                }
-            }
-            s->num_attributes = num_of_vars;
-            if (ssl_env_values[4] && ssl_env_values[4][0] == '1') {
-                CERT_CONTEXT_EX cc;
-                cc.cbAllocated = MAX_PACKET_SIZE;
-                cc.CertContext.pbCertEncoded = (BYTE *) huge_buf;
-                cc.CertContext.cbCertEncoded = 0;
-
-                if (private_data->lpEcb->
-                    ServerSupportFunction(private_data->lpEcb->ConnID,
-                                          (DWORD) HSE_REQ_GET_CERT_INFO_EX,
-                                          (LPVOID) & cc, NULL,
-                                          NULL) != FALSE) {
-                    jk_log(logger, JK_LOG_DEBUG,
-                           "Client Certificate encoding:%d sz:%d flags:%ld",
-                           cc.CertContext.
-                           dwCertEncodingType & X509_ASN_ENCODING,
-                           cc.CertContext.cbCertEncoded,
-                           cc.dwCertificateFlags);
-                    s->ssl_cert =
-                        jk_pool_alloc(&private_data->p,
-                                      base64_encode_cert_len(cc.CertContext.
-                                                             cbCertEncoded));
-
-                    s->ssl_cert_len = base64_encode_cert(s->ssl_cert,
-                                                         huge_buf,
-                                                         cc.CertContext.
-                                                         cbCertEncoded) - 1;
-                }
-            }
-        }
-    }
-
-    huge_buf_sz = MAX_PACKET_SIZE;
-    if (get_server_value(private_data->lpEcb,
-#ifndef USE_CGI_HEADERS
-                         "ALL_RAW", huge_buf, huge_buf_sz)) {
-#else
-                         "ALL_HTTP", huge_buf, huge_buf_sz)) {
-#endif
-        unsigned int cnt = 0;
-        char *tmp;
-
-        for (tmp = huge_buf; *tmp; tmp++) {
-            if (*tmp == '\n') {
-                cnt++;
-            }
-        }
-
-        if (cnt) {
-            char *headers_buf = huge_buf;
-            unsigned int i;
-            BOOL need_content_length_header = FALSE;
-
-            if (s->content_length == 0 && unknown_content_length == FALSE) {
-                /* Add content-length=0 only if really zero
-                 */
-                need_content_length_header = TRUE;
-            }
-
-            /* allocate an extra header slot in case we need to add a content-length header */
-            s->headers_names =
-                jk_pool_alloc(&private_data->p, (cnt + 1) * sizeof(char *));
-            s->headers_values =
-                jk_pool_alloc(&private_data->p, (cnt + 1) * sizeof(char *));
-
-            if (!s->headers_names || !s->headers_values || !headers_buf) {
-                JK_TRACE_EXIT(logger);
-                return JK_FALSE;
-            }
-
-            for (i = 0, tmp = headers_buf; *tmp && i < cnt;) {
-                int real_header = JK_TRUE;
-
-#ifdef USE_CGI_HEADERS
-                /* Skip the HTTP_ prefix to the beginning of the header name */
-                tmp += HTTP_HEADER_PREFIX_LEN;
-#endif
-
-                if (!strnicmp(tmp, URI_HEADER_NAME, strlen(URI_HEADER_NAME))
-                    || !strnicmp(tmp, WORKER_HEADER_NAME, strlen(WORKER_HEADER_NAME))
-                    || !strnicmp(tmp, WORKER_HEADER_INDEX, strlen(WORKER_HEADER_INDEX))
-                    || !strnicmp(tmp, QUERY_HEADER_NAME, strlen(QUERY_HEADER_NAME))) {
-                    /* Skip redirector headers */
-                    cnt--;
-                    real_header = JK_FALSE;
-                }
-                else if (!strnicmp(tmp, CONTENT_LENGTH,
-                                   sizeof(CONTENT_LENGTH) - 1)) {
-                    need_content_length_header = FALSE;
-                    
-                    /* If the content-length is unknown
-                     * or larger then 4Gb do not send it.
-                     * IIS can also create a synthetic Content-Length header to make
-                     * lpcbTotalBytes and the CONTENT_LENGTH server variable agree
-                     * on small requests where the entire chunk encoded message is
-                     * read into the available buffer.
-                     */
-                    if (unknown_content_length || s->is_chunked) {
-                        if (JK_IS_DEBUG_LEVEL(logger)) {
-                            jk_log(logger, JK_LOG_DEBUG,
-                                   "Disregarding Content-Length in request - content is %s",
-                                   s->is_chunked ? "chunked" : "unknown length");
-                        }
-                        cnt--;
-                        real_header = JK_FALSE;
-                    }
-                    else {
-                        s->headers_names[i] = tmp;
-                    }
-                }
-                else if (!strnicmp(tmp, TOMCAT_TRANSLATE_HEADER_NAME,
-                                   strlen(TOMCAT_TRANSLATE_HEADER_NAME))) {
-                    s->headers_names[i] = TRANSLATE_HEADER_NAME_LC;
-                }
-                else {
-                    s->headers_names[i] = tmp;
-                }
-
-                while (':' != *tmp && *tmp) {
-#ifdef USE_CGI_HEADERS
-                    if (real_header) {
-                        if ('_' == *tmp) {
-                            *tmp = '-';
-                        }
-                        else {
-                            *tmp = JK_TOLOWER(*tmp);
-                        }
-                    }
-#endif
-                    tmp++;
-                }
-                *tmp = '\0';
-                tmp++;
-
-                /* Skip all the WS chars after the ':' to the beginning of the header value */
-                while (' ' == *tmp || '\t' == *tmp || '\v' == *tmp) {
-                    tmp++;
-                }
-
-                if (real_header) {
-                    s->headers_values[i] = tmp;
-                }
-
-                while (*tmp && *tmp != '\n' && *tmp != '\r') {
-                    tmp++;
-                }
-                *tmp = '\0';
-                tmp++;
-
-                /* skip CR LF */
-                while (*tmp == '\n' || *tmp == '\r') {
-                    tmp++;
-                }
-
-                if (real_header) {
-                    if (JK_IS_DEBUG_LEVEL(logger)) {
-                        jk_log(logger, JK_LOG_DEBUG, "Forwarding request header %s : %s",
-                               s->headers_names[i], s->headers_values[i]);
-                    }
-                    i++;
-                }
-            }
-            /* Add a content-length = 0 header if needed.
-             * Ajp13 assumes an absent content-length header means an unknown,
-             * but non-zero length body.
-             */
-            if (need_content_length_header) {
-                if (JK_IS_DEBUG_LEVEL(logger)) {
-                    jk_log(logger, JK_LOG_DEBUG, "Incoming request needs explicit Content-Length: 0 in AJP13");
-                }
-                s->headers_names[cnt] = "Content-Length";
-                s->headers_values[cnt] = "0";
-                cnt++;
-            }
-            s->num_headers = cnt;
-        }
-        else {
-            /* We must have our two headers */
-            JK_TRACE_EXIT(logger);
-            return JK_FALSE;
-        }
-    }
-    else {
-        JK_TRACE_EXIT(logger);
-        return JK_FALSE;
-    }
-
-    /* Dump all connection param so we can trace what's going to
-     * the remote tomcat
-     */
-    if (JK_IS_DEBUG_LEVEL(logger)) {
-        jk_log(logger, JK_LOG_DEBUG,
-               "Service protocol=%s method=%s host=%s addr=%s name=%s port=%d "
-               "auth=%s user=%s uri=%s",
-               STRNULL_FOR_NULL(s->protocol),
-               STRNULL_FOR_NULL(s->method),
-               STRNULL_FOR_NULL(s->remote_host),
-               STRNULL_FOR_NULL(s->remote_addr),
-               STRNULL_FOR_NULL(s->server_name),
-               s->server_port,
-               STRNULL_FOR_NULL(s->auth_type),
-               STRNULL_FOR_NULL(s->remote_user),
-               STRNULL_FOR_NULL(s->req_uri));
-        jk_log(logger, JK_LOG_DEBUG,
-               "Service request headers=%d attributes=%d "
-               "chunked=%s content-length=%" JK_UINT64_T_FMT " available=%u",
-               s->num_headers,
-               s->num_attributes,
-               (s->is_chunked == JK_TRUE) ? "yes" : "no",
-               s->content_length,
-               private_data->lpEcb->cbTotalBytes);
-    }
-
-    JK_TRACE_EXIT(logger);
-    return JK_TRUE;
-}
-
-static int get_server_value(LPEXTENSION_CONTROL_BLOCK lpEcb,
-                            char *name, char *buf, DWORD bufsz)
-{
-    DWORD sz = bufsz;
-    buf[0]   = '\0';
-    if (!lpEcb->GetServerVariable(lpEcb->ConnID, name,
-                                  buf, (LPDWORD) &sz))
-        return JK_FALSE;
-
-    if (sz <= bufsz)
-        buf[sz-1] = '\0';
-    return JK_TRUE;
-}
-
-static const char begin_cert[] = "-----BEGIN CERTIFICATE-----\r\n";
-
-static const char end_cert[] = "-----END CERTIFICATE-----\r\n";
-
-static const char basis_64[] =
-    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
-
-static int base64_encode_cert_len(int len)
-{
-    int n = ((len + 2) / 3 * 4) + 1;    /* base64 encoded size */
-    n += (n + 63 / 64) * 2;             /* add CRLF's */
-    n += sizeof(begin_cert) + sizeof(end_cert) - 2;  /* add enclosing strings. */
-    return n;
-}
-
-static int base64_encode_cert(char *encoded,
-                              const char *string, int len)
-{
-    int i, c;
-    char *p;
-    const char *t;
-
-    p = encoded;
-
-    t = begin_cert;
-    while (*t != '\0')
-        *p++ = *t++;
-
-    c = 0;
-    for (i = 0; i < len - 2; i += 3) {
-        *p++ = basis_64[(string[i] >> 2) & 0x3F];
-        *p++ = basis_64[((string[i] & 0x3) << 4) |
-                        ((int)(string[i + 1] & 0xF0) >> 4)];
-        *p++ = basis_64[((string[i + 1] & 0xF) << 2) |
-                        ((int)(string[i + 2] & 0xC0) >> 6)];
-        *p++ = basis_64[string[i + 2] & 0x3F];
-        c += 4;
-        if (c >= 64) {
-            *p++ = '\r';
-            *p++ = '\n';
-            c = 0;
-        }
-    }
-    if (i < len) {
-        *p++ = basis_64[(string[i] >> 2) & 0x3F];
-        if (i == (len - 1)) {
-            *p++ = basis_64[((string[i] & 0x3) << 4)];
-            *p++ = '=';
-        }
-        else {
-            *p++ = basis_64[((string[i] & 0x3) << 4) |
-                            ((int)(string[i + 1] & 0xF0) >> 4)];
-            *p++ = basis_64[((string[i + 1] & 0xF) << 2)];
-        }
-        *p++ = '=';
-        c++;
-    }
-    if (c != 0) {
-        *p++ = '\r';
-        *p++ = '\n';
-    }
-
-    t = end_cert;
-    while (*t != '\0')
-        *p++ = *t++;
-
-    *p++ = '\0';
-    return (int)(p - encoded);
-}
-
-/**
-* Determine version info and the primary notification event
-*/
-static int get_iis_info(iis_info_t* iis_info)
-{
-    HKEY hkey;
-    long rc;
-    int rv = JK_FALSE;
-
-    iis_info->major = 0;
-    iis_info->minor = 0;
-    iis_info->filter_notify_event = SF_NOTIFY_PREPROC_HEADERS;
-
-    /* Retrieve the IIS version Major/Minor */
-    rc = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
-                      W3SVC_REGISTRY_KEY, (DWORD) 0, KEY_READ, &hkey);
-    if (ERROR_SUCCESS == rc) {
-        if (get_registry_config_number(hkey, "MajorVersion", &iis_info->major) == JK_TRUE) {
-#ifdef AUTOMATIC_AUTH_NOTIFICATION
-            if (iis_info->major > 4)
-#else
-            if (use_auth_notification_flags && iis_info->major > 4)
-#endif
-                iis_info->filter_notify_event = SF_NOTIFY_AUTH_COMPLETE;
-            if (get_registry_config_number(hkey, "MinorVersion", &iis_info->minor) == JK_TRUE) {
-
-#ifdef AUTOMATIC_AUTH_NOTIFICATION
-                /* SF_NOTIFY_AUTH_COMPLETE causes redirect failures
-                 * (ERROR_INVALID_PARAMETER) on IIS 5.1 with OPTIONS/PUT
-                 * and is only available from IIS 5+
-                 */
-                if (iis_info->major == 5 && iis_info->minor == 1) {
-                    iis_info->filter_notify_event = SF_NOTIFY_PREPROC_HEADERS;
-                }
-#endif
-                rv = JK_TRUE;
-            }
-        }
-    }
-    CloseHandle(hkey);
-    return rv;
-}