summaryrefslogtreecommitdiffstats
path: root/rubbos/app/tomcat-connectors-1.2.32-src/native/iis/jk_isapi_plugin.c
diff options
context:
space:
mode:
authorhongbotian <hongbo.tianhongbo@huawei.com>2015-11-30 03:10:21 -0500
committerhongbotian <hongbo.tianhongbo@huawei.com>2015-11-30 03:10:21 -0500
commitc0b7206652b2852bc574694e7ba07ba1c2acdc00 (patch)
tree5cb95cb0e19e03610525903df46279df2c3b7eb1 /rubbos/app/tomcat-connectors-1.2.32-src/native/iis/jk_isapi_plugin.c
parentb6d3d6e668b793220f2d3af1bc3e828553dc3fe6 (diff)
delete app
Change-Id: Id4c572809969ebe89e946e88063eaed262cff3f2 Signed-off-by: hongbotian <hongbo.tianhongbo@huawei.com>
Diffstat (limited to 'rubbos/app/tomcat-connectors-1.2.32-src/native/iis/jk_isapi_plugin.c')
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/iis/jk_isapi_plugin.c3495
1 files changed, 0 insertions, 3495 deletions
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
index 7c9f67be..00000000
--- a/rubbos/app/tomcat-connectors-1.2.32-src/native/iis/jk_isapi_plugin.c
+++ /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;
-}