2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
18 /***************************************************************************
19 * Description: URI to worker map object. *
21 * Author: Gal Shachor <shachor@il.ibm.com> *
22 * Author: Mladen Turk <mturk@apache.org> *
23 * Version: $Revision: 890739 $ *
24 ***************************************************************************/
30 #include "jk_uri_worker_map.h"
31 #include "jk_worker.h"
32 #include "jk_lb_worker.h"
35 #define JK_STRCMP strcasecmp
36 #define JK_STRNCMP strnicmp
38 #define JK_STRCMP strcmp
39 #define JK_STRNCMP strncmp
42 #define JK_UWMAP_EXTENSION_REPLY_TIMEOUT "reply_timeout="
43 #define JK_UWMAP_EXTENSION_ACTIVE "active="
44 #define JK_UWMAP_EXTENSION_DISABLED "disabled="
45 #define JK_UWMAP_EXTENSION_STOPPED "stopped="
46 #define JK_UWMAP_EXTENSION_FAIL_ON_STATUS "fail_on_status="
47 #define JK_UWMAP_EXTENSION_USE_SRV_ERRORS "use_server_errors="
49 #define IND_SWITCH(x) (((x)+1) % 2)
50 #define IND_THIS(x) ((x)[uw_map->index])
51 #define IND_NEXT(x) ((x)[IND_SWITCH(uw_map->index)])
53 #define STRNULL_FOR_NULL(x) ((x) ? (x) : "(null)")
55 static const char *uri_worker_map_source_type[] = {
57 SOURCE_TYPE_TEXT_WORKERDEF,
58 SOURCE_TYPE_TEXT_JKMOUNT,
59 SOURCE_TYPE_TEXT_URIMAP,
60 SOURCE_TYPE_TEXT_DISCOVER,
65 /* Return the string representation of the uwr source */
66 const char *uri_worker_map_get_source(uri_worker_record_t *uwr, jk_logger_t *l)
68 return uri_worker_map_source_type[uwr->source_type];
71 /* Return the string representation of the uwr match type */
72 char *uri_worker_map_get_match(uri_worker_record_t *uwr, char *buf, jk_logger_t *l)
77 match = uwr->match_type;
79 if (match & MATCH_TYPE_DISABLED)
80 strcat(buf, "Disabled ");
82 if (match & MATCH_TYPE_STOPPED)
83 strcat(buf, "Stopped ");
85 if (match & MATCH_TYPE_NO_MATCH)
86 strcat(buf, "Unmount ");
87 if (match & MATCH_TYPE_EXACT)
89 else if (match & MATCH_TYPE_WILDCHAR_PATH)
90 strcat(buf, "Wildchar");
92 else if (match & MATCH_TYPE_CONTEXT)
93 strcat(buf, "Context");
94 else if (match & MATCH_TYPE_CONTEXT_PATH)
95 strcat(buf, "Context Path");
96 else if (match & MATCH_TYPE_SUFFIX)
97 strcat(buf, "Suffix");
98 else if (match & MATCH_TYPE_GENERAL_SUFFIX)
99 return "General Suffix";
102 strcat(buf, "Unknown");
107 * Given context uri, count the number of path tokens.
109 * Servlet specification 2.4, SRV.11.1 says
111 * The container will recursively try tomatch the longest
112 * path-prefix. This is done by stepping down the path tree a
113 * directory at a time, using the / character as a path
114 * separator. The longest match determines the servlet selected.
116 * The implication seems to be `most uri path elements is most exact'.
117 * This is a little helper function to count uri tokens, so we can
118 * keep the worker map sorted with most specific first.
120 static int worker_count_context_uri_tokens(const char * context)
122 const char * c = context;
131 static int worker_compare(const void *elem1, const void *elem2)
133 uri_worker_record_t *e1 = *(uri_worker_record_t **)elem1;
134 uri_worker_record_t *e2 = *(uri_worker_record_t **)elem2;
138 e1_tokens = worker_count_context_uri_tokens(e1->context);
139 e2_tokens = worker_count_context_uri_tokens(e2->context);
141 if (e1_tokens != e2_tokens) {
142 return (e2_tokens - e1_tokens);
144 /* given the same number of URI tokens, use character
145 * length as a tie breaker
147 if(e2->context_len != e1->context_len)
148 return ((int)e2->context_len - (int)e1->context_len);
150 return ((int)e2->source_type - (int)e1->source_type);
153 static void worker_qsort(jk_uri_worker_map_t *uw_map)
156 /* Sort remaining args using Quicksort algorithm: */
157 qsort((void *)IND_NEXT(uw_map->maps), IND_NEXT(uw_map->size),
158 sizeof(uri_worker_record_t *), worker_compare );
162 /* Dump the map contents - only call if debug log is active. */
163 static void uri_worker_map_dump(jk_uri_worker_map_t *uw_map,
164 const char *reason, jk_logger_t *l)
169 uri_worker_record_t *uwr = NULL;
171 jk_log(l, JK_LOG_DEBUG, "uri map dump %s: index=%d file='%s' reject_unsafe=%d "
172 "reload=%d modified=%d checked=%d",
173 reason, uw_map->index, STRNULL_FOR_NULL(uw_map->fname), uw_map->reject_unsafe,
174 uw_map->reload, uw_map->modified, uw_map->checked);
176 jk_log(l, JK_LOG_DEBUG, "generation %d: size=%d nosize=%d capacity=%d",
177 i, uw_map->size[i], uw_map->nosize[i], uw_map->capacity[i], uw_map->maps[i]);
184 for (j = 0; j < uw_map->size[k]; j++) {
185 uwr = uw_map->maps[k][j];
186 jk_log(l, JK_LOG_DEBUG, "%s (%d) map #%d: uri=%s worker=%s context=%s "
187 "source=%s type=%s len=%d",
188 i ? "NEXT" : "THIS", i, j,
189 STRNULL_FOR_NULL(uwr->uri), STRNULL_FOR_NULL(uwr->worker_name),
190 STRNULL_FOR_NULL(uwr->context), STRNULL_FOR_NULL(uri_worker_map_get_source(uwr,l)),
191 STRNULL_FOR_NULL(uri_worker_map_get_match(uwr,buf,l)), uwr->context_len);
199 int uri_worker_map_alloc(jk_uri_worker_map_t **uw_map_p,
200 jk_map_t *init_data, jk_logger_t *l)
208 jk_uri_worker_map_t *uw_map;
209 *uw_map_p = (jk_uri_worker_map_t *)calloc(1, sizeof(jk_uri_worker_map_t));
212 JK_INIT_CS(&(uw_map->cs), rc);
213 if (rc == JK_FALSE) {
214 jk_log(l, JK_LOG_ERROR,
215 "creating thread lock (errno=%d)",
221 jk_open_pool(&(uw_map->p),
222 uw_map->buf, sizeof(jk_pool_atom_t) * BIG_POOL_SIZE);
224 jk_open_pool(&(uw_map->p_dyn[i]),
225 uw_map->buf_dyn[i], sizeof(jk_pool_atom_t) * BIG_POOL_SIZE);
227 uw_map->nosize[i] = 0;
228 uw_map->capacity[i] = 0;
229 uw_map->maps[i] = NULL;
232 uw_map->fname = NULL;
233 uw_map->reject_unsafe = 0;
234 uw_map->reload = JK_URIMAP_DEF_RELOAD;
235 uw_map->modified = 0;
239 rc = uri_worker_map_open(uw_map, init_data, l);
244 JK_LOG_NULL_PARAMS(l);
250 static int uri_worker_map_close(jk_uri_worker_map_t *uw_map, jk_logger_t *l)
256 JK_DELETE_CS(&(uw_map->cs), i);
257 jk_close_pool(&uw_map->p_dyn[0]);
258 jk_close_pool(&uw_map->p_dyn[1]);
259 jk_close_pool(&uw_map->p);
264 JK_LOG_NULL_PARAMS(l);
269 int uri_worker_map_free(jk_uri_worker_map_t **uw_map, jk_logger_t *l)
273 if (uw_map && *uw_map) {
274 uri_worker_map_close(*uw_map, l);
281 JK_LOG_NULL_PARAMS(l);
288 * Ensure there will be memory in context info to store Context Bases
291 #define UW_INC_SIZE 4 /* 4 URI->WORKER STEP */
293 static int uri_worker_map_realloc(jk_uri_worker_map_t *uw_map)
295 if (IND_NEXT(uw_map->size) == IND_NEXT(uw_map->capacity)) {
296 uri_worker_record_t **uwr;
297 int capacity = IND_NEXT(uw_map->capacity) + UW_INC_SIZE;
300 (uri_worker_record_t **) jk_pool_alloc(&IND_NEXT(uw_map->p_dyn),
301 sizeof(uri_worker_record_t
307 if (IND_NEXT(uw_map->capacity) && IND_NEXT(uw_map->maps))
308 memcpy(uwr, IND_NEXT(uw_map->maps),
309 sizeof(uri_worker_record_t *) * IND_NEXT(uw_map->capacity));
311 IND_NEXT(uw_map->maps) = uwr;
312 IND_NEXT(uw_map->capacity) = capacity;
320 * Delete all entries of a given source type
323 static int uri_worker_map_clear(jk_uri_worker_map_t *uw_map,
326 uri_worker_record_t *uwr = NULL;
328 unsigned int new_size = 0;
329 unsigned int new_nosize = 0;
333 IND_NEXT(uw_map->maps) =
334 (uri_worker_record_t **) jk_pool_alloc(&(IND_NEXT(uw_map->p_dyn)),
335 sizeof(uri_worker_record_t
336 *) * IND_THIS(uw_map->size));
337 IND_NEXT(uw_map->capacity) = IND_THIS(uw_map->size);
338 IND_NEXT(uw_map->size) = 0;
339 IND_NEXT(uw_map->nosize) = 0;
340 for (i = 0; i < IND_THIS(uw_map->size); i++) {
341 uwr = IND_THIS(uw_map->maps)[i];
342 if (uwr->source_type == SOURCE_TYPE_URIMAP) {
343 if (JK_IS_DEBUG_LEVEL(l))
344 jk_log(l, JK_LOG_DEBUG,
345 "deleting map rule '%s=%s' source '%s'",
346 uwr->context, uwr->worker_name, uri_worker_map_get_source(uwr, l));
349 IND_NEXT(uw_map->maps)[new_size] = uwr;
351 if (uwr->match_type & MATCH_TYPE_NO_MATCH)
355 IND_NEXT(uw_map->size) = new_size;
356 IND_NEXT(uw_map->nosize) = new_nosize;
362 static void extract_activation(jk_uri_worker_map_t *uw_map,
363 uri_worker_record_t *uwr,
373 #ifdef _MT_CODE_PTHREAD
379 if (uwr->source_type == SOURCE_TYPE_URIMAP)
380 p = &IND_NEXT(uw_map->p_dyn);
383 worker = jk_pool_strdup(p, workers);
385 #ifdef _MT_CODE_PTHREAD
386 for (worker = strtok_r(worker, ", ", &lasts);
387 worker; worker = strtok_r(NULL, ", ", &lasts)) {
389 for (worker = strtok(worker, ", "); worker; worker = strtok(NULL, ", ")) {
391 for (i=0; i<lb->num_of_workers; i++) {
392 if (!strcmp(worker, lb->lb_workers[i].name)) {
393 if (activations[i] != JK_LB_ACTIVATION_UNSET)
394 jk_log(l, JK_LOG_WARNING,
395 "inconsistent activation overwrite for member %s "
396 "of load balancer %s: '%s' replaced by '%s'",
398 jk_lb_get_activation_direct(activations[i], l),
399 jk_lb_get_activation_direct(activation, l));
400 activations[i] = activation;
404 if (i >= lb->num_of_workers)
405 jk_log(l, JK_LOG_WARNING,
406 "could not find member %s of load balancer %s",
414 static void extract_fail_on_status(jk_uri_worker_map_t *uw_map,
415 uri_worker_record_t *uwr,
423 #ifdef _MT_CODE_PTHREAD
429 for (i=0; i<strlen(uwr->extensions.fail_on_status_str); i++) {
430 if (uwr->extensions.fail_on_status_str[i] == ',' ||
431 uwr->extensions.fail_on_status_str[i] == ' ')
434 uwr->extensions.fail_on_status_size = cnt;
436 if (uwr->source_type == SOURCE_TYPE_URIMAP)
437 p = &IND_NEXT(uw_map->p_dyn);
440 status = jk_pool_strdup(p, uwr->extensions.fail_on_status_str);
441 uwr->extensions.fail_on_status = (int *)jk_pool_alloc(p,
442 uwr->extensions.fail_on_status_size * sizeof(int));
443 if (!uwr->extensions.fail_on_status) {
444 jk_log(l, JK_LOG_ERROR,
445 "can't alloc extensions fail_on_status list");
448 } else if (JK_IS_DEBUG_LEVEL(l))
449 jk_log(l, JK_LOG_DEBUG,
450 "Allocated fail_on_status array of size %d for worker %s",
451 uwr->extensions.fail_on_status_size, uwr->worker_name);
454 for (j=0; j<uwr->extensions.fail_on_status_size; j++) {
455 uwr->extensions.fail_on_status[j] = 0;
459 #ifdef _MT_CODE_PTHREAD
460 for (status = strtok_r(status, ", ", &lasts);
461 status; status = strtok_r(NULL, ", ", &lasts)) {
463 for (status = strtok(status, ", "); status; status = strtok(NULL, ", ")) {
465 uwr->extensions.fail_on_status[cnt] = atoi(status);
473 void uri_worker_map_switch(jk_uri_worker_map_t *uw_map, jk_logger_t *l)
480 new_index = IND_SWITCH(uw_map->index);
481 if (JK_IS_DEBUG_LEVEL(l))
482 jk_log(l, JK_LOG_DEBUG,
483 "Switching uri worker map from index %d to index %d",
484 uw_map->index, new_index);
485 uw_map->index = new_index;
486 jk_reset_pool(&(IND_NEXT(uw_map->p_dyn)));
493 void uri_worker_map_ext(jk_uri_worker_map_t *uw_map, jk_logger_t *l)
499 for (i = 0; i < IND_NEXT(uw_map->size); i++) {
500 uri_worker_record_t *uwr = IND_NEXT(uw_map->maps)[i];
502 if(uwr->match_type & MATCH_TYPE_NO_MATCH)
504 jw = wc_get_worker_for_name(uwr->worker_name, l);
506 jk_log(l, JK_LOG_ERROR,
507 "Could not find worker with name '%s' in uri map post processing.",
511 if (JK_IS_DEBUG_LEVEL(l))
512 jk_log(l, JK_LOG_DEBUG,
513 "Checking extension for worker %d: %s of type %s (%d)",
514 i, uwr->worker_name, wc_get_name_for_type(jw->type,l), jw->type);
516 if (jw->type == JK_LB_WORKER_TYPE &&
517 (uwr->extensions.active || uwr->extensions.disabled || uwr->extensions.stopped)) {
519 lb_worker_t *lb = (lb_worker_t *)jw->worker_private;
521 if (!uwr->extensions.activation) {
522 uwr->extensions.activation_size = lb->num_of_workers;
523 if (uwr->source_type == SOURCE_TYPE_URIMAP)
524 p = &IND_NEXT(uw_map->p_dyn);
527 uwr->extensions.activation = (int *)jk_pool_alloc(p,
528 uwr->extensions.activation_size * sizeof(int));
529 if (!uwr->extensions.activation) {
530 jk_log(l, JK_LOG_ERROR,
531 "can't alloc extensions activation list");
533 } else if (JK_IS_DEBUG_LEVEL(l))
534 jk_log(l, JK_LOG_DEBUG,
535 "Allocated activations array of size %d for lb worker %s",
536 uwr->extensions.activation_size, uwr->worker_name);
537 for (j=0; j<uwr->extensions.activation_size; j++) {
538 uwr->extensions.activation[j] = JK_LB_ACTIVATION_UNSET;
541 if (uwr->extensions.active)
542 extract_activation(uw_map, uwr, lb, uwr->extensions.activation,
543 uwr->extensions.active, JK_LB_ACTIVATION_ACTIVE, l);
544 if (uwr->extensions.disabled)
545 extract_activation(uw_map, uwr, lb, uwr->extensions.activation,
546 uwr->extensions.disabled, JK_LB_ACTIVATION_DISABLED, l);
547 if (uwr->extensions.stopped)
548 extract_activation(uw_map, uwr, lb, uwr->extensions.activation,
549 uwr->extensions.stopped, JK_LB_ACTIVATION_STOPPED, l);
551 else if (uwr->extensions.active) {
552 jk_log(l, JK_LOG_WARNING,
553 "Worker %s is not of type lb, activation extension "
554 JK_UWMAP_EXTENSION_ACTIVE " for %s ignored",
555 uwr->worker_name, uwr->extensions.active);
557 else if (uwr->extensions.disabled) {
558 jk_log(l, JK_LOG_WARNING,
559 "Worker %s is not of type lb, activation extension "
560 JK_UWMAP_EXTENSION_DISABLED " for %s ignored",
561 uwr->worker_name, uwr->extensions.disabled);
563 else if (uwr->extensions.stopped) {
564 jk_log(l, JK_LOG_WARNING,
565 "Worker %s is not of type lb, activation extension "
566 JK_UWMAP_EXTENSION_STOPPED " for %s ignored",
567 uwr->worker_name, uwr->extensions.stopped);
569 if (uwr->extensions.fail_on_status_str) {
570 extract_fail_on_status(uw_map, uwr, l);
573 if (JK_IS_DEBUG_LEVEL(l))
574 uri_worker_map_dump(uw_map, "after extension stripping", l);
581 /* Add new entry to NEXT generation */
582 int uri_worker_map_add(jk_uri_worker_map_t *uw_map,
583 const char *puri, const char *worker,
584 unsigned int source_type, jk_logger_t *l)
586 uri_worker_record_t *uwr = NULL;
589 unsigned int match_type = 0;
595 * This way you can disable already mounted
598 match_type = MATCH_TYPE_DISABLED;
602 match_type |= MATCH_TYPE_NO_MATCH;
606 if (uri_worker_map_realloc(uw_map) == JK_FALSE) {
610 if (source_type == SOURCE_TYPE_URIMAP)
611 p = &IND_NEXT(uw_map->p_dyn);
615 uwr = (uri_worker_record_t *)jk_pool_alloc(p, sizeof(uri_worker_record_t));
617 jk_log(l, JK_LOG_ERROR,
618 "can't alloc map entry");
623 uri = jk_pool_strdup(p, puri);
624 if (!uri || !worker) {
625 jk_log(l, JK_LOG_ERROR,
626 "can't alloc uri/worker strings");
634 #ifdef _MT_CODE_PTHREAD
638 w = jk_pool_strdup(p, worker);
639 uwr->extensions.reply_timeout = -1;
640 uwr->extensions.active = NULL;
641 uwr->extensions.disabled = NULL;
642 uwr->extensions.stopped = NULL;
643 uwr->extensions.activation_size = 0;
644 uwr->extensions.activation = NULL;
645 uwr->extensions.fail_on_status_size = 0;
646 uwr->extensions.fail_on_status = NULL;
647 uwr->extensions.fail_on_status_str = NULL;
648 uwr->extensions.use_server_error_pages = 0;
650 #ifdef _MT_CODE_PTHREAD
651 param = strtok_r(w, ";", &lasts);
653 param = strtok(w, ";");
656 #ifdef _MT_CODE_PTHREAD
657 for (param = strtok_r(NULL, ";", &lasts); param; param = strtok_r(NULL, ";", &lasts)) {
659 for (param = strtok(NULL, ";"); param; param = strtok(NULL, ";")) {
661 if (!strncmp(param, JK_UWMAP_EXTENSION_REPLY_TIMEOUT, strlen(JK_UWMAP_EXTENSION_REPLY_TIMEOUT))) {
662 uwr->extensions.reply_timeout = atoi(param + strlen(JK_UWMAP_EXTENSION_REPLY_TIMEOUT));
664 else if (!strncmp(param, JK_UWMAP_EXTENSION_USE_SRV_ERRORS, strlen(JK_UWMAP_EXTENSION_USE_SRV_ERRORS))) {
665 uwr->extensions.use_server_error_pages = atoi(param + strlen(JK_UWMAP_EXTENSION_USE_SRV_ERRORS));
667 else if (!strncmp(param, JK_UWMAP_EXTENSION_ACTIVE, strlen(JK_UWMAP_EXTENSION_ACTIVE))) {
668 if (uwr->extensions.active)
669 jk_log(l, JK_LOG_WARNING,
670 "extension '%s' in uri worker map only allowed once",
671 JK_UWMAP_EXTENSION_ACTIVE);
673 uwr->extensions.active = param + strlen(JK_UWMAP_EXTENSION_ACTIVE);
675 else if (!strncmp(param, JK_UWMAP_EXTENSION_DISABLED, strlen(JK_UWMAP_EXTENSION_DISABLED))) {
676 if (uwr->extensions.disabled)
677 jk_log(l, JK_LOG_WARNING,
678 "extension '%s' in uri worker map only allowed once",
679 JK_UWMAP_EXTENSION_DISABLED);
681 uwr->extensions.disabled = param + strlen(JK_UWMAP_EXTENSION_DISABLED);
683 else if (!strncmp(param, JK_UWMAP_EXTENSION_STOPPED, strlen(JK_UWMAP_EXTENSION_STOPPED))) {
684 if (uwr->extensions.stopped)
685 jk_log(l, JK_LOG_WARNING,
686 "extension '%s' in uri worker map only allowed once",
687 JK_UWMAP_EXTENSION_STOPPED);
689 uwr->extensions.stopped = param + strlen(JK_UWMAP_EXTENSION_STOPPED);
691 else if (!strncmp(param, JK_UWMAP_EXTENSION_FAIL_ON_STATUS, strlen(JK_UWMAP_EXTENSION_FAIL_ON_STATUS))) {
692 if (uwr->extensions.fail_on_status_str)
693 jk_log(l, JK_LOG_WARNING,
694 "extension '%s' in uri worker map only allowed once",
695 JK_UWMAP_EXTENSION_FAIL_ON_STATUS);
697 uwr->extensions.fail_on_status_str = param + strlen(JK_UWMAP_EXTENSION_FAIL_ON_STATUS);
700 jk_log(l, JK_LOG_WARNING,
701 "unknown extension '%s' in uri worker map",
707 uwr->source_type = source_type;
708 uwr->worker_name = w;
711 uwr->context_len = strlen(uwr->context);
712 if (strchr(uri, '*') ||
715 * /context/ * /user/ *
718 match_type |= MATCH_TYPE_WILDCHAR_PATH;
719 if (JK_IS_DEBUG_LEVEL(l))
720 jk_log(l, JK_LOG_DEBUG,
721 "wildchar rule '%s=%s' source '%s' was added",
722 uwr->context, uwr->worker_name, uri_worker_map_get_source(uwr, l));
726 /* Something like: JkMount /login/j_security_check ajp13 */
727 match_type |= MATCH_TYPE_EXACT;
728 if (JK_IS_DEBUG_LEVEL(l))
729 jk_log(l, JK_LOG_DEBUG,
730 "exact rule '%s=%s' source '%s' was added",
731 uwr->context, uwr->worker_name, uri_worker_map_get_source(uwr, l));
736 * JFC: please check...
737 * Not sure what to do, but I try to prevent problems.
738 * I have fixed jk_mount_context() in apaches/mod_jk.c so we should
739 * not arrive here when using Apache.
741 jk_log(l, JK_LOG_ERROR,
742 "invalid context '%s': does not begin with '/'",
747 uwr->match_type = match_type;
748 IND_NEXT(uw_map->maps)[IND_NEXT(uw_map->size)] = uwr;
749 IND_NEXT(uw_map->size)++;
750 if (match_type & MATCH_TYPE_NO_MATCH) {
751 /* If we split the mappings this one will be calculated */
752 IND_NEXT(uw_map->nosize)++;
754 worker_qsort(uw_map);
759 int uri_worker_map_open(jk_uri_worker_map_t *uw_map,
760 jk_map_t *init_data, jk_logger_t *l)
767 int sz = jk_map_size(init_data);
769 if (JK_IS_DEBUG_LEVEL(l))
770 jk_log(l, JK_LOG_DEBUG,
771 "rule map size is %d",
776 for (i = 0; i < sz; i++) {
777 const char *u = jk_map_name_at(init_data, i);
778 const char *w = jk_map_value_at(init_data, i);
779 /* Multiple mappings like :
780 * /servlets-examples|/ *
781 * will create two mappings:
784 * /servlets-examples/ *
786 if (strchr(u, '|')) {
787 char *s, *r = strdup(u);
790 /* Add first mapping */
791 if (!uri_worker_map_add(uw_map, r, w, SOURCE_TYPE_JKMOUNT, l)) {
792 jk_log(l, JK_LOG_ERROR,
793 "invalid mapping rule %s->%s", r, w);
799 /* add second mapping */
800 if (!uri_worker_map_add(uw_map, r, w, SOURCE_TYPE_JKMOUNT, l)) {
801 jk_log(l, JK_LOG_ERROR,
802 "invalid mapping rule %s->%s", r, w);
807 else if (!uri_worker_map_add(uw_map, u, w, SOURCE_TYPE_JKMOUNT, l)) {
808 jk_log(l, JK_LOG_ERROR,
809 "invalid mapping rule %s->%s",
819 if (rc == JK_FALSE) {
820 jk_log(l, JK_LOG_ERROR,
821 "there was an error, freeing buf");
822 jk_close_pool(&uw_map->p_dyn[0]);
823 jk_close_pool(&uw_map->p_dyn[1]);
824 jk_close_pool(&uw_map->p);
826 else if (JK_IS_DEBUG_LEVEL(l))
827 uri_worker_map_dump(uw_map, "after map open", l);
834 static int find_match(jk_uri_worker_map_t *uw_map,
835 const char *url, jk_logger_t *l)
841 for (i = 0; i < IND_THIS(uw_map->size); i++) {
842 uri_worker_record_t *uwr = IND_THIS(uw_map->maps)[i];
844 /* Check for match types */
845 if ((uwr->match_type & MATCH_TYPE_DISABLED) ||
846 (uwr->match_type & MATCH_TYPE_NO_MATCH))
849 if (JK_IS_DEBUG_LEVEL(l))
850 jk_log(l, JK_LOG_DEBUG, "Attempting to map context URI '%s=%s' source '%s'",
851 uwr->context, uwr->worker_name, uri_worker_map_get_source(uwr, l));
853 if (uwr->match_type & MATCH_TYPE_WILDCHAR_PATH) {
854 /* Map is already sorted by context_len */
855 if (jk_wildchar_match(url, uwr->context,
862 if (JK_IS_DEBUG_LEVEL(l))
863 jk_log(l, JK_LOG_DEBUG,
864 "Found a wildchar match '%s=%s'",
865 uwr->context, uwr->worker_name);
870 else if (JK_STRNCMP(uwr->context, url, uwr->context_len) == 0) {
871 if (strlen(url) == uwr->context_len) {
872 if (JK_IS_DEBUG_LEVEL(l))
873 jk_log(l, JK_LOG_DEBUG,
874 "Found an exact match '%s=%s'",
875 uwr->context, uwr->worker_name);
886 static int is_nomatch(jk_uri_worker_map_t *uw_map,
887 const char *uri, int match,
891 const char *worker = IND_THIS(uw_map->maps)[match]->worker_name;
895 for (i = 0; i < IND_THIS(uw_map->size); i++) {
896 uri_worker_record_t *uwr = IND_THIS(uw_map->maps)[i];
898 /* Check only nomatch mappings */
899 if (!(uwr->match_type & MATCH_TYPE_NO_MATCH) ||
900 (uwr->match_type & MATCH_TYPE_DISABLED))
902 /* Check only matching workers */
903 if (strcmp(uwr->worker_name, worker) &&
904 strcmp(uwr->worker_name, "*"))
906 if (uwr->match_type & MATCH_TYPE_WILDCHAR_PATH) {
907 /* Map is already sorted by context_len */
908 if (jk_wildchar_match(uri, uwr->context,
915 if (JK_IS_DEBUG_LEVEL(l))
916 jk_log(l, JK_LOG_DEBUG,
917 "Found a wildchar no match '%s=%s' source '%s'",
918 uwr->context, uwr->worker_name, uri_worker_map_get_source(uwr, l));
923 else if (JK_STRNCMP(uwr->context, uri, uwr->context_len) == 0) {
924 if (strlen(uri) == uwr->context_len) {
925 if (JK_IS_DEBUG_LEVEL(l))
926 jk_log(l, JK_LOG_DEBUG,
927 "Found an exact no match '%s=%s' source '%s'",
928 uwr->context, uwr->worker_name, uri_worker_map_get_source(uwr, l));
939 const char *map_uri_to_worker_ext(jk_uri_worker_map_t *uw_map,
940 const char *uri, const char *vhost,
941 rule_extension_t **extensions,
946 unsigned int vhost_len;
949 char url[JK_MAX_URI_LEN+1];
953 if (!uw_map || !uri || !extensions) {
954 JK_LOG_NULL_PARAMS(l);
962 jk_log(l, JK_LOG_WARNING,
963 "Uri %s is invalid. Uri must start with /", uri);
968 uri_worker_map_update(uw_map, 0, l);
969 if (!IND_THIS(uw_map->size)) {
970 jk_log(l, JK_LOG_INFO,
971 "No worker maps defined for %s.",
977 /* Make the copy of the provided uri and strip
978 * everything after the first ';' char.
980 reject_unsafe = uw_map->reject_unsafe;
983 * In case we got a vhost, we prepend a slash
984 * and the vhost to the url in order to enable
985 * vhost mapping rules especially for IIS.
989 /* Add leading '/' if necessary */
990 if (vhost[0] != '/') {
994 /* Size including leading slash. */
995 vhost_len = strlen(vhost);
996 if (vhost_len + off >= JK_MAX_URI_LEN) {
998 jk_log(l, JK_LOG_WARNING,
999 "Host prefix %s for URI %s is invalid and will be ignored."
1000 " It must be smaller than %d chars",
1001 vhost, JK_MAX_URI_LEN - off);
1004 strncpy(&url[off], vhost, vhost_len + 1);
1008 for (i = 0; i < strlen(uri); i++) {
1009 if (i == JK_MAX_URI_LEN) {
1010 jk_log(l, JK_LOG_WARNING,
1011 "URI %s is invalid. URI must be smaller than %d chars",
1012 uri, JK_MAX_URI_LEN);
1019 url[i + vhost_len] = uri[i];
1020 if (reject_unsafe && (uri[i] == '%' || uri[i] == '\\')) {
1021 jk_log(l, JK_LOG_INFO, "Potentially unsafe request url '%s' rejected", uri);
1027 url[i + vhost_len] = '\0';
1029 if (JK_IS_DEBUG_LEVEL(l)) {
1030 char *url_rewrite = strstr(uri, JK_PATH_SESSION_IDENTIFIER);
1032 jk_log(l, JK_LOG_DEBUG, "Found session identifier '%s' in url '%s'",
1035 if (JK_IS_DEBUG_LEVEL(l))
1036 jk_log(l, JK_LOG_DEBUG, "Attempting to map URI '%s' from %d maps",
1037 url, IND_THIS(uw_map->size));
1038 rv = find_match(uw_map, url, l);
1039 /* If this doesn't find a match, try without the vhost. */
1040 if (rv < 0 && vhost_len) {
1041 rv = find_match(uw_map, &url[vhost_len], l);
1044 /* In case we found a match, check for the unmounts. */
1045 if (rv >= 0 && IND_THIS(uw_map->nosize)) {
1046 /* Again first including vhost. */
1047 int rc = is_nomatch(uw_map, url, rv, l);
1048 /* If no unmount was find, try without vhost. */
1049 if (!rc && vhost_len)
1050 rc = is_nomatch(uw_map, &url[vhost_len], rv, l);
1052 if (JK_IS_DEBUG_LEVEL(l)) {
1053 jk_log(l, JK_LOG_DEBUG,
1054 "Denying match for worker %s by nomatch rule",
1055 IND_THIS(uw_map->maps)[rv]->worker_name);
1062 *extensions = &(IND_THIS(uw_map->maps)[rv]->extensions);
1066 return IND_THIS(uw_map->maps)[rv]->worker_name;
1072 rule_extension_t *get_uri_to_worker_ext(jk_uri_worker_map_t *uw_map,
1076 return &(IND_THIS(uw_map->maps)[index]->extensions);
1083 const char *map_uri_to_worker(jk_uri_worker_map_t *uw_map,
1084 const char *uri, const char *vhost,
1087 rule_extension_t *ext;
1088 return map_uri_to_worker_ext(uw_map, uri, vhost, &ext, NULL, l);
1091 int uri_worker_map_load(jk_uri_worker_map_t *uw_map,
1098 if (jk_map_read_properties(map, NULL, uw_map->fname, &uw_map->modified,
1099 JK_MAP_HANDLE_NORMAL, l)) {
1101 if (JK_IS_DEBUG_LEVEL(l))
1102 jk_log(l, JK_LOG_DEBUG,
1103 "Loading urimaps from %s with reload check interval %d seconds",
1104 uw_map->fname, uw_map->reload);
1105 uri_worker_map_clear(uw_map, l);
1106 for (i = 0; i < jk_map_size(map); i++) {
1107 const char *u = jk_map_name_at(map, i);
1108 const char *w = jk_map_value_at(map, i);
1109 /* Multiple mappings like :
1110 * /servlets-examples|/ *
1111 * will create two mappings:
1112 * /servlets-examples
1114 * /servlets-examples/ *
1116 if (strchr(u, '|')) {
1117 char *s, *r = strdup(u);
1120 /* Add first mapping */
1121 if (!uri_worker_map_add(uw_map, r, w, SOURCE_TYPE_URIMAP, l)) {
1122 jk_log(l, JK_LOG_ERROR,
1123 "invalid mapping rule %s->%s", r, w);
1128 /* add second mapping */
1129 if (!uri_worker_map_add(uw_map, r, w, SOURCE_TYPE_URIMAP, l)) {
1130 jk_log(l, JK_LOG_ERROR,
1131 "invalid mapping rule %s->%s", r, w);
1135 else if (!uri_worker_map_add(uw_map, u, w, SOURCE_TYPE_URIMAP, l)) {
1136 jk_log(l, JK_LOG_ERROR,
1137 "invalid mapping rule %s->%s",
1141 uw_map->checked = time(NULL);
1142 if (JK_IS_DEBUG_LEVEL(l))
1143 uri_worker_map_dump(uw_map, "after file load", l);
1150 int uri_worker_map_update(jk_uri_worker_map_t *uw_map,
1151 int force, jk_logger_t *l)
1154 time_t now = time(NULL);
1156 if (force || (uw_map->reload > 0 && difftime(now, uw_map->checked) >
1158 struct stat statbuf;
1159 uw_map->checked = now;
1160 if ((rc = jk_stat(uw_map->fname, &statbuf)) == -1) {
1161 jk_log(l, JK_LOG_ERROR,
1162 "Unable to stat the %s (errno=%d)",
1163 uw_map->fname, errno);
1166 if (statbuf.st_mtime == uw_map->modified) {
1167 if (JK_IS_DEBUG_LEVEL(l))
1168 jk_log(l, JK_LOG_DEBUG,
1169 "File %s is not modified",
1173 JK_ENTER_CS(&(uw_map->cs), rc);
1174 /* Check if some other thread updated status */
1175 if (statbuf.st_mtime == uw_map->modified) {
1176 JK_LEAVE_CS(&(uw_map->cs), rc);
1177 if (JK_IS_DEBUG_LEVEL(l))
1178 jk_log(l, JK_LOG_DEBUG,
1179 "File %s is not modified",
1183 rc = uri_worker_map_load(uw_map, l);
1184 uri_worker_map_ext(uw_map, l);
1185 uri_worker_map_switch(uw_map, l);
1186 JK_LEAVE_CS(&(uw_map->cs), rc);
1187 jk_log(l, JK_LOG_INFO,
1188 "Reloaded urimaps from %s", uw_map->fname);