jk_isapi_plugin.c
来自「精通tomcat书籍原代码,希望大家共同学习」· C语言 代码 · 共 1,117 行 · 第 1/3 页
C
1,117 行
/*
* 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 Tomcat *
* Author: Andy Armstrong <andy@tagish.com> *
* Version: $Revision: 299862 $ *
***************************************************************************/
/* Based on the the server redirector which was, in turn, based on the IIS
* redirector by Gal Shachor <shachor@il.ibm.com>
*/
#include "config.h"
#include "inifile.h"
#include "poolbuf.h"
/* ISAPI stuff */
#include <httpext.h>
#include <httpfilt.h>
#include <wininet.h>
/* JK stuff */
#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 <stdarg.h>
#define NOERROR 0
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#if !defined(DLLEXPORT)
#ifdef WIN32
#define DLLEXPORT __declspec(dllexport)
#else
#define DLLEXPORT
#endif
#endif
#define VERSION "2.0"
#define VERSION_STRING "Jakarta/ISAPI/" VERSION
/* What we call ourselves */
#define FILTERDESC "Apache Tomcat Interceptor (" VERSION_STRING ")"
#define SERVERDFLT "Microsoft IIS"
/* Registry location of configuration data */
#define REGISTRY_LOCATION "Software\\Apache Software Foundation\\Jakarta Isapi Redirector\\2.0"
/* Name of INI file relative to whatever the 'current' directory is when the filter is
* loaded. Certainly on Linux this is the the server data directory -- it seems likely that
* it's the same on other platforms
*/
#define ININAME "libtomcat.ini"
/* Names of registry keys/ini items that contain commands to start, stop Tomcat */
#define TOMCAT_START "tomcat_start"
#define TOMCAT_STOP "tomcat_stop"
#define TOMCAT_STARTSTOP_TO 30000 /* 30 seconds */
static int initDone = JK_FALSE;
static jk_uri_worker_map_t *uw_map = NULL;
static jk_logger_t *logger = NULL;
static int logLevel = JK_LOG_EMERG_LEVEL;
static jk_pool_t cfgPool;
static const char *logFile;
static const char *workerFile;
static const char *workerMountFile;
static const char *tomcatStart;
static const char *tomcatStop;
#if defined(JK_VERSION) && JK_VERSION >= MAKEVERSION(1, 2, 0, 1)
static jk_worker_env_t worker_env;
#endif
static char *crlf = "\r\n";
typedef enum
{ HDR, BODY } rq_state;
typedef struct private_ws
{
jk_pool_t p;
/* Passed in by server, used to access various methods and data.
*/
LPEXTENSION_CONTROL_BLOCK lpEcb;
/* True iff the response headers have been sent
*/
int responseStarted;
rq_state state;
poolbuf hdr;
poolbuf body;
} private_ws_t;
/* These three functions are called back (indirectly) by
* Tomcat during request processing. StartResponse() sends
* the headers associated with the response.
*/
static int JK_METHOD StartResponse(jk_ws_service_t *s, int status,
const char *reason,
const char *const *hdrNames,
const char *const *hdrValues,
unsigned hdrCount);
/* Read() is called by Tomcat to read from the request body (if any).
*/
static int JK_METHOD Read(jk_ws_service_t *s, void *b, unsigned l,
unsigned *a);
/* Write() is called by Tomcat to send data back to the client.
*/
static int JK_METHOD Write(jk_ws_service_t *s, const void *b, unsigned l);
static int ReadInitData(void);
#ifndef USE_INIFILE
static const char *GetRegString(HKEY hkey, const char *key);
#endif
//static unsigned int ParsedRequest(PHTTP_FILTER_CONTEXT *context, FilterParsedRequest *reqData);
/* Case insentive memcmp() clone
*/
#ifdef HAVE_MEMICMP
#define NoCaseMemCmp(ci, cj, l) _memicmp((void *) (ci), (void *) (cj), (l))
#else
static int NoCaseMemCmp(const char *ci, const char *cj, int len)
{
if (0 == memcmp(ci, cj, len))
return 0;
while (len > 0) {
int cmp = tolower(*ci) - tolower(*cj);
if (cmp != 0)
return cmp;
ci++;
cj++;
len--;
}
return 0;
}
#endif
/* Case insentive strcmp() clone
*/
#ifdef HAVE_STRICMP
#define NoCaseStrCmp(si, sj) _stricmp((void *) (si), (void *) (sj))
#else
static int NoCaseStrCmp(const char *si, const char *sj)
{
if (0 == strcmp(si, sj))
return 0;
while (*si && tolower(*si) == tolower(*sj))
si++, sj++;
return tolower(*si) - tolower(*sj);
}
#endif
/* Case insensitive substring search.
* str string to search
* slen length of string to search
* ptn pattern to search for
* plen length of pattern
* returns 1 if there's a match otherwise 0
*/
static int FindPathElem(const char *str, int slen, const char *ptn, int plen)
{
const char *sp = str;
while (slen >= plen) {
/* We're looking for a match for the specified string bounded by
* the start of the string, \ or / at the left and the end of the
* string, \ or / at the right. We look for \ as well as / on the
* suspicion that a Windows hosted server might accept URIs
* containing \.
*/
if (NoCaseMemCmp(sp, ptn, plen) == 0 &&
(sp == str || *sp == '\\' || *sp == '/') &&
(*sp == '\0' || *sp == '\\' || *sp == '/'))
return 1;
slen--;
sp++;
}
return 0;
}
static void LogMessage(char *msg, unsigned short code, ...)
{
va_list ap;
if (code != NOERROR)
printf("Error %d: ", code);
va_start(ap, code);
vprintf(msg, ap);
va_end(ap);
printf("\n");
}
/* Get the value of a server (CGI) variable as a string
*/
static int GetVariable(private_ws_t * ws, char *hdrName,
char *buf, DWORD bufsz, char **dest, const char *dflt)
{
LPEXTENSION_CONTROL_BLOCK lpEcb = ws->lpEcb;
if (lpEcb->
GetServerVariable(lpEcb->ConnID, hdrName, buf, (LPDWORD) & bufsz)) {
if (bufsz > 0)
buf[bufsz - 1] = '\0';
*dest = jk_pool_strdup(&ws->p, buf);
return JK_TRUE;
}
*dest = jk_pool_strdup(&ws->p, dflt);
return JK_FALSE;
}
/* Get the value of a server (CGI) variable as an integer
*/
static int GetVariableInt(private_ws_t * ws, char *hdrName,
char *buf, DWORD bufsz, int *dest, int dflt)
{
LPEXTENSION_CONTROL_BLOCK lpEcb = ws->lpEcb;
if (lpEcb->
GetServerVariable(lpEcb->ConnID, hdrName, buf, (LPDWORD) & bufsz)) {
if (bufsz > 0)
buf[bufsz - 1] = '\0';
*dest = atoi(buf);
return JK_TRUE;
}
*dest = dflt;
return JK_FALSE;
}
/* Get the value of a server (CGI) variable as a boolean switch
*/
static int GetVariableBool(private_ws_t * ws, char *hdrName,
char *buf, DWORD bufsz, int *dest, int dflt)
{
LPEXTENSION_CONTROL_BLOCK lpEcb = ws->lpEcb;
if (lpEcb->
GetServerVariable(lpEcb->ConnID, hdrName, buf, (LPDWORD) & bufsz)) {
if (bufsz > 0)
buf[bufsz - 1] = '\0';
if (isdigit(buf[0]))
*dest = atoi(buf) != 0;
else if (NoCaseStrCmp(buf, "yes") == 0
|| NoCaseStrCmp(buf, "on") == 0)
*dest = 1;
else
*dest = 0;
return JK_TRUE;
}
*dest = dflt;
return JK_FALSE;
}
/* A couple of utility macros to supply standard arguments to GetVariable() and
* GetVariableInt().
*/
#define GETVARIABLE(name, dest, dflt) GetVariable(ws, (name), workBuf, sizeof(workBuf), (dest), (dflt))
#define GETVARIABLEINT(name, dest, dflt) GetVariableInt(ws, (name), workBuf, sizeof(workBuf), (dest), (dflt))
#define GETVARIABLEBOOL(name, dest, dflt) GetVariableBool(ws, (name), workBuf, sizeof(workBuf), (dest), (dflt))
/* Return 1 iff the supplied string contains "web-inf" (in any case
* variation. We don't allow URIs containing web-inf, although
* FindPathElem() actually looks for the string bounded by path punctuation
* or the ends of the string, so web-inf must appear as a single element
* of the supplied URI
*/
static int BadURI(const char *uri)
{
static char *wi = "web-inf";
return FindPathElem(uri, strlen(uri), wi, strlen(wi));
}
/* Replacement for strcat() that updates a buffer pointer. It's
* probably marginal, but this should be more efficient that strcat()
* in cases where the string being concatenated to gets long because
* strcat() has to count from start of the string each time.
*/
static void Append(char **buf, const char *str)
{
int l = strlen(str);
memcpy(*buf, str, l);
(*buf)[l] = '\0';
*buf += l;
}
/* Start the response by sending any headers. Invoked by Tomcat. I don't
* particularly like the fact that this always allocates memory, but
* perhaps jk_pool_alloc() is efficient.
*/
static int JK_METHOD StartResponse(jk_ws_service_t *s, int status,
const char *reason,
const char *const *hdrNames,
const char *const *hdrValues,
unsigned hdrCount)
{
DEBUG(("StartResponse()\n"));
jk_log(logger, JK_LOG_DEBUG, "Into jk_ws_service_t::StartResponse\n");
if (status < 100 || status > 1000) {
jk_log(logger, JK_LOG_ERROR,
"jk_ws_service_t::StartResponse, invalid status %d\n", status);
return JK_FALSE;
}
if (s && s->ws_private) {
private_ws_t *p = s->ws_private;
if (!p->responseStarted) {
char *statBuf;
char *hdrBuf;
size_t statLen;
p->responseStarted = JK_TRUE;
if (NULL == reason)
reason = "";
/* TODO: coallesce the to jk_pool_alloc() calls into a single
* buffer alloc
*/
statLen = 4 + strlen(reason);
statBuf = jk_pool_alloc(&p->p, statLen + 1);
/* slightly quicker than sprintf() we hope */
statBuf[0] = (status / 100) % 10 + '0';
statBuf[1] = (status / 10) % 10 + '0';
statBuf[2] = (status / 1) % 10 + '0';
statBuf[3] = ' ';
strcpy(statBuf + 4, reason);
/* Build a single string containing all the headers
* because that's what the server needs.
*/
if (hdrCount > 0) {
unsigned i;
unsigned hdrLen;
char *bufp;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?