blob: bfe93c53e525ccb6a0db2a79eabb1b9d633e5ecc [file] [log] [blame]
/*
* 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: URI to worker map object.
* Maps can be
*
* Exact Context -> /exact/uri=worker e.g. /examples/do[STAR]=ajp12
* Context Based -> /context/[STAR]=worker e.g. /examples/[STAR]=ajp12
* Context and suffix ->/context/[STAR].suffix=worker e.g. /examples/[STAR].jsp=ajp12
*
* This lets us either partition the work among the web server and the
* servlet container.
*
* @author: Gal Shachor <shachor@il.ibm.com>
* @author: Costin Manolache
*/
#include "jk_pool.h"
#include "jk_env.h"
#include "jk_uriMap.h"
#include "jk_registry.h"
#ifdef HAS_AP_PCRE
#include "httpd.h"
#define REGEXEC ap_regexec
#else
#ifdef HAS_PCRE
#include "pcre.h"
#include "pcreposix.h"
#define REGEXEC regexec
#endif
#endif
static INLINE const char *jk2_findExtension(jk_env_t *env, const char *uri);
static int jk2_uriMap_checkUri(jk_env_t *env, jk_uriMap_t *uriMap,
const char *uri);
#ifdef WIN32
static int jk2_uri_icase = 1;
#else
static int jk2_uri_icase = 0;
#endif
/*
* We are now in a security nightmare, it maybe that somebody sent
* us a uri that looks like /top-secret.jsp. and the web server will
* fumble and return the jsp content.
*
* To solve that we will check for path info following the suffix, we
* will also check that the end of the uri is not ".suffix.",
* ".suffix/", or ".suffix ".
*
* Was: check_security_fraud
*/
static int jk2_uriMap_checkUri(jk_env_t *env, jk_uriMap_t *uriMap,
const char *uri)
{
int i;
for (i = 0; i < uriMap->maps->size(env, uriMap->maps); i++) {
jk_uriEnv_t *uriEnv = uriMap->maps->valueAt(env, uriMap->maps, i);
if (MATCH_TYPE_SUFFIX == uriEnv->match_type) {
char *suffix_start;
for (suffix_start = strstr(uri, uriEnv->suffix);
suffix_start;
suffix_start = strstr(suffix_start + 1, uriEnv->suffix)) {
if ('.' != *(suffix_start - 1)) {
continue;
}
else {
char *after_suffix = suffix_start +
strlen(uriEnv->suffix);
if ((('.' == *after_suffix) ||
('/' == *after_suffix) ||
(' ' == *after_suffix)) &&
(0 == strncmp(uriEnv->prefix, uri,
uriEnv->prefix_len))) {
/*
* Security violation !!!
* this is a fraud.
*/
return JK_ERR;
}
}
}
}
}
return JK_OK;
}
/* Match = 0, NoMatch = 1, Abort = -1
* Based loosely on sections of wildmat.c by Rich Salz
*/
int jk2_strcmp_match(const char *str, const char *exp, int icase)
{
int x, y;
for (x = 0, y = 0; exp[y]; ++y, ++x) {
if (!str[x] && exp[y] != '*')
return -1;
if (exp[y] == '*') {
while (exp[++y] == '*');
if (!exp[y])
return 0;
while (str[x]) {
int ret;
if ((ret = jk2_strcmp_match(&str[x++], &exp[y], icase)) != 1)
return ret;
}
return -1;
}
else if (exp[y] != '?') {
if (icase && tolower(str[x]) != tolower(exp[y]))
return 1;
else if (!icase && str[x] != exp[y])
return 1;
}
}
return (str[x] != '\0');
}
/** Add a uri mapping. Called during uri: initialization. Will just copy the
uri in the table ( XXX use a map keyed on name ). In init() we process this
and set the right structures.
*/
static int jk2_uriMap_addUriEnv(jk_env_t *env, jk_uriMap_t *uriMap,
jk_uriEnv_t *uriEnv)
{
uriMap->maps->put(env, uriMap->maps, uriEnv->name, uriEnv, NULL);
if (uriMap->mbean->debug > 0)
env->l->jkLog(env, env->l, JK_LOG_DEBUG,
"uriMap.addUriEnv() %s %s %s\n", uriEnv->name,
uriEnv->virtual, uriEnv->uri);
return JK_OK;
}
static int JK_METHOD jk2_uriMap_setProperty(jk_env_t *env, jk_bean_t *mbean,
char *name, void *valueP)
{
return JK_OK;
}
static jk_uriEnv_t *jk2_uriMap_prefixMap(jk_env_t *env, jk_uriMap_t *uriMap,
jk_map_t *mapTable, const char *uri,
int uriLen)
{
int best_match = 0;
jk_uriEnv_t *match = NULL;
int i;
int sz = mapTable->size(env, mapTable);
for (i = 0; i < sz; i++) {
jk_uriEnv_t *uwr = mapTable->valueAt(env, mapTable, i);
/* XXX: the maps are already sorted by length. Should we skip that ??? */
if (uriLen < uwr->prefix_len)
continue;
if (strncmp(uri, uwr->prefix, uwr->prefix_len) == 0) {
if (uwr->prefix_len > best_match) {
best_match = uwr->prefix_len;
match = uwr;
}
}
}
return match;
}
static jk_uriEnv_t *jk2_uriMap_contextMap(jk_env_t *env, jk_uriMap_t *uriMap,
jk_map_t *mapTable, const char *uri,
int uriLen)
{
int i;
int sz = mapTable->size(env, mapTable);
for (i = 0; i < sz; i++) {
jk_uriEnv_t *uwr = mapTable->valueAt(env, mapTable, i);
if (uriLen != uwr->prefix_len - 1)
continue;
if (strncmp(uri, uwr->prefix, uriLen) == 0) {
return uwr;
}
}
return NULL;
}
static jk_uriEnv_t *jk2_uriMap_exactMap(jk_env_t *env, jk_uriMap_t *uriMap,
jk_map_t *mapTable, const char *uri,
int uriLen)
{
int i;
int sz = mapTable->size(env, mapTable);
jk_uriEnv_t *match = NULL;
for (i = 0; i < sz; i++) {
jk_uriEnv_t *uwr = mapTable->valueAt(env, mapTable, i);
if (uriLen != uwr->prefix_len)
continue;
if (strncmp(uri, uwr->prefix, uriLen) == 0) {
return uwr;
}
}
return NULL;
}
static jk_uriEnv_t *jk2_uriMap_suffixMap(jk_env_t *env, jk_uriMap_t *uriMap,
jk_map_t *mapTable,
const char *suffix, int suffixLen)
{
int i;
int sz = mapTable->size(env, mapTable);
for (i = 0; i < sz; i++) {
jk_uriEnv_t *uwr = mapTable->valueAt(env, mapTable, i);
if (!jk2_strcmp_match(suffix, uwr->suffix, jk2_uri_icase))
return uwr;
}
return NULL;
}
#define MAX_HOST_LENGTH 1024
/* Find the vhost */
static jk_uriEnv_t *jk2_uriMap_hostMap(jk_env_t *env, jk_uriMap_t *uriMap,
const char *vhost, int port)
{
int i, j, n;
char *name;
char hostname[MAX_HOST_LENGTH] = { 0 };
char portSuffix[32];
int vhostLen;
if (port) {
if (vhost) {
vhostLen = strlen(vhost);
if (strchr(vhost, ':')) {
strncpy(hostname, vhost, MAX_HOST_LENGTH);
}
else {
strncpy(hostname, vhost, MAX_HOST_LENGTH);
if (strlen(vhost) < MAX_HOST_LENGTH - 1) {
sprintf(portSuffix, ":%d", port);
strncat(hostname + vhostLen, portSuffix,
MAX_HOST_LENGTH - vhostLen);
}
}
}
else
sprintf(hostname, "*:%d", port);
}
else if (vhost)
strncpy(hostname, vhost, MAX_HOST_LENGTH);
else /* Return default host if vhost and port wasn't suplied */
return uriMap->vhosts->get(env, uriMap->vhosts, "*");
hostname[MAX_HOST_LENGTH - 1] = 0;
n = uriMap->vhosts->size(env, uriMap->vhosts);
/* Check the exact hostname:port first */
for (i = 0; i < n; i++) {
jk_uriEnv_t *uriEnv = uriMap->vhosts->valueAt(env, uriMap->vhosts, i);
name = uriMap->vhosts->nameAt(env, uriMap->vhosts, i);
/* Host name is not case sensitive */
if (strcasecmp(name, hostname) == 0 && port == uriEnv->port)
return uriEnv;
}
if (vhost) {
/* Check the hostname */
for (i = 0; i < n; i++) {
jk_uriEnv_t *uriEnv =
uriMap->vhosts->valueAt(env, uriMap->vhosts, i);
name = uriMap->vhosts->nameAt(env, uriMap->vhosts, i);
/* Host name is not case sensitive */
if (strcasecmp(name, vhost) == 0)
return uriEnv;
}
/* Then for each vhost, check the aliases */
for (i = 0; i < n; i++) {
jk_uriEnv_t *uriEnv =
uriMap->vhosts->valueAt(env, uriMap->vhosts, i);
if (uriEnv->aliases) {
int m = uriEnv->aliases->size(env, uriEnv->aliases);
for (j = 0; j < m; j++) {
name = uriEnv->aliases->nameAt(env, uriEnv->aliases, j);
if (strcasecmp(name, hostname) == 0)
return uriEnv;
}
}
}
}
/* Finally, check aginst *:port hostname */
if (port) {
for (i = 0; i < n; i++) {
jk_uriEnv_t *uriEnv =
uriMap->vhosts->valueAt(env, uriMap->vhosts, i);
name = uriMap->vhosts->nameAt(env, uriMap->vhosts, i);
if ((strncmp(name, "*:", 2) == 0) && uriEnv->port == port) {
return uriEnv;
}
}
}
/* Return default host if none found */
return uriMap->vhosts->get(env, uriMap->vhosts, "*");
}
#if defined(HAS_PCRE) || defined(HAS_AP_PCRE)
static jk_uriEnv_t *jk2_uriMap_regexpMap(jk_env_t *env, jk_uriMap_t *uriMap,
jk_map_t *mapTable, const char *uri)
{
int i;
int sz = mapTable->size(env, mapTable);
for (i = 0; i < sz; i++) {
jk_uriEnv_t *uwr = mapTable->valueAt(env, mapTable, i);
if (uwr->regexp) {
regex_t *r = (regex_t *) uwr->regexp;
regmatch_t regm[10];
if (!REGEXEC(r, uri, r->re_nsub + 1, regm, 0)) {
return uwr;
}
}
}
return NULL;
}
#else
static jk_uriEnv_t *jk2_uriMap_regexpMap(jk_env_t *env, jk_uriMap_t *uriMap,
jk_map_t *mapTable, const char *uri)
{
return NULL;
}
#endif
static void jk2_uriMap_createHosts(jk_env_t *env, jk_uriMap_t *uriMap)
{
int i;
for (i = 0; i < uriMap->maps->size(env, uriMap->maps); i++) {
jk_uriEnv_t *uriEnv = uriMap->maps->valueAt(env, uriMap->maps, i);
if (uriEnv == NULL)
continue;
if (uriEnv->virtual != NULL && strlen(uriEnv->virtual)) {
if (uriEnv->match_type == MATCH_TYPE_HOST) {
jk2_map_default_create(env, &uriEnv->webapps, uriMap->pool);
uriMap->vhosts->put(env, uriMap->vhosts,
uriEnv->virtual, uriEnv, NULL);
}
else { /* Create the missing vhosts */
if (!uriMap->vhosts->get(env, uriMap->vhosts,
uriEnv->virtual)) {
/* Actually create the bean */
jk_uriEnv_t *hostEnv = env->getByName2(env, "uri",
uriEnv->virtual);
if (hostEnv == NULL) {
env->createBean2(env, uriMap->mbean->pool, "uri",
uriEnv->virtual);
hostEnv = env->getByName2(env, "uri",
uriEnv->virtual);
if (!hostEnv) {
/* XXX this is a error. */
continue;
}
if (uriMap->mbean->debug > 0)
env->l->jkLog(env, env->l, JK_LOG_DEBUG,
"uriMap.init() Create missing host %s\n",
uriEnv->virtual);
}
jk2_map_default_create(env, &hostEnv->webapps,
uriMap->pool);
uriMap->vhosts->put(env, uriMap->vhosts, uriEnv->virtual,
hostEnv, NULL);
env->l->jkLog(env, env->l, JK_LOG_DEBUG,
"uriMap.init() Fixing Host %s\n",
uriEnv->virtual);
}
}
}
}
/** Make sure each vhost has a default context
*/
for (i = 0; i < uriMap->vhosts->size(env, uriMap->vhosts); i++) {
jk_uriEnv_t *hostEnv =
uriMap->vhosts->valueAt(env, uriMap->vhosts, i);
jk_uriEnv_t *rootCtx;
char *uriPath;
if (hostEnv->virtual != NULL) {
uriPath = env->tmpPool->pstrcat(env, env->tmpPool,
hostEnv->virtual, "/", NULL);
}
else {
uriPath = "/";
}
rootCtx = env->getByName2(env, "uri", uriPath);
if (rootCtx == NULL) {
env->createBean2(env, uriMap->mbean->pool, "uri", uriPath);
rootCtx = env->getByName2(env, "uri", uriPath);
if (uriMap->mbean->debug > 0)
env->l->jkLog(env, env->l, JK_LOG_DEBUG,
"uriMap.init() Create default context %s\n",
uriPath);
rootCtx->mbean->setAttribute(env, rootCtx->mbean, "context", "/");
}
}
}
static void jk2_uriMap_createWebapps(jk_env_t *env, jk_uriMap_t *uriMap)
{
int i;
/* Init all contexts */
/* For each context, init the local uri maps */
for (i = 0; i < uriMap->maps->size(env, uriMap->maps); i++) {
jk_uriEnv_t *uriEnv = uriMap->maps->valueAt(env, uriMap->maps, i);
char *uri;
char *context;
if (uriEnv == NULL) {
env->l->jkLog(env, env->l, JK_LOG_INFO, "uriMap.init() NPE\n");
}
uri = uriEnv->uri;
context = uriEnv->contextPath;
if (uri != NULL && context != NULL && strcmp(uri, context) == 0) {
char *vhost = uriEnv->virtual;
int port = uriEnv->port;
jk_uriEnv_t *hostEnv =
jk2_uriMap_hostMap(env, uriMap, vhost, port);
if (!hostEnv)
continue;
if (uriMap->mbean->debug > 5)
env->l->jkLog(env, env->l, JK_LOG_DEBUG,
"uriMap.init() loaded context %s %s %#lx %#lx %#lx\n",
uriEnv->virtual, context, hostEnv,
hostEnv->webapps, uriMap->pool);
uriEnv->match_type = MATCH_TYPE_CONTEXT;
uriEnv->prefix = context;
uriEnv->prefix_len = strlen(context);
hostEnv->webapps->put(env, hostEnv->webapps, context, uriEnv,
NULL);
jk2_map_default_create(env, &uriEnv->exactMatch, uriMap->pool);
jk2_map_default_create(env, &uriEnv->prefixMatch, uriMap->pool);
jk2_map_default_create(env, &uriEnv->suffixMatch, uriMap->pool);
jk2_map_default_create(env, &uriEnv->regexpMatch, uriMap->pool);
}
}
/* Now, fix the webapps finding context from each uri
* and create one if not found.
*/
for (i = 0; i < uriMap->maps->size(env, uriMap->maps); i++) {
jk_uriEnv_t *uriEnv = uriMap->maps->valueAt(env, uriMap->maps, i);
char *vhost = uriEnv->virtual;
int port = uriEnv->port;
char *context = uriEnv->contextPath;
jk_uriEnv_t *hostEnv = jk2_uriMap_hostMap(env, uriMap, vhost, port);
jk_uriEnv_t *ctxEnv;
env->l->jkLog(env, env->l, JK_LOG_DEBUG,
"uriMap: fix uri %s context %s host %s\n",
uriEnv->uri == NULL ? "null" : uriEnv->uri,
uriEnv->contextPath ==
NULL ? "null" : uriEnv->contextPath, hostEnv->virtual);
if (context == NULL) {
if (uriMap->mbean->debug > 5)
env->l->jkLog(env, env->l, JK_LOG_DEBUG,
"uriMap: no context %s\n", uriEnv->uri);
continue;
}
ctxEnv = jk2_uriMap_exactMap(env, uriMap, hostEnv->webapps, context,
strlen(context));
/* if not alredy created, create it */
if (ctxEnv == NULL) {
jk_bean_t *mbean;
char *ctxname;
ctxname = uriEnv->pool->pstrcat(env, uriEnv->pool, vhost,
context, NULL);
env->l->jkLog(env, env->l, JK_LOG_INFO,
"uriMap: creating context %s\n", ctxname);
mbean = env->getBean2(env, "uri", ctxname);
if (mbean == NULL)
mbean = env->createBean2(env, uriMap->pool, "uri", ctxname);
if (mbean == NULL || mbean->object == NULL) {
env->l->jkLog(env, env->l, JK_LOG_ERROR,
"uriMap: can't create context object %s\n",
ctxname);
continue;
}
ctxEnv = mbean->object;
ctxEnv->match_type = MATCH_TYPE_CONTEXT;
ctxEnv->prefix = context;
ctxEnv->prefix_len = strlen(context);
ctxEnv->contextPath = context;
ctxEnv->ctxt_len = strlen(context);
hostEnv->webapps->put(env, hostEnv->webapps, context, ctxEnv,
NULL);
jk2_map_default_create(env, &ctxEnv->exactMatch, uriMap->pool);
jk2_map_default_create(env, &ctxEnv->prefixMatch, uriMap->pool);
jk2_map_default_create(env, &ctxEnv->suffixMatch, uriMap->pool);
jk2_map_default_create(env, &ctxEnv->regexpMatch, uriMap->pool);
}
}
}
static int jk2_uriMap_createMappings(jk_env_t *env, jk_uriMap_t *uriMap)
{
int i;
if (uriMap->mbean->debug > 5)
env->l->jkLog(env, env->l, JK_LOG_DEBUG,
"uriMap.init() processing mappings\n");
/* XXX We should also sort prefix mappings and maybe use binary search - but
it won't have too bigger benefits, the number of mappings per ctx is typically
small
*/
for (i = 0; i < uriMap->maps->size(env, uriMap->maps); i++) {
jk_uriEnv_t *uriEnv = uriMap->maps->valueAt(env, uriMap->maps, i);
char *vhost = uriEnv->virtual;
int port = uriEnv->port;
jk_uriEnv_t *hostEnv = jk2_uriMap_hostMap(env, uriMap, vhost, port);
char *uri = uriEnv->uri;
jk_uriEnv_t *ctxEnv = NULL;
if (hostEnv == NULL)
continue;
if (uri == NULL)
continue;
uriEnv->uriMap = uriMap;
uriEnv->init(env, uriEnv);
if (uri == NULL)
continue;
/* If the context was specified try to find the exact one */
if (uriEnv->contextPath != NULL)
ctxEnv = jk2_uriMap_exactMap(env, uriMap, hostEnv->webapps,
uriEnv->contextPath,
uriEnv->ctxt_len);
else if (uriEnv->match_type == MATCH_TYPE_REGEXP) {
ctxEnv = hostEnv->webapps->get(env, hostEnv->webapps, "/");
}
/* Next find by uri prefix */
if (ctxEnv == NULL)
ctxEnv = jk2_uriMap_prefixMap(env, uriMap, hostEnv->webapps, uri,
strlen(uri));
if (ctxEnv == NULL) {
env->l->jkLog(env, env->l, JK_LOG_DEBUG,
"uriMap.init() no context for %s\n", uri);
/* Normal case if Location is used */
continue;
}
/* Correct the context path if needed */
uriEnv->contextPath = ctxEnv->prefix;
uriEnv->ctxt_len = ctxEnv->prefix_len;
if (uriMap->mbean->debug > 5)
env->l->jkLog(env, env->l, JK_LOG_INFO,
"uriMap.init() adding context %s:%s for %s\n",
vhost, ctxEnv->prefix, uri);
switch (uriEnv->match_type) {
case MATCH_TYPE_EXACT:
ctxEnv->exactMatch->add(env, ctxEnv->exactMatch, uri, uriEnv);
ctxEnv->exactMatch->sort(env, ctxEnv->exactMatch);
break;
case MATCH_TYPE_SUFFIX:
ctxEnv->suffixMatch->add(env, ctxEnv->suffixMatch, uri, uriEnv);
ctxEnv->suffixMatch->sort(env, ctxEnv->suffixMatch);
break;
case MATCH_TYPE_PREFIX:
ctxEnv->prefixMatch->add(env, ctxEnv->prefixMatch, uri, uriEnv);
ctxEnv->suffixMatch->sort(env, ctxEnv->prefixMatch);
break;
case MATCH_TYPE_REGEXP:
if (uriEnv->regexp)
ctxEnv->regexpMatch->add(env, ctxEnv->regexpMatch, uri,
uriEnv);
break;
}
}
return JK_OK;
}
static jk_uriEnv_t *jk2_uriMap_duplicateUri(jk_env_t *env,
jk_uriMap_t *uriMap,
jk_uriEnv_t *uriEnv,
jk_uriEnv_t *mapEnv)
{
char *uriname;
jk_uriEnv_t *newEnv;
jk_bean_t *mbean;
uriname = uriEnv->pool->pstrcat(env, uriEnv->pool, uriEnv->name,
mapEnv->uri, NULL);
env->l->jkLog(env, env->l, JK_LOG_INFO,
"uriMap: creating duplicate of uri %s\n", uriname);
mbean = env->getBean2(env, "uri", uriname);
if (mbean == NULL)
mbean = env->createBean2(env, uriMap->pool, "uri", uriname);
if (mbean == NULL || mbean->object == NULL) {
env->l->jkLog(env, env->l, JK_LOG_ERROR,
"uriMap: can't create uri object %s\n", uriname);
return NULL;
}
newEnv = mbean->object;
newEnv->match_type = mapEnv->match_type;
newEnv->prefix = mapEnv->prefix;
newEnv->prefix_len = mapEnv->prefix_len;
newEnv->contextPath = mapEnv->contextPath;
newEnv->ctxt_len = mapEnv->ctxt_len;
newEnv->worker = mapEnv->worker;
newEnv->workerName = mapEnv->workerName;
newEnv->workerEnv = mapEnv->workerEnv;
newEnv->regexp = mapEnv->regexp;
return newEnv;
}
static jk_uriEnv_t *jk2_uriMap_duplicateContext(jk_env_t *env,
jk_uriMap_t *uriMap,
jk_uriEnv_t *uriEnv,
jk_uriEnv_t *mapEnv)
{
char *uriname;
jk_uriEnv_t *newEnv;
jk_bean_t *mbean;
uriname = uriEnv->pool->pstrcat(env, uriEnv->pool, uriEnv->name,
mapEnv->contextPath, NULL);
env->l->jkLog(env, env->l, JK_LOG_INFO,
"uriMap: creating duplicate of context %s\n", uriname);
mbean = env->getBean2(env, "uri", uriname);
if (mbean == NULL)
mbean = env->createBean2(env, uriMap->pool, "uri", uriname);
if (mbean == NULL || mbean->object == NULL) {
env->l->jkLog(env, env->l, JK_LOG_ERROR,
"uriMap: can't create uri object %s\n", uriname);
return NULL;
}
newEnv = mbean->object;
newEnv->match_type = mapEnv->match_type;
newEnv->prefix = mapEnv->prefix;
newEnv->prefix_len = mapEnv->prefix_len;
newEnv->contextPath = mapEnv->contextPath;
newEnv->ctxt_len = mapEnv->ctxt_len;
newEnv->worker = mapEnv->worker;
newEnv->workerName = mapEnv->workerName;
newEnv->workerEnv = mapEnv->workerEnv;
jk2_map_default_create(env, &newEnv->exactMatch, uriMap->pool);
jk2_map_default_create(env, &newEnv->prefixMatch, uriMap->pool);
jk2_map_default_create(env, &newEnv->suffixMatch, uriMap->pool);
jk2_map_default_create(env, &newEnv->regexpMatch, uriMap->pool);
return newEnv;
}
static int jk2_uriMap_createGlobals(jk_env_t *env, jk_uriMap_t *uriMap)
{
int i, n;
jk_uriEnv_t *globalEnv;
if (uriMap->mbean->debug > 5)
env->l->jkLog(env, env->l, JK_LOG_DEBUG,
"uriMap.init() creating global mappings\n");
globalEnv = uriMap->vhosts->get(env, uriMap->vhosts, "*");
n = uriMap->vhosts->size(env, uriMap->vhosts);
for (i = 0; i < n; i++) {
jk_uriEnv_t *uriEnv = uriMap->vhosts->valueAt(env, uriMap->vhosts, i);
/* Duplicate globals for each vhost that has inheritGlobals set */
if (uriEnv != globalEnv && uriEnv->inherit_globals) {
int j, m;
env->l->jkLog(env, env->l, JK_LOG_DEBUG,
"uriMap.init() global for %s\n", uriEnv->name);
m = globalEnv->webapps->size(env, globalEnv->webapps);
for (j = 0; j < m; j++) {
jk_uriEnv_t *ctxEnv;
jk_uriEnv_t *appEnv;
int k, l;
ctxEnv =
globalEnv->webapps->valueAt(env, globalEnv->webapps, j);
appEnv =
uriEnv->webapps->get(env, uriEnv->webapps,
ctxEnv->contextPath);
/* Create the webapp if it doesn't exists on the selected vhost */
if (!appEnv) {
appEnv =
jk2_uriMap_duplicateContext(env, uriMap, uriEnv,
ctxEnv);
uriEnv->webapps->put(env, uriEnv->webapps,
appEnv->contextPath, appEnv, NULL);
env->l->jkLog(env, env->l, JK_LOG_DEBUG,
"uriMap.init() creating global webapp %s for %s\n",
appEnv->contextPath, uriEnv->name);
}
/* Fix the exact matches */
l = ctxEnv->exactMatch->size(env, ctxEnv->exactMatch);
for (k = 0; k < l; k++) {
jk_uriEnv_t *mapEnv;
jk_uriEnv_t *newEnv;
mapEnv =
ctxEnv->exactMatch->valueAt(env, ctxEnv->exactMatch,
k);
newEnv =
appEnv->exactMatch->get(env, appEnv->exactMatch,
mapEnv->uri);
/* Create the new exact match uri */
if (!newEnv) {
newEnv =
jk2_uriMap_duplicateUri(env, uriMap, uriEnv,
mapEnv);
appEnv->exactMatch->put(env, appEnv->exactMatch,
newEnv->name, newEnv, NULL);
}
}
/* Fix the prefix matches */
l = ctxEnv->prefixMatch->size(env, ctxEnv->prefixMatch);
for (k = 0; k < l; k++) {
jk_uriEnv_t *mapEnv;
jk_uriEnv_t *newEnv;
mapEnv =
ctxEnv->prefixMatch->valueAt(env, ctxEnv->prefixMatch,
k);
newEnv =
appEnv->prefixMatch->get(env, appEnv->prefixMatch,
mapEnv->uri);
/* Create the new prefix match uri */
if (!newEnv) {
newEnv =
jk2_uriMap_duplicateUri(env, uriMap, uriEnv,
mapEnv);
appEnv->prefixMatch->put(env, appEnv->prefixMatch,
newEnv->name, newEnv, NULL);
}
}
/* Fix the suffix matches */
l = ctxEnv->suffixMatch->size(env, ctxEnv->suffixMatch);
for (k = 0; k < l; k++) {
jk_uriEnv_t *mapEnv;
jk_uriEnv_t *newEnv;
mapEnv =
ctxEnv->suffixMatch->valueAt(env, ctxEnv->suffixMatch,
k);
newEnv =
appEnv->suffixMatch->get(env, appEnv->suffixMatch,
mapEnv->uri);
/* Create the new suffix match uri */
if (!newEnv) {
newEnv =
jk2_uriMap_duplicateUri(env, uriMap, uriEnv,
mapEnv);
appEnv->suffixMatch->put(env, appEnv->prefixMatch,
newEnv->name, newEnv, NULL);
}
}
uriEnv->webapps->put(env, uriEnv->webapps,
appEnv->contextPath, appEnv, NULL);
}
}
}
return JK_OK;
}
static int jk2_uriMap_init(jk_env_t *env, jk_uriMap_t *uriMap)
{
int rc = JK_OK;
jk_workerEnv_t *workerEnv = uriMap->workerEnv;
jk_bean_t *mbean = env->getBean2(env, "uri", "*");
/* create the default server */
if (mbean == NULL) {
mbean = env->createBean2(env, workerEnv->pool, "uri", "*");
if (mbean == NULL || mbean->object == NULL) {
env->l->jkLog(env, env->l, JK_LOG_ERROR,
"uriMap.factory() Fail to create default host\n");
return JK_ERR;
}
}
/* Create virtual hosts and initialize them */
jk2_uriMap_createHosts(env, uriMap);
/* Create webapps and initialize them */
jk2_uriMap_createWebapps(env, uriMap);
/* All other mappings are added in the right context leaf. */
if ((rc = jk2_uriMap_createMappings(env, uriMap)) != JK_OK)
return rc;
/* Fix the global mappings for virtual hosts */
rc = jk2_uriMap_createGlobals(env, uriMap);
return rc;
}
static void jk2_uriMap_destroy(jk_env_t *env, jk_uriMap_t *uriMap)
{
if (uriMap->mbean->debug > 0)
env->l->jkLog(env, env->l, JK_LOG_DEBUG, "uriMap.destroy()\n");
/* this can't be null ( or a NPE would have been generated */
uriMap->pool->close(env, uriMap->pool);
}
/* returns the index of the last occurrence of the 'ch' character
if ch=='\0' returns the length of the string str */
static INLINE int jk2_last_index_of(const char *str, char ch)
{
const char *str_minus_one = str - 1;
const char *s = str + strlen(str);
while (s != str_minus_one && ch != *s) {
--s;
}
return (s - str);
}
/* find the suffix - only once. We also make sure
we check only the last component, as required by
servlet spec
*/
static INLINE const char *jk2_findExtension(jk_env_t *env, const char *uri)
{
int suffix_start;
const char *suffix;
for (suffix_start = strlen(uri) - 1; suffix_start > 0; suffix_start--) {
if ('.' == uri[suffix_start] || '/' == uri[suffix_start])
break;
}
if ('.' != uri[suffix_start]) {
suffix_start = -1;
suffix = NULL;
}
else {
suffix_start++;
suffix = uri + suffix_start;
}
return suffix;
}
#define SAFE_URI_SIZE 8192
static jk_uriEnv_t *jk2_uriMap_getHostCache(jk_env_t *env,
jk_uriMap_t *uriMap,
const char *vhost, int port)
{
char key[MAX_HOST_LENGTH];
char portSuffix[32];
int vhostLen;
if (!vhost && !port)
return uriMap->vhosts->get(env, uriMap->vhosts, "*");
if (!vhost)
vhost = "*";
vhostLen = strlen(vhost);
strncpy(key, vhost, MAX_HOST_LENGTH);
if (vhostLen < MAX_HOST_LENGTH - 1) {
sprintf(portSuffix, ":%d", port);
strncat(key + vhostLen, portSuffix, MAX_HOST_LENGTH);
}
key[MAX_HOST_LENGTH - 1] = 0;
return uriMap->vhcache->get(env, uriMap->vhcache, key);
}
static void jk2_uriMap_addHostCache(jk_env_t *env, jk_uriMap_t *uriMap,
const char *vhost, int port,
jk_uriEnv_t *hostEnv)
{
char *key;
if (!vhost)
vhost = "*";
key = uriMap->pool->calloc(env, uriMap->pool, strlen(vhost) + 8);
sprintf(key, "%s:%d", vhost, port);
uriMap->vhcache->add(env, uriMap->vhcache, key, hostEnv);
}
static jk_uriEnv_t *jk2_uriMap_mapUri(jk_env_t *env, jk_uriMap_t *uriMap,
const char *vhost, int port,
const char *uri)
{
char *url_rewrite = NULL;
int uriLen;
jk_uriEnv_t *hostEnv;
jk_uriEnv_t *ctxEnv;
jk_uriEnv_t *match;
/* Ugly hack to avoid using non-thread safe code.
Modify the uri in place for uri session encoding, then
restore it to the original. That works since the processing
happens in a single thred. A better solution is to allocate
the jk_ws_service and it's pool and pass it as param */
char origChar = '\0';
/* XXX - need to make sure prefix match take precedence over
extension match ( now it doesn't )
*/
if (uriMap == NULL || uri == NULL)
return NULL;
if (uriMap->mbean->debug > 1)
env->l->jkLog(env, env->l, JK_LOG_DEBUG,
"uriMap.mapUri() hostname %s port %d uri %s\n", vhost,
port, uri);
if (uri[0] != '/') {
env->l->jkLog(env, env->l, JK_LOG_ERROR,
"uriMap.mapUri() uri must start with /\n");
return NULL;
}
hostEnv = jk2_uriMap_getHostCache(env, uriMap, vhost, port);
if (!hostEnv) {
hostEnv = jk2_uriMap_hostMap(env, uriMap, vhost, port);
if (!hostEnv) {
env->l->jkLog(env, env->l, JK_LOG_INFO,
"uriMap.mapUri() cannot find host %s/\n", vhost);
return NULL;
}
if (uriMap->mbean->debug > 1)
env->l->jkLog(env, env->l, JK_LOG_DEBUG,
"uriMap.mapUri() caching host %s\n",
hostEnv->virtual);
jk2_uriMap_addHostCache(env, uriMap, vhost, port, hostEnv);
}
else if (uriMap->mbean->debug > 1)
env->l->jkLog(env, env->l, JK_LOG_DEBUG,
"uriMap.mapUri() found host %s\n", hostEnv->virtual);
url_rewrite = strstr(uri, JK_PATH_SESSION_IDENTIFIER);
if (url_rewrite) {
origChar = *url_rewrite;
*url_rewrite = '\0';
if (uriMap->mbean->debug > 0)
env->l->jkLog(env, env->l, JK_LOG_DEBUG,
"uriMap.mapUri() rewrote uri %s \n", uri);
}
uriLen = strlen(uri);
/* Map the context */
ctxEnv = jk2_uriMap_prefixMap(env, uriMap, hostEnv->webapps, uri, uriLen);
if (ctxEnv == NULL) {
if (url_rewrite)
*url_rewrite = origChar;
env->l->jkLog(env, env->l, JK_LOG_INFO,
"uriMap.mapUri() no context %s\n", uri);
return NULL;
}
if (uriMap->mbean->debug > 1)
env->l->jkLog(env, env->l, JK_LOG_DEBUG,
"uriMap.mapUri() found ctx %s\n", ctxEnv->uri);
match = jk2_uriMap_regexpMap(env, uriMap, ctxEnv->regexpMatch, uri);
if (match != NULL) {
/* restore */
if (url_rewrite)
*url_rewrite = origChar;
if (uriMap->mbean->debug > 0)
env->l->jkLog(env, env->l, JK_LOG_DEBUG,
"uriMap.mapUri() regexp match %s %s\n",
uri, match->workerName);
return match;
}
/* As per Servlet spec, do exact match first */
match = jk2_uriMap_exactMap(env, uriMap, ctxEnv->exactMatch, uri, uriLen);
if (match != NULL) {
/* restore */
if (url_rewrite)
*url_rewrite = origChar;
if (uriMap->mbean->debug > 0)
env->l->jkLog(env, env->l, JK_LOG_DEBUG,
"uriMap.mapUri() exact match %s %s\n",
uri, match->workerName);
return match;
}
/* Then prefix match */
match =
jk2_uriMap_prefixMap(env, uriMap, ctxEnv->prefixMatch, uri, uriLen);
if (match != NULL) {
char c = uri[match->prefix_len - 1];
/* XXX Filter prefix matches to allow only exact
matches with an optional path_info or query string at end.
Fixes Bugzilla#12141, needs review..
*/
if ((uriLen > match->prefix_len && (c == '/' || c == '?')) ||
uriLen == match->prefix_len) {
/* restore */
if (url_rewrite)
*url_rewrite = origChar;
if (uriMap->mbean->debug > 0)
env->l->jkLog(env, env->l, JK_LOG_DEBUG,
"uriMap.mapUri() prefix match %s %s\n",
uri, match->workerName);
return match;
}
}
/* Try to find exact match of /uri and prefix /uri/star (*) */
match =
jk2_uriMap_contextMap(env, uriMap, ctxEnv->prefixMatch, uri, uriLen);
if (match != NULL) {
/* restore */
if (url_rewrite)
*url_rewrite = origChar;
if (uriMap->mbean->debug > 0)
env->l->jkLog(env, env->l, JK_LOG_DEBUG,
"uriMap.mapUri() context match %s %s\n",
uri, match->workerName);
return match;
}
/* And do a wild char match at the end */
match = jk2_uriMap_suffixMap(env, uriMap, ctxEnv->suffixMatch, uri, 0);
if (match != NULL) {
/* restore */
if (url_rewrite)
*url_rewrite = origChar;
if (uriMap->mbean->debug > 0)
env->l->jkLog(env, env->l, JK_LOG_DEBUG,
"uriMap.mapUri() extension match %s %s\n",
uri, match->workerName);
return match;
}
/* restore */
if (url_rewrite)
*url_rewrite = origChar;
if (uriMap->mbean->debug > 1)
env->l->jkLog(env, env->l, JK_LOG_DEBUG,
"uriMap.mapUri() no match found\n");
return NULL;
}
int JK_METHOD jk2_uriMap_factory(jk_env_t *env, jk_pool_t *pool,
jk_bean_t *result, const char *type,
const char *name)
{
jk_uriMap_t *uriMap;
uriMap = (jk_uriMap_t *)pool->calloc(env, pool, sizeof(jk_uriMap_t));
if (!uriMap) {
env->l->jkLog(env, env->l, JK_LOG_ERROR,
"uriMap.factory() OutOfMemoryError\n");
return JK_ERR;
}
uriMap->pool = pool;
jk2_map_default_create(env, &uriMap->maps, pool);
jk2_map_default_create(env, &uriMap->vhosts, pool);
jk2_map_default_create(env, &uriMap->vhcache, pool);
uriMap->init = jk2_uriMap_init;
uriMap->destroy = jk2_uriMap_destroy;
uriMap->addUriEnv = jk2_uriMap_addUriEnv;
uriMap->checkUri = jk2_uriMap_checkUri;
uriMap->mapUri = jk2_uriMap_mapUri;
result->object = uriMap;
result->setAttribute = jk2_uriMap_setProperty;
uriMap->mbean = result;
return JK_OK;
}