diff options
author | hongbotian <hongbo.tianhongbo@huawei.com> | 2015-11-30 02:41:33 -0500 |
---|---|---|
committer | hongbotian <hongbo.tianhongbo@huawei.com> | 2015-11-30 02:43:36 -0500 |
commit | 9401f816dd0d9d550fe98a8507224bde51c4b847 (patch) | |
tree | 94f2d7a7893a787bafdca8b5ef063ea316938874 /rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_uri_worker_map.c | |
parent | e8ec7aa8e38a93f5b034ac74cebce5de23710317 (diff) |
upload tomcat
JIRA: BOTTLENECK-7
Change-Id: I875d474869efd76ca203c30b60ebc0c3ee606d0e
Signed-off-by: hongbotian <hongbo.tianhongbo@huawei.com>
Diffstat (limited to 'rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_uri_worker_map.c')
-rw-r--r-- | rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_uri_worker_map.c | 1191 |
1 files changed, 1191 insertions, 0 deletions
diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_uri_worker_map.c b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_uri_worker_map.c new file mode 100644 index 00000000..d652f769 --- /dev/null +++ b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_uri_worker_map.c @@ -0,0 +1,1191 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. * + * * + * Author: Gal Shachor <shachor@il.ibm.com> * + * Author: Mladen Turk <mturk@apache.org> * + * Version: $Revision: 890739 $ * + ***************************************************************************/ + +#include "jk_pool.h" +#include "jk_util.h" +#include "jk_map.h" +#include "jk_mt.h" +#include "jk_uri_worker_map.h" +#include "jk_worker.h" +#include "jk_lb_worker.h" + +#ifdef WIN32 +#define JK_STRCMP strcasecmp +#define JK_STRNCMP strnicmp +#else +#define JK_STRCMP strcmp +#define JK_STRNCMP strncmp +#endif + +#define JK_UWMAP_EXTENSION_REPLY_TIMEOUT "reply_timeout=" +#define JK_UWMAP_EXTENSION_ACTIVE "active=" +#define JK_UWMAP_EXTENSION_DISABLED "disabled=" +#define JK_UWMAP_EXTENSION_STOPPED "stopped=" +#define JK_UWMAP_EXTENSION_FAIL_ON_STATUS "fail_on_status=" +#define JK_UWMAP_EXTENSION_USE_SRV_ERRORS "use_server_errors=" + +#define IND_SWITCH(x) (((x)+1) % 2) +#define IND_THIS(x) ((x)[uw_map->index]) +#define IND_NEXT(x) ((x)[IND_SWITCH(uw_map->index)]) + +#define STRNULL_FOR_NULL(x) ((x) ? (x) : "(null)") + +static const char *uri_worker_map_source_type[] = { + "unknown", + SOURCE_TYPE_TEXT_WORKERDEF, + SOURCE_TYPE_TEXT_JKMOUNT, + SOURCE_TYPE_TEXT_URIMAP, + SOURCE_TYPE_TEXT_DISCOVER, + NULL +}; + + +/* Return the string representation of the uwr source */ +const char *uri_worker_map_get_source(uri_worker_record_t *uwr, jk_logger_t *l) +{ + return uri_worker_map_source_type[uwr->source_type]; +} + +/* Return the string representation of the uwr match type */ +char *uri_worker_map_get_match(uri_worker_record_t *uwr, char *buf, jk_logger_t *l) +{ + unsigned int match; + + buf[0] = '\0'; + match = uwr->match_type; + + if (match & MATCH_TYPE_DISABLED) + strcat(buf, "Disabled "); +/* deprecated + if (match & MATCH_TYPE_STOPPED) + strcat(buf, "Stopped "); + */ + if (match & MATCH_TYPE_NO_MATCH) + strcat(buf, "Unmount "); + if (match & MATCH_TYPE_EXACT) + strcat(buf, "Exact"); + else if (match & MATCH_TYPE_WILDCHAR_PATH) + strcat(buf, "Wildchar"); +/* deprecated + else if (match & MATCH_TYPE_CONTEXT) + strcat(buf, "Context"); + else if (match & MATCH_TYPE_CONTEXT_PATH) + strcat(buf, "Context Path"); + else if (match & MATCH_TYPE_SUFFIX) + strcat(buf, "Suffix"); + else if (match & MATCH_TYPE_GENERAL_SUFFIX) + return "General Suffix"; + */ + else + strcat(buf, "Unknown"); + return buf; +} + +/* + * Given context uri, count the number of path tokens. + * + * Servlet specification 2.4, SRV.11.1 says + + * The container will recursively try tomatch the longest + * path-prefix. This is done by stepping down the path tree a + * directory at a time, using the / character as a path + * separator. The longest match determines the servlet selected. + * + * The implication seems to be `most uri path elements is most exact'. + * This is a little helper function to count uri tokens, so we can + * keep the worker map sorted with most specific first. + */ +static int worker_count_context_uri_tokens(const char * context) +{ + const char * c = context; + int count = 0; + while (c && *c) { + if ('/' == *c++) + count++; + } + return count; +} + +static int worker_compare(const void *elem1, const void *elem2) +{ + uri_worker_record_t *e1 = *(uri_worker_record_t **)elem1; + uri_worker_record_t *e2 = *(uri_worker_record_t **)elem2; + int e1_tokens = 0; + int e2_tokens = 0; + + e1_tokens = worker_count_context_uri_tokens(e1->context); + e2_tokens = worker_count_context_uri_tokens(e2->context); + + if (e1_tokens != e2_tokens) { + return (e2_tokens - e1_tokens); + } + /* given the same number of URI tokens, use character + * length as a tie breaker + */ + if(e2->context_len != e1->context_len) + return ((int)e2->context_len - (int)e1->context_len); + + return ((int)e2->source_type - (int)e1->source_type); +} + +static void worker_qsort(jk_uri_worker_map_t *uw_map) +{ + + /* Sort remaining args using Quicksort algorithm: */ + qsort((void *)IND_NEXT(uw_map->maps), IND_NEXT(uw_map->size), + sizeof(uri_worker_record_t *), worker_compare ); + +} + +/* Dump the map contents - only call if debug log is active. */ +static void uri_worker_map_dump(jk_uri_worker_map_t *uw_map, + const char *reason, jk_logger_t *l) +{ + JK_TRACE_ENTER(l); + if (uw_map) { + int i, off, k; + uri_worker_record_t *uwr = NULL; + char buf[32]; + jk_log(l, JK_LOG_DEBUG, "uri map dump %s: index=%d file='%s' reject_unsafe=%d " + "reload=%d modified=%d checked=%d", + reason, uw_map->index, STRNULL_FOR_NULL(uw_map->fname), uw_map->reject_unsafe, + uw_map->reload, uw_map->modified, uw_map->checked); + for(i=0;i<=1;i++) { + jk_log(l, JK_LOG_DEBUG, "generation %d: size=%d nosize=%d capacity=%d", + i, uw_map->size[i], uw_map->nosize[i], uw_map->capacity[i], uw_map->maps[i]); + } + + off = uw_map->index; + for(i=0;i<=1;i++) { + unsigned int j; + k = (i + off) % 2; + for (j = 0; j < uw_map->size[k]; j++) { + uwr = uw_map->maps[k][j]; + jk_log(l, JK_LOG_DEBUG, "%s (%d) map #%d: uri=%s worker=%s context=%s " + "source=%s type=%s len=%d", + i ? "NEXT" : "THIS", i, j, + STRNULL_FOR_NULL(uwr->uri), STRNULL_FOR_NULL(uwr->worker_name), + STRNULL_FOR_NULL(uwr->context), STRNULL_FOR_NULL(uri_worker_map_get_source(uwr,l)), + STRNULL_FOR_NULL(uri_worker_map_get_match(uwr,buf,l)), uwr->context_len); + } + } + } + JK_TRACE_EXIT(l); +} + + +int uri_worker_map_alloc(jk_uri_worker_map_t **uw_map_p, + jk_map_t *init_data, jk_logger_t *l) +{ + int i; + + JK_TRACE_ENTER(l); + + if (uw_map_p) { + int rc; + jk_uri_worker_map_t *uw_map; + *uw_map_p = (jk_uri_worker_map_t *)calloc(1, sizeof(jk_uri_worker_map_t)); + uw_map = *uw_map_p; + + JK_INIT_CS(&(uw_map->cs), rc); + if (rc == JK_FALSE) { + jk_log(l, JK_LOG_ERROR, + "creating thread lock (errno=%d)", + errno); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + jk_open_pool(&(uw_map->p), + uw_map->buf, sizeof(jk_pool_atom_t) * BIG_POOL_SIZE); + for(i=0;i<=1;i++) { + jk_open_pool(&(uw_map->p_dyn[i]), + uw_map->buf_dyn[i], sizeof(jk_pool_atom_t) * BIG_POOL_SIZE); + uw_map->size[i] = 0; + uw_map->nosize[i] = 0; + uw_map->capacity[i] = 0; + uw_map->maps[i] = NULL; + } + uw_map->index = 0; + uw_map->fname = NULL; + uw_map->reject_unsafe = 0; + uw_map->reload = JK_URIMAP_DEF_RELOAD; + uw_map->modified = 0; + uw_map->checked = 0; + + if (init_data) + rc = uri_worker_map_open(uw_map, init_data, l); + JK_TRACE_EXIT(l); + return rc; + } + + JK_LOG_NULL_PARAMS(l); + JK_TRACE_EXIT(l); + + return JK_FALSE; +} + +static int uri_worker_map_close(jk_uri_worker_map_t *uw_map, jk_logger_t *l) +{ + JK_TRACE_ENTER(l); + + if (uw_map) { + int i; + JK_DELETE_CS(&(uw_map->cs), i); + jk_close_pool(&uw_map->p_dyn[0]); + jk_close_pool(&uw_map->p_dyn[1]); + jk_close_pool(&uw_map->p); + JK_TRACE_EXIT(l); + return JK_TRUE; + } + + JK_LOG_NULL_PARAMS(l); + JK_TRACE_EXIT(l); + return JK_FALSE; +} + +int uri_worker_map_free(jk_uri_worker_map_t **uw_map, jk_logger_t *l) +{ + JK_TRACE_ENTER(l); + + if (uw_map && *uw_map) { + uri_worker_map_close(*uw_map, l); + free(*uw_map); + *uw_map = NULL; + JK_TRACE_EXIT(l); + return JK_TRUE; + } + else + JK_LOG_NULL_PARAMS(l); + + JK_TRACE_EXIT(l); + return JK_FALSE; +} + +/* + * Ensure there will be memory in context info to store Context Bases + */ + +#define UW_INC_SIZE 4 /* 4 URI->WORKER STEP */ + +static int uri_worker_map_realloc(jk_uri_worker_map_t *uw_map) +{ + if (IND_NEXT(uw_map->size) == IND_NEXT(uw_map->capacity)) { + uri_worker_record_t **uwr; + int capacity = IND_NEXT(uw_map->capacity) + UW_INC_SIZE; + + uwr = + (uri_worker_record_t **) jk_pool_alloc(&IND_NEXT(uw_map->p_dyn), + sizeof(uri_worker_record_t + *) * capacity); + + if (!uwr) + return JK_FALSE; + + if (IND_NEXT(uw_map->capacity) && IND_NEXT(uw_map->maps)) + memcpy(uwr, IND_NEXT(uw_map->maps), + sizeof(uri_worker_record_t *) * IND_NEXT(uw_map->capacity)); + + IND_NEXT(uw_map->maps) = uwr; + IND_NEXT(uw_map->capacity) = capacity; + } + + return JK_TRUE; +} + + +/* + * Delete all entries of a given source type + */ + +static int uri_worker_map_clear(jk_uri_worker_map_t *uw_map, + jk_logger_t *l) +{ + uri_worker_record_t *uwr = NULL; + unsigned int i; + unsigned int new_size = 0; + unsigned int new_nosize = 0; + + JK_TRACE_ENTER(l); + + IND_NEXT(uw_map->maps) = + (uri_worker_record_t **) jk_pool_alloc(&(IND_NEXT(uw_map->p_dyn)), + sizeof(uri_worker_record_t + *) * IND_THIS(uw_map->size)); + IND_NEXT(uw_map->capacity) = IND_THIS(uw_map->size); + IND_NEXT(uw_map->size) = 0; + IND_NEXT(uw_map->nosize) = 0; + for (i = 0; i < IND_THIS(uw_map->size); i++) { + uwr = IND_THIS(uw_map->maps)[i]; + if (uwr->source_type == SOURCE_TYPE_URIMAP) { + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "deleting map rule '%s=%s' source '%s'", + uwr->context, uwr->worker_name, uri_worker_map_get_source(uwr, l)); + } + else { + IND_NEXT(uw_map->maps)[new_size] = uwr; + new_size++; + if (uwr->match_type & MATCH_TYPE_NO_MATCH) + new_nosize++; + } + } + IND_NEXT(uw_map->size) = new_size; + IND_NEXT(uw_map->nosize) = new_nosize; + + JK_TRACE_EXIT(l); + return JK_TRUE; +} + +static void extract_activation(jk_uri_worker_map_t *uw_map, + uri_worker_record_t *uwr, + lb_worker_t *lb, + int *activations, + char *workers, + int activation, + jk_logger_t *l) +{ + unsigned int i; + jk_pool_t *p; + char *worker; +#ifdef _MT_CODE_PTHREAD + char *lasts; +#endif + + JK_TRACE_ENTER(l); + + if (uwr->source_type == SOURCE_TYPE_URIMAP) + p = &IND_NEXT(uw_map->p_dyn); + else + p = &uw_map->p; + worker = jk_pool_strdup(p, workers); + +#ifdef _MT_CODE_PTHREAD + for (worker = strtok_r(worker, ", ", &lasts); + worker; worker = strtok_r(NULL, ", ", &lasts)) { +#else + for (worker = strtok(worker, ", "); worker; worker = strtok(NULL, ", ")) { +#endif + for (i=0; i<lb->num_of_workers; i++) { + if (!strcmp(worker, lb->lb_workers[i].name)) { + if (activations[i] != JK_LB_ACTIVATION_UNSET) + jk_log(l, JK_LOG_WARNING, + "inconsistent activation overwrite for member %s " + "of load balancer %s: '%s' replaced by '%s'", + worker, lb->name, + jk_lb_get_activation_direct(activations[i], l), + jk_lb_get_activation_direct(activation, l)); + activations[i] = activation; + break; + } + } + if (i >= lb->num_of_workers) + jk_log(l, JK_LOG_WARNING, + "could not find member %s of load balancer %s", + worker, lb->name); + } + + JK_TRACE_EXIT(l); + +} + +static void extract_fail_on_status(jk_uri_worker_map_t *uw_map, + uri_worker_record_t *uwr, + jk_logger_t *l) +{ + unsigned int i; + int j; + int cnt = 1; + jk_pool_t *p; + char *status; +#ifdef _MT_CODE_PTHREAD + char *lasts; +#endif + + JK_TRACE_ENTER(l); + + for (i=0; i<strlen(uwr->extensions.fail_on_status_str); i++) { + if (uwr->extensions.fail_on_status_str[i] == ',' || + uwr->extensions.fail_on_status_str[i] == ' ') + cnt++; + } + uwr->extensions.fail_on_status_size = cnt; + + if (uwr->source_type == SOURCE_TYPE_URIMAP) + p = &IND_NEXT(uw_map->p_dyn); + else + p = &uw_map->p; + status = jk_pool_strdup(p, uwr->extensions.fail_on_status_str); + uwr->extensions.fail_on_status = (int *)jk_pool_alloc(p, + uwr->extensions.fail_on_status_size * sizeof(int)); + if (!uwr->extensions.fail_on_status) { + jk_log(l, JK_LOG_ERROR, + "can't alloc extensions fail_on_status list"); + JK_TRACE_EXIT(l); + return; + } else if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "Allocated fail_on_status array of size %d for worker %s", + uwr->extensions.fail_on_status_size, uwr->worker_name); + + + for (j=0; j<uwr->extensions.fail_on_status_size; j++) { + uwr->extensions.fail_on_status[j] = 0; + } + + cnt = 0; +#ifdef _MT_CODE_PTHREAD + for (status = strtok_r(status, ", ", &lasts); + status; status = strtok_r(NULL, ", ", &lasts)) { +#else + for (status = strtok(status, ", "); status; status = strtok(NULL, ", ")) { +#endif + uwr->extensions.fail_on_status[cnt] = atoi(status); + cnt++; + } + + JK_TRACE_EXIT(l); + +} + +void uri_worker_map_switch(jk_uri_worker_map_t *uw_map, jk_logger_t *l) +{ + int new_index; + + JK_TRACE_ENTER(l); + + if (uw_map) { + new_index = IND_SWITCH(uw_map->index); + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "Switching uri worker map from index %d to index %d", + uw_map->index, new_index); + uw_map->index = new_index; + jk_reset_pool(&(IND_NEXT(uw_map->p_dyn))); + } + + JK_TRACE_EXIT(l); + +} + +void uri_worker_map_ext(jk_uri_worker_map_t *uw_map, jk_logger_t *l) +{ + unsigned int i; + + JK_TRACE_ENTER(l); + + for (i = 0; i < IND_NEXT(uw_map->size); i++) { + uri_worker_record_t *uwr = IND_NEXT(uw_map->maps)[i]; + jk_worker_t *jw; + if(uwr->match_type & MATCH_TYPE_NO_MATCH) + continue; + jw = wc_get_worker_for_name(uwr->worker_name, l); + if(!jw) { + jk_log(l, JK_LOG_ERROR, + "Could not find worker with name '%s' in uri map post processing.", + uwr->worker_name); + continue; + } + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "Checking extension for worker %d: %s of type %s (%d)", + i, uwr->worker_name, wc_get_name_for_type(jw->type,l), jw->type); + + if (jw->type == JK_LB_WORKER_TYPE && + (uwr->extensions.active || uwr->extensions.disabled || uwr->extensions.stopped)) { + int j; + lb_worker_t *lb = (lb_worker_t *)jw->worker_private; + jk_pool_t *p; + if (!uwr->extensions.activation) { + uwr->extensions.activation_size = lb->num_of_workers; + if (uwr->source_type == SOURCE_TYPE_URIMAP) + p = &IND_NEXT(uw_map->p_dyn); + else + p = &uw_map->p; + uwr->extensions.activation = (int *)jk_pool_alloc(p, + uwr->extensions.activation_size * sizeof(int)); + if (!uwr->extensions.activation) { + jk_log(l, JK_LOG_ERROR, + "can't alloc extensions activation list"); + continue; + } else if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "Allocated activations array of size %d for lb worker %s", + uwr->extensions.activation_size, uwr->worker_name); + for (j=0; j<uwr->extensions.activation_size; j++) { + uwr->extensions.activation[j] = JK_LB_ACTIVATION_UNSET; + } + } + if (uwr->extensions.active) + extract_activation(uw_map, uwr, lb, uwr->extensions.activation, + uwr->extensions.active, JK_LB_ACTIVATION_ACTIVE, l); + if (uwr->extensions.disabled) + extract_activation(uw_map, uwr, lb, uwr->extensions.activation, + uwr->extensions.disabled, JK_LB_ACTIVATION_DISABLED, l); + if (uwr->extensions.stopped) + extract_activation(uw_map, uwr, lb, uwr->extensions.activation, + uwr->extensions.stopped, JK_LB_ACTIVATION_STOPPED, l); + } + else if (uwr->extensions.active) { + jk_log(l, JK_LOG_WARNING, + "Worker %s is not of type lb, activation extension " + JK_UWMAP_EXTENSION_ACTIVE " for %s ignored", + uwr->worker_name, uwr->extensions.active); + } + else if (uwr->extensions.disabled) { + jk_log(l, JK_LOG_WARNING, + "Worker %s is not of type lb, activation extension " + JK_UWMAP_EXTENSION_DISABLED " for %s ignored", + uwr->worker_name, uwr->extensions.disabled); + } + else if (uwr->extensions.stopped) { + jk_log(l, JK_LOG_WARNING, + "Worker %s is not of type lb, activation extension " + JK_UWMAP_EXTENSION_STOPPED " for %s ignored", + uwr->worker_name, uwr->extensions.stopped); + } + if (uwr->extensions.fail_on_status_str) { + extract_fail_on_status(uw_map, uwr, l); + } + } + if (JK_IS_DEBUG_LEVEL(l)) + uri_worker_map_dump(uw_map, "after extension stripping", l); + + JK_TRACE_EXIT(l); + return; + +} + +/* Add new entry to NEXT generation */ +int uri_worker_map_add(jk_uri_worker_map_t *uw_map, + const char *puri, const char *worker, + unsigned int source_type, jk_logger_t *l) +{ + uri_worker_record_t *uwr = NULL; + char *uri; + jk_pool_t *p; + unsigned int match_type = 0; + + JK_TRACE_ENTER(l); + + if (*puri == '-') { + /* Disable urimap. + * This way you can disable already mounted + * context. + */ + match_type = MATCH_TYPE_DISABLED; + puri++; + } + if (*puri == '!') { + match_type |= MATCH_TYPE_NO_MATCH; + puri++; + } + + if (uri_worker_map_realloc(uw_map) == JK_FALSE) { + JK_TRACE_EXIT(l); + return JK_FALSE; + } + if (source_type == SOURCE_TYPE_URIMAP) + p = &IND_NEXT(uw_map->p_dyn); + else + p = &uw_map->p; + + uwr = (uri_worker_record_t *)jk_pool_alloc(p, sizeof(uri_worker_record_t)); + if (!uwr) { + jk_log(l, JK_LOG_ERROR, + "can't alloc map entry"); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + uri = jk_pool_strdup(p, puri); + if (!uri || !worker) { + jk_log(l, JK_LOG_ERROR, + "can't alloc uri/worker strings"); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + + if (*uri == '/') { + char *w; + char *param; +#ifdef _MT_CODE_PTHREAD + char *lasts = NULL; +#endif + + w = jk_pool_strdup(p, worker); + uwr->extensions.reply_timeout = -1; + uwr->extensions.active = NULL; + uwr->extensions.disabled = NULL; + uwr->extensions.stopped = NULL; + uwr->extensions.activation_size = 0; + uwr->extensions.activation = NULL; + uwr->extensions.fail_on_status_size = 0; + uwr->extensions.fail_on_status = NULL; + uwr->extensions.fail_on_status_str = NULL; + uwr->extensions.use_server_error_pages = 0; + +#ifdef _MT_CODE_PTHREAD + param = strtok_r(w, ";", &lasts); +#else + param = strtok(w, ";"); +#endif + if (param) { +#ifdef _MT_CODE_PTHREAD + for (param = strtok_r(NULL, ";", &lasts); param; param = strtok_r(NULL, ";", &lasts)) { +#else + for (param = strtok(NULL, ";"); param; param = strtok(NULL, ";")) { +#endif + if (!strncmp(param, JK_UWMAP_EXTENSION_REPLY_TIMEOUT, strlen(JK_UWMAP_EXTENSION_REPLY_TIMEOUT))) { + uwr->extensions.reply_timeout = atoi(param + strlen(JK_UWMAP_EXTENSION_REPLY_TIMEOUT)); + } + else if (!strncmp(param, JK_UWMAP_EXTENSION_USE_SRV_ERRORS, strlen(JK_UWMAP_EXTENSION_USE_SRV_ERRORS))) { + uwr->extensions.use_server_error_pages = atoi(param + strlen(JK_UWMAP_EXTENSION_USE_SRV_ERRORS)); + } + else if (!strncmp(param, JK_UWMAP_EXTENSION_ACTIVE, strlen(JK_UWMAP_EXTENSION_ACTIVE))) { + if (uwr->extensions.active) + jk_log(l, JK_LOG_WARNING, + "extension '%s' in uri worker map only allowed once", + JK_UWMAP_EXTENSION_ACTIVE); + else + uwr->extensions.active = param + strlen(JK_UWMAP_EXTENSION_ACTIVE); + } + else if (!strncmp(param, JK_UWMAP_EXTENSION_DISABLED, strlen(JK_UWMAP_EXTENSION_DISABLED))) { + if (uwr->extensions.disabled) + jk_log(l, JK_LOG_WARNING, + "extension '%s' in uri worker map only allowed once", + JK_UWMAP_EXTENSION_DISABLED); + else + uwr->extensions.disabled = param + strlen(JK_UWMAP_EXTENSION_DISABLED); + } + else if (!strncmp(param, JK_UWMAP_EXTENSION_STOPPED, strlen(JK_UWMAP_EXTENSION_STOPPED))) { + if (uwr->extensions.stopped) + jk_log(l, JK_LOG_WARNING, + "extension '%s' in uri worker map only allowed once", + JK_UWMAP_EXTENSION_STOPPED); + else + uwr->extensions.stopped = param + strlen(JK_UWMAP_EXTENSION_STOPPED); + } + else if (!strncmp(param, JK_UWMAP_EXTENSION_FAIL_ON_STATUS, strlen(JK_UWMAP_EXTENSION_FAIL_ON_STATUS))) { + if (uwr->extensions.fail_on_status_str) + jk_log(l, JK_LOG_WARNING, + "extension '%s' in uri worker map only allowed once", + JK_UWMAP_EXTENSION_FAIL_ON_STATUS); + else + uwr->extensions.fail_on_status_str = param + strlen(JK_UWMAP_EXTENSION_FAIL_ON_STATUS); + } + else { + jk_log(l, JK_LOG_WARNING, + "unknown extension '%s' in uri worker map", + param); + } + } + } + + uwr->source_type = source_type; + uwr->worker_name = w; + uwr->uri = uri; + uwr->context = uri; + uwr->context_len = strlen(uwr->context); + if (strchr(uri, '*') || + strchr(uri, '?')) { + /* Something like + * /context/ * /user/ * + * /context/ *.suffix + */ + match_type |= MATCH_TYPE_WILDCHAR_PATH; + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "wildchar rule '%s=%s' source '%s' was added", + uwr->context, uwr->worker_name, uri_worker_map_get_source(uwr, l)); + + } + else { + /* Something like: JkMount /login/j_security_check ajp13 */ + match_type |= MATCH_TYPE_EXACT; + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "exact rule '%s=%s' source '%s' was added", + uwr->context, uwr->worker_name, uri_worker_map_get_source(uwr, l)); + } + } + else { + /* + * JFC: please check... + * Not sure what to do, but I try to prevent problems. + * I have fixed jk_mount_context() in apaches/mod_jk.c so we should + * not arrive here when using Apache. + */ + jk_log(l, JK_LOG_ERROR, + "invalid context '%s': does not begin with '/'", + uri); + JK_TRACE_EXIT(l); + return JK_FALSE; + } + uwr->match_type = match_type; + IND_NEXT(uw_map->maps)[IND_NEXT(uw_map->size)] = uwr; + IND_NEXT(uw_map->size)++; + if (match_type & MATCH_TYPE_NO_MATCH) { + /* If we split the mappings this one will be calculated */ + IND_NEXT(uw_map->nosize)++; + } + worker_qsort(uw_map); + JK_TRACE_EXIT(l); + return JK_TRUE; +} + +int uri_worker_map_open(jk_uri_worker_map_t *uw_map, + jk_map_t *init_data, jk_logger_t *l) +{ + int rc = JK_TRUE; + + JK_TRACE_ENTER(l); + + if (uw_map) { + int sz = jk_map_size(init_data); + + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "rule map size is %d", + sz); + + if (sz > 0) { + int i; + for (i = 0; i < sz; i++) { + const char *u = jk_map_name_at(init_data, i); + const char *w = jk_map_value_at(init_data, i); + /* Multiple mappings like : + * /servlets-examples|/ * + * will create two mappings: + * /servlets-examples + * and: + * /servlets-examples/ * + */ + if (strchr(u, '|')) { + char *s, *r = strdup(u); + s = strchr(r, '|'); + *(s++) = '\0'; + /* Add first mapping */ + if (!uri_worker_map_add(uw_map, r, w, SOURCE_TYPE_JKMOUNT, l)) { + jk_log(l, JK_LOG_ERROR, + "invalid mapping rule %s->%s", r, w); + rc = JK_FALSE; + } + for (; *s; s++) + *(s - 1) = *s; + *(s - 1) = '\0'; + /* add second mapping */ + if (!uri_worker_map_add(uw_map, r, w, SOURCE_TYPE_JKMOUNT, l)) { + jk_log(l, JK_LOG_ERROR, + "invalid mapping rule %s->%s", r, w); + rc = JK_FALSE; + } + free(r); + } + else if (!uri_worker_map_add(uw_map, u, w, SOURCE_TYPE_JKMOUNT, l)) { + jk_log(l, JK_LOG_ERROR, + "invalid mapping rule %s->%s", + u, w); + rc = JK_FALSE; + break; + } + if (rc == JK_FALSE) + break; + } + } + + if (rc == JK_FALSE) { + jk_log(l, JK_LOG_ERROR, + "there was an error, freeing buf"); + jk_close_pool(&uw_map->p_dyn[0]); + jk_close_pool(&uw_map->p_dyn[1]); + jk_close_pool(&uw_map->p); + } + else if (JK_IS_DEBUG_LEVEL(l)) + uri_worker_map_dump(uw_map, "after map open", l); + } + + JK_TRACE_EXIT(l); + return rc; +} + +static int find_match(jk_uri_worker_map_t *uw_map, + const char *url, jk_logger_t *l) +{ + unsigned int i; + + JK_TRACE_ENTER(l); + + for (i = 0; i < IND_THIS(uw_map->size); i++) { + uri_worker_record_t *uwr = IND_THIS(uw_map->maps)[i]; + + /* Check for match types */ + if ((uwr->match_type & MATCH_TYPE_DISABLED) || + (uwr->match_type & MATCH_TYPE_NO_MATCH)) + continue; + + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, "Attempting to map context URI '%s=%s' source '%s'", + uwr->context, uwr->worker_name, uri_worker_map_get_source(uwr, l)); + + if (uwr->match_type & MATCH_TYPE_WILDCHAR_PATH) { + /* Map is already sorted by context_len */ + if (jk_wildchar_match(url, uwr->context, +#ifdef WIN32 + 0 +#else + 0 +#endif + ) == 0) { + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "Found a wildchar match '%s=%s'", + uwr->context, uwr->worker_name); + JK_TRACE_EXIT(l); + return i; + } + } + else if (JK_STRNCMP(uwr->context, url, uwr->context_len) == 0) { + if (strlen(url) == uwr->context_len) { + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "Found an exact match '%s=%s'", + uwr->context, uwr->worker_name); + JK_TRACE_EXIT(l); + return i; + } + } + } + + JK_TRACE_EXIT(l); + return -1; +} + +static int is_nomatch(jk_uri_worker_map_t *uw_map, + const char *uri, int match, + jk_logger_t *l) +{ + unsigned int i; + const char *worker = IND_THIS(uw_map->maps)[match]->worker_name; + + JK_TRACE_ENTER(l); + + for (i = 0; i < IND_THIS(uw_map->size); i++) { + uri_worker_record_t *uwr = IND_THIS(uw_map->maps)[i]; + + /* Check only nomatch mappings */ + if (!(uwr->match_type & MATCH_TYPE_NO_MATCH) || + (uwr->match_type & MATCH_TYPE_DISABLED)) + continue; + /* Check only matching workers */ + if (strcmp(uwr->worker_name, worker) && + strcmp(uwr->worker_name, "*")) + continue; + if (uwr->match_type & MATCH_TYPE_WILDCHAR_PATH) { + /* Map is already sorted by context_len */ + if (jk_wildchar_match(uri, uwr->context, +#ifdef WIN32 + 0 +#else + 0 +#endif + ) == 0) { + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "Found a wildchar no match '%s=%s' source '%s'", + uwr->context, uwr->worker_name, uri_worker_map_get_source(uwr, l)); + JK_TRACE_EXIT(l); + return JK_TRUE; + } + } + else if (JK_STRNCMP(uwr->context, uri, uwr->context_len) == 0) { + if (strlen(uri) == uwr->context_len) { + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "Found an exact no match '%s=%s' source '%s'", + uwr->context, uwr->worker_name, uri_worker_map_get_source(uwr, l)); + JK_TRACE_EXIT(l); + return JK_TRUE; + } + } + } + + JK_TRACE_EXIT(l); + return JK_FALSE; +} + +const char *map_uri_to_worker_ext(jk_uri_worker_map_t *uw_map, + const char *uri, const char *vhost, + rule_extension_t **extensions, + int *index, + jk_logger_t *l) +{ + unsigned int i; + unsigned int vhost_len; + int reject_unsafe; + int rv = -1; + char url[JK_MAX_URI_LEN+1]; + + JK_TRACE_ENTER(l); + + if (!uw_map || !uri || !extensions) { + JK_LOG_NULL_PARAMS(l); + JK_TRACE_EXIT(l); + return NULL; + } + *extensions = NULL; + if (index) + *index = -1; + if (*uri != '/') { + jk_log(l, JK_LOG_WARNING, + "Uri %s is invalid. Uri must start with /", uri); + JK_TRACE_EXIT(l); + return NULL; + } + if (uw_map->fname) { + uri_worker_map_update(uw_map, 0, l); + if (!IND_THIS(uw_map->size)) { + jk_log(l, JK_LOG_INFO, + "No worker maps defined for %s.", + uw_map->fname); + JK_TRACE_EXIT(l); + return NULL; + } + } + /* Make the copy of the provided uri and strip + * everything after the first ';' char. + */ + reject_unsafe = uw_map->reject_unsafe; + vhost_len = 0; + /* + * In case we got a vhost, we prepend a slash + * and the vhost to the url in order to enable + * vhost mapping rules especially for IIS. + */ + if (vhost) { + int off = 0; + /* Add leading '/' if necessary */ + if (vhost[0] != '/') { + url[0] = '/'; + off = 1; + } + /* Size including leading slash. */ + vhost_len = strlen(vhost); + if (vhost_len + off >= JK_MAX_URI_LEN) { + vhost_len = 0; + jk_log(l, JK_LOG_WARNING, + "Host prefix %s for URI %s is invalid and will be ignored." + " It must be smaller than %d chars", + vhost, JK_MAX_URI_LEN - off); + } + else { + strncpy(&url[off], vhost, vhost_len + 1); + } + vhost_len += off; + } + for (i = 0; i < strlen(uri); i++) { + if (i == JK_MAX_URI_LEN) { + jk_log(l, JK_LOG_WARNING, + "URI %s is invalid. URI must be smaller than %d chars", + uri, JK_MAX_URI_LEN); + JK_TRACE_EXIT(l); + return NULL; + } + if (uri[i] == ';') + break; + else { + url[i + vhost_len] = uri[i]; + if (reject_unsafe && (uri[i] == '%' || uri[i] == '\\')) { + jk_log(l, JK_LOG_INFO, "Potentially unsafe request url '%s' rejected", uri); + JK_TRACE_EXIT(l); + return NULL; + } + } + } + url[i + vhost_len] = '\0'; + + if (JK_IS_DEBUG_LEVEL(l)) { + char *url_rewrite = strstr(uri, JK_PATH_SESSION_IDENTIFIER); + if (url_rewrite) + jk_log(l, JK_LOG_DEBUG, "Found session identifier '%s' in url '%s'", + url_rewrite, uri); + } + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, "Attempting to map URI '%s' from %d maps", + url, IND_THIS(uw_map->size)); + rv = find_match(uw_map, url, l); + /* If this doesn't find a match, try without the vhost. */ + if (rv < 0 && vhost_len) { + rv = find_match(uw_map, &url[vhost_len], l); + } + + /* In case we found a match, check for the unmounts. */ + if (rv >= 0 && IND_THIS(uw_map->nosize)) { + /* Again first including vhost. */ + int rc = is_nomatch(uw_map, url, rv, l); + /* If no unmount was find, try without vhost. */ + if (!rc && vhost_len) + rc = is_nomatch(uw_map, &url[vhost_len], rv, l); + if (rc) { + if (JK_IS_DEBUG_LEVEL(l)) { + jk_log(l, JK_LOG_DEBUG, + "Denying match for worker %s by nomatch rule", + IND_THIS(uw_map->maps)[rv]->worker_name); + } + rv = -1; + } + } + + if (rv >= 0) { + *extensions = &(IND_THIS(uw_map->maps)[rv]->extensions); + if (index) + *index = rv; + JK_TRACE_EXIT(l); + return IND_THIS(uw_map->maps)[rv]->worker_name; + } + JK_TRACE_EXIT(l); + return NULL; +} + +rule_extension_t *get_uri_to_worker_ext(jk_uri_worker_map_t *uw_map, + int index) +{ + if (index >= 0) { + return &(IND_THIS(uw_map->maps)[index]->extensions); + } + else { + return NULL; + } +} + +const char *map_uri_to_worker(jk_uri_worker_map_t *uw_map, + const char *uri, const char *vhost, + jk_logger_t *l) +{ + rule_extension_t *ext; + return map_uri_to_worker_ext(uw_map, uri, vhost, &ext, NULL, l); +} + +int uri_worker_map_load(jk_uri_worker_map_t *uw_map, + jk_logger_t *l) +{ + int rc = JK_FALSE; + jk_map_t *map; + + jk_map_alloc(&map); + if (jk_map_read_properties(map, NULL, uw_map->fname, &uw_map->modified, + JK_MAP_HANDLE_NORMAL, l)) { + int i; + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "Loading urimaps from %s with reload check interval %d seconds", + uw_map->fname, uw_map->reload); + uri_worker_map_clear(uw_map, l); + for (i = 0; i < jk_map_size(map); i++) { + const char *u = jk_map_name_at(map, i); + const char *w = jk_map_value_at(map, i); + /* Multiple mappings like : + * /servlets-examples|/ * + * will create two mappings: + * /servlets-examples + * and: + * /servlets-examples/ * + */ + if (strchr(u, '|')) { + char *s, *r = strdup(u); + s = strchr(r, '|'); + *(s++) = '\0'; + /* Add first mapping */ + if (!uri_worker_map_add(uw_map, r, w, SOURCE_TYPE_URIMAP, l)) { + jk_log(l, JK_LOG_ERROR, + "invalid mapping rule %s->%s", r, w); + } + for (; *s; s++) + *(s - 1) = *s; + *(s - 1) = '\0'; + /* add second mapping */ + if (!uri_worker_map_add(uw_map, r, w, SOURCE_TYPE_URIMAP, l)) { + jk_log(l, JK_LOG_ERROR, + "invalid mapping rule %s->%s", r, w); + } + free(r); + } + else if (!uri_worker_map_add(uw_map, u, w, SOURCE_TYPE_URIMAP, l)) { + jk_log(l, JK_LOG_ERROR, + "invalid mapping rule %s->%s", + u, w); + } + } + uw_map->checked = time(NULL); + if (JK_IS_DEBUG_LEVEL(l)) + uri_worker_map_dump(uw_map, "after file load", l); + rc = JK_TRUE; + } + jk_map_free(&map); + return rc; +} + +int uri_worker_map_update(jk_uri_worker_map_t *uw_map, + int force, jk_logger_t *l) +{ + int rc = JK_TRUE; + time_t now = time(NULL); + + if (force || (uw_map->reload > 0 && difftime(now, uw_map->checked) > + uw_map->reload)) { + struct stat statbuf; + uw_map->checked = now; + if ((rc = jk_stat(uw_map->fname, &statbuf)) == -1) { + jk_log(l, JK_LOG_ERROR, + "Unable to stat the %s (errno=%d)", + uw_map->fname, errno); + return JK_FALSE; + } + if (statbuf.st_mtime == uw_map->modified) { + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "File %s is not modified", + uw_map->fname); + return JK_TRUE; + } + JK_ENTER_CS(&(uw_map->cs), rc); + /* Check if some other thread updated status */ + if (statbuf.st_mtime == uw_map->modified) { + JK_LEAVE_CS(&(uw_map->cs), rc); + if (JK_IS_DEBUG_LEVEL(l)) + jk_log(l, JK_LOG_DEBUG, + "File %s is not modified", + uw_map->fname); + return JK_TRUE; + } + rc = uri_worker_map_load(uw_map, l); + uri_worker_map_ext(uw_map, l); + uri_worker_map_switch(uw_map, l); + JK_LEAVE_CS(&(uw_map->cs), rc); + jk_log(l, JK_LOG_INFO, + "Reloaded urimaps from %s", uw_map->fname); + } + return JK_TRUE; +} |