📄 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 Tomcat * * Author: Andy Armstrong <andy@tagish.com> * * Version: $Revision: 1.8 $ * ***************************************************************************//* 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;#endifstatic 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_INIFILEstatic 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))#elsestatic 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))#elsestatic 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 + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -