2
* Copyright 1999-2004 The Apache Software Foundation
4
* Licensed under the Apache License, Version 2.0 (the "License");
5
* you may not use this file except in compliance with the License.
6
* You may obtain a copy of the License at
8
* http://www.apache.org/licenses/LICENSE-2.0
10
* Unless required by applicable law or agreed to in writing, software
11
* distributed under the License is distributed on an "AS IS" BASIS,
12
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
* See the License for the specific language governing permissions and
14
* limitations under the License.
17
/***************************************************************************
18
* Description: ISAPI plugin for Tomcat *
19
* Author: Andy Armstrong <andy@tagish.com> *
20
* Version: $Revision: 1.8 $ *
21
***************************************************************************/
23
/* Based on the the server redirector which was, in turn, based on the IIS
24
* redirector by Gal Shachor <shachor@il.ibm.com>
37
#include "jk_global.h"
41
#include "jk_service.h"
42
#include "jk_worker.h"
43
#include "jk_uri_worker_map.h"
52
#if !defined(DLLEXPORT)
54
#define DLLEXPORT __declspec(dllexport)
61
#define VERSION_STRING "Jakarta/ISAPI/" VERSION
63
/* What we call ourselves */
64
#define FILTERDESC "Apache Tomcat Interceptor (" VERSION_STRING ")"
65
#define SERVERDFLT "Microsoft IIS"
67
/* Registry location of configuration data */
68
#define REGISTRY_LOCATION "Software\\Apache Software Foundation\\Jakarta Isapi Redirector\\2.0"
70
/* Name of INI file relative to whatever the 'current' directory is when the filter is
71
* loaded. Certainly on Linux this is the the server data directory -- it seems likely that
72
* it's the same on other platforms
74
#define ININAME "libtomcat.ini"
76
/* Names of registry keys/ini items that contain commands to start, stop Tomcat */
77
#define TOMCAT_START "tomcat_start"
78
#define TOMCAT_STOP "tomcat_stop"
79
#define TOMCAT_STARTSTOP_TO 30000 /* 30 seconds */
81
static int initDone = JK_FALSE;
82
static jk_uri_worker_map_t *uw_map = NULL;
83
static jk_logger_t *logger = NULL;
85
static int logLevel = JK_LOG_EMERG_LEVEL;
86
static jk_pool_t cfgPool;
88
static const char *logFile;
89
static const char *workerFile;
90
static const char *workerMountFile;
91
static const char *tomcatStart;
92
static const char *tomcatStop;
94
#if defined(JK_VERSION) && JK_VERSION >= MAKEVERSION(1, 2, 0, 1)
95
static jk_worker_env_t worker_env;
98
static char *crlf = "\r\n";
101
{ HDR, BODY } rq_state;
103
typedef struct private_ws
107
/* Passed in by server, used to access various methods and data.
109
LPEXTENSION_CONTROL_BLOCK lpEcb;
111
/* True iff the response headers have been sent
122
/* These three functions are called back (indirectly) by
123
* Tomcat during request processing. StartResponse() sends
124
* the headers associated with the response.
126
static int JK_METHOD StartResponse(jk_ws_service_t *s, int status,
128
const char *const *hdrNames,
129
const char *const *hdrValues,
131
/* Read() is called by Tomcat to read from the request body (if any).
133
static int JK_METHOD Read(jk_ws_service_t *s, void *b, unsigned l,
135
/* Write() is called by Tomcat to send data back to the client.
137
static int JK_METHOD Write(jk_ws_service_t *s, const void *b, unsigned l);
139
static int ReadInitData(void);
142
static const char *GetRegString(HKEY hkey, const char *key);
145
//static unsigned int ParsedRequest(PHTTP_FILTER_CONTEXT *context, FilterParsedRequest *reqData);
147
/* Case insentive memcmp() clone
150
#define NoCaseMemCmp(ci, cj, l) _memicmp((void *) (ci), (void *) (cj), (l))
152
static int NoCaseMemCmp(const char *ci, const char *cj, int len)
154
if (0 == memcmp(ci, cj, len))
157
int cmp = tolower(*ci) - tolower(*cj);
168
/* Case insentive strcmp() clone
171
#define NoCaseStrCmp(si, sj) _stricmp((void *) (si), (void *) (sj))
173
static int NoCaseStrCmp(const char *si, const char *sj)
175
if (0 == strcmp(si, sj))
178
while (*si && tolower(*si) == tolower(*sj))
181
return tolower(*si) - tolower(*sj);
185
/* Case insensitive substring search.
186
* str string to search
187
* slen length of string to search
188
* ptn pattern to search for
189
* plen length of pattern
190
* returns 1 if there's a match otherwise 0
192
static int FindPathElem(const char *str, int slen, const char *ptn, int plen)
194
const char *sp = str;
196
while (slen >= plen) {
197
/* We're looking for a match for the specified string bounded by
198
* the start of the string, \ or / at the left and the end of the
199
* string, \ or / at the right. We look for \ as well as / on the
200
* suspicion that a Windows hosted server might accept URIs
203
if (NoCaseMemCmp(sp, ptn, plen) == 0 &&
204
(sp == str || *sp == '\\' || *sp == '/') &&
205
(*sp == '\0' || *sp == '\\' || *sp == '/'))
213
static void LogMessage(char *msg, unsigned short code, ...)
218
printf("Error %d: ", code);
226
/* Get the value of a server (CGI) variable as a string
228
static int GetVariable(private_ws_t * ws, char *hdrName,
229
char *buf, DWORD bufsz, char **dest, const char *dflt)
231
LPEXTENSION_CONTROL_BLOCK lpEcb = ws->lpEcb;
234
GetServerVariable(lpEcb->ConnID, hdrName, buf, (LPDWORD) & bufsz)) {
236
buf[bufsz - 1] = '\0';
237
*dest = jk_pool_strdup(&ws->p, buf);
241
*dest = jk_pool_strdup(&ws->p, dflt);
245
/* Get the value of a server (CGI) variable as an integer
247
static int GetVariableInt(private_ws_t * ws, char *hdrName,
248
char *buf, DWORD bufsz, int *dest, int dflt)
250
LPEXTENSION_CONTROL_BLOCK lpEcb = ws->lpEcb;
253
GetServerVariable(lpEcb->ConnID, hdrName, buf, (LPDWORD) & bufsz)) {
255
buf[bufsz - 1] = '\0';
264
/* Get the value of a server (CGI) variable as a boolean switch
266
static int GetVariableBool(private_ws_t * ws, char *hdrName,
267
char *buf, DWORD bufsz, int *dest, int dflt)
269
LPEXTENSION_CONTROL_BLOCK lpEcb = ws->lpEcb;
272
GetServerVariable(lpEcb->ConnID, hdrName, buf, (LPDWORD) & bufsz)) {
274
buf[bufsz - 1] = '\0';
276
*dest = atoi(buf) != 0;
277
else if (NoCaseStrCmp(buf, "yes") == 0
278
|| NoCaseStrCmp(buf, "on") == 0)
289
/* A couple of utility macros to supply standard arguments to GetVariable() and
292
#define GETVARIABLE(name, dest, dflt) GetVariable(ws, (name), workBuf, sizeof(workBuf), (dest), (dflt))
293
#define GETVARIABLEINT(name, dest, dflt) GetVariableInt(ws, (name), workBuf, sizeof(workBuf), (dest), (dflt))
294
#define GETVARIABLEBOOL(name, dest, dflt) GetVariableBool(ws, (name), workBuf, sizeof(workBuf), (dest), (dflt))
296
/* Return 1 iff the supplied string contains "web-inf" (in any case
297
* variation. We don't allow URIs containing web-inf, although
298
* FindPathElem() actually looks for the string bounded by path punctuation
299
* or the ends of the string, so web-inf must appear as a single element
300
* of the supplied URI
302
static int BadURI(const char *uri)
304
static char *wi = "web-inf";
305
return FindPathElem(uri, strlen(uri), wi, strlen(wi));
308
/* Replacement for strcat() that updates a buffer pointer. It's
309
* probably marginal, but this should be more efficient that strcat()
310
* in cases where the string being concatenated to gets long because
311
* strcat() has to count from start of the string each time.
313
static void Append(char **buf, const char *str)
316
memcpy(*buf, str, l);
321
/* Start the response by sending any headers. Invoked by Tomcat. I don't
322
* particularly like the fact that this always allocates memory, but
323
* perhaps jk_pool_alloc() is efficient.
325
static int JK_METHOD StartResponse(jk_ws_service_t *s, int status,
327
const char *const *hdrNames,
328
const char *const *hdrValues,
331
DEBUG(("StartResponse()\n"));
332
jk_log(logger, JK_LOG_DEBUG, "Into jk_ws_service_t::StartResponse\n");
334
if (status < 100 || status > 1000) {
335
jk_log(logger, JK_LOG_ERROR,
336
"jk_ws_service_t::StartResponse, invalid status %d\n", status);
340
if (s && s->ws_private) {
341
private_ws_t *p = s->ws_private;
343
if (!p->responseStarted) {
348
p->responseStarted = JK_TRUE;
353
/* TODO: coallesce the to jk_pool_alloc() calls into a single
356
statLen = 4 + strlen(reason);
357
statBuf = jk_pool_alloc(&p->p, statLen + 1);
359
/* slightly quicker than sprintf() we hope */
360
statBuf[0] = (status / 100) % 10 + '0';
361
statBuf[1] = (status / 10) % 10 + '0';
362
statBuf[2] = (status / 1) % 10 + '0';
364
strcpy(statBuf + 4, reason);
366
/* Build a single string containing all the headers
367
* because that's what the server needs.
374
for (i = 0, hdrLen = 3; i < hdrCount; i++)
375
hdrLen += strlen(hdrNames[i]) + strlen(hdrValues[i]) + 4;
377
hdrBuf = jk_pool_alloc(&p->p, hdrLen);
380
for (i = 0; i < hdrCount; i++) {
381
Append(&bufp, hdrNames[i]);
383
Append(&bufp, hdrValues[i]);
393
DEBUG(("%d %s\n%s", status, reason, hdrBuf));
395
/* TODO: check API docs for this */
396
if (!p->lpEcb->ServerSupportFunction(p->lpEcb->ConnID,
397
HSE_REQ_SEND_RESPONSE_HEADER,
398
statBuf, (LPDWORD) & statLen,
400
jk_log(logger, JK_LOG_ERROR,
401
"jk_ws_service_t::start_response, ServerSupportFunction failed\n");
409
jk_log(logger, JK_LOG_ERROR,
410
"jk_ws_service_t::StartResponse, NULL parameters\n");
415
static int JK_METHOD Read(jk_ws_service_t *s, void *bytes, unsigned len,
419
DEBUG(("Read(%p, %p, %u, %p)\n", s, bytes, len, countp));
420
jk_log(logger, JK_LOG_DEBUG, "Into jk_ws_service_t::Read\n");
422
if (s && s->ws_private && bytes && countp) {
423
private_ws_t *p = s->ws_private;
425
/* Copy data from the server's buffer. Although it seems slightly
426
* improbably we're believing that the server always buffers the
427
* entire request in memory. Not properly tested yet.
429
if (len > p->reqSize)
431
memcpy(bytes, p->reqBuffer, len);
438
jk_log(logger, JK_LOG_ERROR, "jk_ws_service_t::Read, NULL parameters\n");
444
static int JK_METHOD Write(jk_ws_service_t *s, const void *bytes,
447
DEBUG(("Write(%p, %p, %u)\n", s, bytes, len));
448
jk_log(logger, JK_LOG_DEBUG, "Into jk_ws_service_t::Write\n");
450
if (s && s->ws_private && bytes) {
451
private_ws_t *p = s->ws_private;
454
/* Make sure the response has really started. I'm almost certain
455
* this isn't necessary, but it was in the ISAPI code, so it's in
458
if (!p->responseStarted)
459
StartResponse(s, 200, NULL, NULL, NULL, 0);
461
DEBUG(("Writing %d bytes of content\n", len));
466
WriteClient(p->lpEcb->ConnID, (LPVOID) bytes, &dwLen, 0)) {
467
jk_log(logger, JK_LOG_ERROR,
468
"jk_ws_service_t::Write, WriteClient failed\n");
476
jk_log(logger, JK_LOG_ERROR, "jk_ws_service_t::Write, NULL parameters\n");
481
static int RunProg(const char *cmd)
485
PROCESS_INFORMATION pi;
487
ZeroMemory(&si, sizeof(si));
488
si.cb = sizeof(si); // Start the child process.
489
si.dwFlags = STARTF_USESHOWWINDOW;
490
si.wShowWindow = SW_SHOWMAXIMIZED;
493
(NULL, (char *)cmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) {
494
DWORD err = GetLastError();
495
LogMessage("Command \"%s\" (error %u)", NOERROR, cmd, err);
500
WaitForSingleObject(pi.hProcess, TOMCAT_STARTSTOP_TO))
503
LogMessage("Command \"%s\" didn't complete in time", NOERROR, cmd);
507
int err = system(cmd);
510
LogMessage("Command \"%s\" failed (error %d)", NOERROR, cmd, err);
515
/* Called when the filter is unloaded. Free various resources and
518
BOOL WINAPI TerminateFilter(DWORD dwFlags)
521
uri_worker_map_free(&uw_map, logger);
524
jk_close_file_logger(&logger);
529
if (NULL != tomcatStop && '\0' != *tomcatStop) {
530
LogMessage("Attempting to stop Tomcat: %s", NOERROR, tomcatStop);
534
LogMessage(FILTERDESC " unloaded", NOERROR);
536
jk_close_pool(&cfgPool);
541
/* Called when the server loads the filter. Reads a load of config data from
542
* the registry and elsewhere and displays a banner.
544
BOOL WINAPI GetFilterVersion(PHTTP_FILTER_VERSION pVer)
546
jk_open_pool(&cfgPool, NULL, 0); /* empty pool for config data */
551
if (!jk_open_file_logger(&logger, logFile, logLevel))
554
if (NULL != tomcatStart && '\0' != *tomcatStart) {
555
LogMessage("Attempting to start Tomcat: %s", NOERROR, tomcatStart);
556
RunProg(tomcatStart);
559
pVer->dwFilterVersion = pVer->dwServerFilterVersion;
561
//if (pVer->dwFilterVersion > HTTP_FILTER_REVISION)
562
// pVer->dwFilterVersion = HTTP_FILTER_REVISION;
564
/* Come back and check these... */
565
pVer->dwFlags = SF_NOTIFY_ORDER_HIGH |
566
SF_NOTIFY_SECURE_PORT |
567
SF_NOTIFY_NONSECURE_PORT | SF_NOTIFY_PREPROC_HEADERS;
569
strcpy(pVer->lpszFilterDesc, FILTERDESC);
572
LogMessage("%s loaded", NOERROR, pVer->lpszFilterDesc);
577
LogMessage("Error loading %s", NOERROR, FILTERDESC);
582
/* Read parameters from the registry
584
static int ReadInitData(void)
592
#define GETV(key) inifile_lookup(key)
596
if (e = inifile_read(&cfgPool, ININAME), ERRNONE != e) {
597
LogMessage("Error reading: %s, %s", NOERROR, ININAME, ERRTXT(e));
602
// Using the registry
603
#define GETV(key) GetRegString(hkey, key)
608
rc = RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGISTRY_LOCATION, (DWORD) 0,
610
if (ERROR_SUCCESS != rc)
615
#define GETVNB(tag, var) \
619
LogMessage("%s not defined in %s", NOERROR, tag, ININAME); \
623
GETVNB(JK_LOG_FILE_TAG, logFile)
624
GETVNB(JK_LOG_LEVEL_TAG, v);
625
GETVNB(JK_WORKER_FILE_TAG, workerFile);
626
GETVNB(JK_MOUNT_FILE_TAG, workerMountFile);
628
logLevel = (NULL == v) ? 0 : jk_parse_log_level(v);
630
tomcatStart = GETV(TOMCAT_START);
631
tomcatStop = GETV(TOMCAT_STOP);
641
static const char *GetRegString(HKEY hkey, const char *key)
648
rc = RegQueryValueEx(hkey, key, (LPDWORD) 0, &type, NULL, &sz);
649
if (rc != ERROR_SUCCESS || type != REG_SZ)
652
if (val = jk_pool_alloc(&cfgPool, sz), NULL == val)
655
rc = RegQueryValueEx(hkey, key, (LPDWORD) 0, &type, val, &sz);
656
if (rc == ERROR_SUCCESS)
663
/* Main entry point for the filter. Called by the server for every HTTP request.
665
DWORD WINAPI HttpFilterProc(PHTTP_FILTER_CONTEXT pfc,
666
DWORD dwNotificationType, LPVOID pvNotification)
669
switch (dwNotificationType) {
670
case kFilterParsedRequest:
671
return ParsedRequest(context, (FilterParsedRequest *) eventData);
675
return kFilterNotHandled;
678
return SF_STATUS_REQ_NEXT_NOTIFICATION;
681
/* Send a simple response. Used when we don't want to bother Tomcat,
682
* which in practice means for various error conditions that we can
685
static void SimpleResponse(PHTTP_FILTER_CONTEXT * context, int status,
686
char *reason, char *body)
689
FilterResponseHeaders frh;
693
sprintf(hdrBuf, "Content-type: text/html%s%s", crlf, crlf);
695
frh.responseCode = status;
696
frh.reasonText = reason;
697
frh.headerText = hdrBuf;
699
rc = context->ServerSupport(context, kWriteResponseHeaders, &frh, NULL, 0,
701
rc = context->WriteClient(context, body, strlen(body), 0, &errID);
705
/* Called to reject a URI that contains the string "web-inf". We block
706
* these because they may indicate an attempt to invoke arbitrary code.
708
static DWORD RejectBadURI(PHTTP_FILTER_CONTEXT * context)
711
"<HTML><BODY><H1>Access is Forbidden</H1></BODY></HTML>";
713
SimpleResponse(context, 403, "Forbidden", msg);
714
return SF_STATUS_REQ_NEXT_NOTIFICATION;
717
/* Allocate space for a string given a start pointer and an end pointer
718
* and return a pointer to the allocated, copied string.
720
static char *MemDup(private_ws_t * ws, const char *start, const char *end)
724
if (start != NULL && end != NULL && end > start) {
725
int len = end - start;
726
out = jk_pool_alloc(&ws->p, len + 1);
727
memcpy(out, start, len);
734
/* Given all the HTTP headers as a single string parse them into individual
735
* name, value pairs. Called twice: once to work out how many headers there
736
* are, then again to copy them.
738
static int ParseHeaders(private_ws_t * ws, const char *hdrs, int hdrsz,
742
const char *limit = hdrs + hdrsz;
743
const char *name, *nameEnd;
744
const char *value, *valueEnd;
746
/* Clear RECO status */
747
s->reco_status = RECO_NONE;
749
while (hdrs < limit) {
750
/* Skip line *before* doing anything, cos we want to lose the first line which
751
* contains the request.
753
while (hdrs < limit && (*hdrs != '\n' && *hdrs != '\r'))
755
while (hdrs < limit && (*hdrs == '\n' || *hdrs == '\r'))
761
name = nameEnd = value = valueEnd = NULL;
764
while (hdrs < limit && *hdrs >= ' ' && *hdrs != ':')
768
if (hdrs < limit && *hdrs == ':') {
770
while (hdrs < limit && (*hdrs == ' ' || *hdrs == '\t'))
773
while (hdrs < limit && *hdrs >= ' ')
778
if (s->headers_names != NULL && s->headers_values != NULL) {
779
s->headers_names[hdrCount] = MemDup(ws, name, nameEnd);
780
s->headers_values[hdrCount] = MemDup(ws, value, valueEnd);
781
DEBUG(("%s = %s\n", s->headers_names[hdrCount],
782
s->headers_values[hdrCount]));
791
/* Set up all the necessary jk_* workspace based on the current HTTP request.
793
static int InitService(private_ws_t * ws, jk_ws_service_t *s)
795
/* This is the only fixed size buffer left. It won't be overflowed
796
* because the the server API that reads into the buffer accepts a length
797
* constraint, and it's unlikely ever to be exhausted because the
798
* strings being will typically be short, but it's still aesthetically
801
char workBuf[16 * 1024];
807
int rc /*, dummy */ ;
809
static char *methodName[] =
810
{ "", "HEAD", "GET", "POST", "PUT", "DELETE" };
812
rc = ws->context->GetRequest(ws->context, &fr, &errID);
815
s->start_response = StartResponse;
819
s->req_uri = jk_pool_strdup(&ws->p, fr.URL);
820
s->query_string = NULL;
821
if (qp = strchr(s->req_uri, '?'), qp != NULL) {
824
s->query_string = qp;
827
GETVARIABLE("AUTH_TYPE", &s->auth_type, "");
828
GETVARIABLE("REMOTE_USER", &s->remote_user, "");
829
GETVARIABLE("SERVER_PROTOCOL", &s->protocol, "");
830
GETVARIABLE("REMOTE_HOST", &s->remote_host, "");
831
GETVARIABLE("REMOTE_ADDR", &s->remote_addr, "");
832
GETVARIABLE("SERVER_NAME", &s->server_name, "");
833
GETVARIABLEINT("SERVER_PORT", &s->server_port, 80);
834
GETVARIABLE("SERVER_SOFTWARE", &s->server_software, SERVERDFLT);
835
GETVARIABLEINT("CONTENT_LENGTH", &s->content_length, 0);
840
GETVARIABLEBOOL("HTTPS", &s->is_ssl, 0);
842
if (ws->reqData->requestMethod < 0 ||
843
ws->reqData->requestMethod >=
844
sizeof(methodName) / sizeof(methodName[0]))
847
s->method = methodName[ws->reqData->requestMethod];
849
s->headers_names = NULL;
850
s->headers_values = NULL;
853
s->ssl_cert_len = fr.clientCertLen;
854
s->ssl_cert = fr.clientCert;
855
s->ssl_cipher = NULL; /* required by Servlet 2.3 Api */
856
s->ssl_session = NULL;
858
#if defined(JK_VERSION) && JK_VERSION >= MAKEVERSION(1, 2, 0, 1)
859
s->ssl_key_size = -1; /* required by Servlet 2.3 Api, added in jtc */
866
"CERT_ISSUER", "CERT_SUBJECT", "CERT_COOKIE", "CERT_FLAGS",
868
"HTTPS_SERVER_SUBJECT", "HTTPS_SECRETKEYSIZE",
869
"HTTPS_SERVER_ISSUER", "HTTPS_KEYSIZE"
872
char *sslValues[] = {
873
NULL, NULL, NULL, NULL, NULL,
874
NULL, NULL, NULL, NULL
878
unsigned i, varCount = 0;
881
DEBUG(("SSL request\n"));
883
#if defined(JK_VERSION) && JK_VERSION >= MAKEVERSION(1, 2, 0, 1)
884
/* Read the variable into a dummy variable: we do this for the side effect of
885
* reading it into workBuf.
887
GETVARIABLEINT("HTTPS_KEYSIZE", &dummy, 0);
888
if (workBuf[0] == '[')
889
s->ssl_key_size = atoi(workBuf + 1);
895
for (i = 0; i < sizeof(sslNames) / sizeof(sslNames[0]); i++) {
896
GETVARIABLE(sslNames[i], &sslValues[i], NULL);
901
/* Andy, some SSL vars must be mapped directly in s->ssl_cipher,
902
* ssl->session and s->ssl_key_size
904
* Cipher could be "RC4-MD5"
906
* SessionID a string containing the UniqID used in SSL dialogue
911
s->attributes_names =
912
jk_pool_alloc(&ws->p, varCount * sizeof(char *));
913
s->attributes_values =
914
jk_pool_alloc(&ws->p, varCount * sizeof(char *));
917
for (i = 0; i < sizeof(sslNames) / sizeof(sslNames[0]); i++) {
919
s->attributes_names[j] = sslNames[i];
920
s->attributes_values[j] = sslValues[i];
924
s->num_attributes = varCount;
929
/* Duplicate all the headers now */
931
hdrsz = ws->reqData->GetAllHeaders(ws->context, &hdrs, &errID);
932
DEBUG(("\nGot headers (length %d)\n--------\n%s\n--------\n\n", hdrsz,
935
s->headers_names = s->headers_values = NULL;
936
hdrCount = ParseHeaders(ws, hdrs, hdrsz, s);
937
DEBUG(("Found %d headers\n", hdrCount));
938
s->num_headers = hdrCount;
939
s->headers_names = jk_pool_alloc(&ws->p, hdrCount * sizeof(char *));
940
s->headers_values = jk_pool_alloc(&ws->p, hdrCount * sizeof(char *));
941
hdrCount = ParseHeaders(ws, hdrs, hdrsz, s);
948
/* Handle an HTTP request. Works out whether Tomcat will be interested then either
949
* despatches it to Tomcat or passes it back to the server.
951
static unsigned int ParsedRequest(PHTTP_FILTER_CONTEXT * context,
952
FilterParsedRequest * reqData)
957
int result = kFilterNotHandled;
959
DEBUG(("\nParsedRequest starting\n"));
961
rc = context->GetRequest(context, &fr, &errID);
963
if (fr.URL && strlen(fr.URL)) {
965
char *workerName, *qp;
968
/* One time initialisation which is deferred so that we have the name of
969
* the server software to plug into worker_env
972
jk_map_t *map = NULL;
974
DEBUG(("Initialising worker map\n"));
976
if (jk_map_alloc(&map)) {
977
if (jk_map_read_properties(map, workerMountFile))
978
if (uri_worker_map_alloc(&uw_map, map, logger))
983
DEBUG(("Got the URI worker map\n"));
987
DEBUG(("About to allocate map\n"));
988
if (jk_map_alloc(&map)) {
989
DEBUG(("About to read %s\n", workerFile));
990
if (jk_map_read_properties(map, workerFile)) {
991
#if defined(JK_VERSION) && JK_VERSION >= MAKEVERSION(1, 2, 0, 1)
994
worker_env.uri_to_worker = uw_map;
996
GetServerVariable(context, "SERVER_SOFTWARE",
997
server, sizeof(server) - 1,
999
worker_env.server_name =
1000
jk_pool_strdup(&cfgPool, server);
1002
worker_env.server_name = SERVERDFLT;
1004
DEBUG(("Server name %s\n", worker_env.server_name));
1006
if (wc_open(map, &worker_env, logger))
1009
if (wc_open(map, logger))
1012
DEBUG(("OK = %d\n", ok));
1015
DEBUG(("Read %s, OK = %d\n", workerFile, ok));
1021
return kFilterError;
1026
if (qp = strchr(uri, '?'), qp != NULL)
1028
workerName = map_uri_to_worker(uw_map, uri, logger);
1032
DEBUG(("Worker for this URL is %s\n", workerName));
1034
if (NULL != workerName) {
1037
jk_pool_atom_t buf[SMALL_POOL_SIZE];
1040
return RejectBadURI(context);
1042
/* Go dispatch the call */
1044
jk_init_ws_service(&s);
1045
jk_open_pool(&ws.p, buf, sizeof(buf));
1047
ws.responseStarted = JK_FALSE;
1048
ws.context = context;
1049
ws.reqData = reqData;
1052
context->GetRequestContents(context, &ws.reqBuffer, &errID);
1057
if (InitService(&ws, &s)) {
1058
jk_worker_t *worker =
1059
wc_get_worker_for_name(workerName, logger);
1061
jk_log(logger, JK_LOG_DEBUG,
1062
"HttpExtensionProc %s a worker for name %s\n",
1063
worker ? "got" : "could not get", workerName);
1066
jk_endpoint_t *e = NULL;
1068
if (worker->get_endpoint(worker, &e, logger)) {
1069
int recover = JK_FALSE;
1071
if (e->service(e, &s, logger, &recover)) {
1072
result = kFilterHandledRequest;
1073
jk_log(logger, JK_LOG_DEBUG,
1074
"HttpExtensionProc service() returned OK\n");
1075
DEBUG(("HttpExtensionProc service() returned OK\n"));
1078
result = kFilterError;
1079
jk_log(logger, JK_LOG_ERROR,
1080
"HttpExtensionProc error, service() failed\n");
1081
DEBUG(("HttpExtensionProc error, service() failed\n"));
1083
e->done(&e, logger);
1087
jk_log(logger, JK_LOG_ERROR,
1088
"HttpExtensionProc error, could not get a worker for name %s\n",
1093
jk_close_pool(&ws.p);
1101
BOOL WINAPI DllMain(HINSTANCE hInst, ULONG ulReason, LPVOID lpReserved)
1103
BOOL fReturn = TRUE;
1107
case DLL_PROCESS_DETACH:
1108
TerminateFilter(HSE_TERM_MUST_UNLOAD);