📄 jk_isapi_plugin.c
字号:
/*
* Copyright 1999-2004 The Apache Software Foundation
*
* Licensed 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: 375077 $ *
***************************************************************************/
// This define is needed to include wincrypt,h, needed to get client certificates
#define _WIN32_WINNT 0x0400
#include <httpext.h>
#include <httpfilt.h>
#include <wininet.h>
#include "jk_global.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"
#define VERSION_STRING "Jakarta/ISAPI/" JK_VERSTRING
#define SHM_DEF_NAME "JKISAPISHMEM"
#define DEFAULT_WORKER_NAME ("ajp13")
/*
* 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 TOMCAT_TRANSLATE_HEADER_NAME_BASE ("TOMCATTRANSLATE")
#define CONTENT_LENGTH ("CONTENT_LENGTH:")
/* 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_%s%p")
static char URI_HEADER_NAME[_MAX_FNAME];
static char QUERY_HEADER_NAME[_MAX_FNAME];
static char WORKER_HEADER_NAME[_MAX_FNAME];
static char TOMCAT_TRANSLATE_HEADER_NAME[_MAX_FNAME];
static char HTTP_URI_HEADER_NAME[_MAX_FNAME];
static char HTTP_QUERY_HEADER_NAME[_MAX_FNAME];
static char HTTP_WORKER_HEADER_NAME[_MAX_FNAME];
#define REGISTRY_LOCATION ("Software\\Apache Software Foundation\\Jakarta Isapi Redirector\\1.0")
#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 TRANSLATE_HEADER ("Translate:")
#define TRANSLATE_HEADER_NAME ("Translate")
#define TRANSLATE_HEADER_NAME_LC ("translate")
#define BAD_REQUEST -1
#define BAD_PATH -2
#define MAX_SERVERNAME 128
#define HTML_ERROR_400 "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">" \
"<HTML><HEAD><TITLE>Bad request!</TITLE></HEAD>" \
"<BODY><H1>Bad request!</H1><DL><DD>\n" \
"Your browser (or proxy) sent a request that " \
"this server could not understand.</DL></DD></BODY></HTML>"
#define HTML_ERROR_404 "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">" \
"<HTML><HEAD><TITLE>Object not found!</TITLE></HEAD>" \
"<BODY><H1>The requested URL was not found on this server" \
"</H1><DL><DD>\nIf you entered the URL manually please check your" \
"spelling and try again.</DL></DD></BODY></HTML>"
#define JK_TOLOWER(x) ((char)tolower((BYTE)(x)))
#define GET_SERVER_VARIABLE_VALUE(name, place) \
do { \
(place) = NULL; \
huge_buf_sz = sizeof(huge_buf); \
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 = sizeof(huge_buf); \
if (get_server_value(private_data->lpEcb, \
(name), \
huge_buf, \
huge_buf_sz)) { \
(place) = atoi(huge_buf); \
if (0 == (place)) { \
(place) = def; \
} \
} else { \
(place) = def; \
} } while(0)
static char ini_file_name[MAX_PATH];
static int using_ini_file = JK_FALSE;
static int is_inited = JK_FALSE;
static int is_mapread = JK_FALSE;
static int iis5 = -1;
static jk_uri_worker_map_t *uw_map = NULL;
static jk_map_t *workers_map = NULL;
static jk_logger_t *logger = NULL;
static char *SERVER_NAME = "SERVER_NAME";
static char *SERVER_SOFTWARE = "SERVER_SOFTWARE";
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 int log_level = JK_LOG_EMERG_LEVEL;
static char worker_file[MAX_PATH * 2];
static char worker_mount_file[MAX_PATH * 2] = {0};
#define URI_SELECT_OPT_PARSED 0
#define URI_SELECT_OPT_UNPARSED 1
#define URI_SELECT_OPT_ESCAPED 2
static int uri_select_option = URI_SELECT_OPT_PARSED;
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;
int request_started;
unsigned int bytes_read_so_far;
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];
};
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 read(jk_ws_service_t *s,
void *b, unsigned int l, unsigned int *a);
static int JK_METHOD write(jk_ws_service_t *s, const void *b, unsigned int l);
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 initialize_extension(void);
static int read_registry_init_data(void);
static int get_registry_config_parameter(HKEY hkey,
const char *tag, char *b, DWORD sz);
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 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 char *status_reason(int status)
{
static struct reasons {
int status;
char *reason;
} *r, reasons[] = {
{ 100, "Continue" },
{ 101, "Switching Protocols" },
{ 200, "OK" },
{ 201, "Created" },
{ 202, "Accepted" },
{ 203, "Non-Authoritative Information" },
{ 204, "No Content" },
{ 205, "Reset Content" },
{ 206, "Partial Content" },
{ 300, "Multiple Choices" },
{ 301, "Moved Permanently" },
{ 302, "Moved Temporarily" },
{ 303, "See Other" },
{ 304, "Not Modified" },
{ 305, "Use Proxy" },
{ 400, "Bad Request" },
{ 401, "Unauthorized" },
{ 402, "Payment Required" },
{ 403, "Forbidden" },
{ 404, "Not Found" },
{ 405, "Method Not Allowed" },
{ 406, "Not Acceptable" },
{ 407, "Proxy Authentication Required" },
{ 408, "Request Timeout" },
{ 409, "Conflict" },
{ 410, "Gone" },
{ 411, "Length Required" },
{ 412, "Precondition Failed" },
{ 413, "Request Entity Too Large" },
{ 414, "Request-URI Too Long" },
{ 415, "Unsupported Media Type" },
{ 500, "Internal Server Error" },
{ 501, "Not Implemented" },
{ 502, "Bad Gateway" },
{ 503, "Service Unavailable" },
{ 504, "Gateway Timeout" },
{ 505, "HTTP Version Not Supported" },
{ 000, NULL}
};
r = reasons;
while (r->status <= status)
if (r->status == status)
return r->reason;
else
r++;
return "No Reason";
}
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;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -