summaryrefslogtreecommitdiffstats
path: root/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_uri_worker_map.c
diff options
context:
space:
mode:
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.c1191
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;
+}