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: Apache 2 plugin for Tomcat *
20 * Author: Gal Shachor <shachor@il.ibm.com> *
21 * Henri Gomez <hgomez@apache.org> *
22 * Version: $Revision: 1126561 $ *
23 ***************************************************************************/
26 * mod_jk: keeps all servlet related ramblings together.
29 #include "ap_config.h"
32 #include "apr_file_info.h"
33 #include "apr_file_io.h"
35 #include "http_config.h"
36 #include "http_request.h"
37 #include "http_core.h"
38 #include "http_protocol.h"
39 #include "http_main.h"
41 #include "util_script.h"
44 #if defined(AS400) && !defined(AS400_UTF8)
45 #include "ap_charset.h"
46 #include "util_charset.h" /* ap_hdrs_from_ascii */
49 /* deprecated with apr 0.9.3 */
51 #include "apr_version.h"
52 #if (APR_MAJOR_VERSION == 0) && \
53 (APR_MINOR_VERSION <= 9) && \
54 (APR_PATCH_VERSION < 3)
55 #define apr_filepath_name_get apr_filename_of_pathname
58 #include "apr_strings.h"
60 /* Yes; sorta sucks - with luck we will clean this up before httpd-2.2
61 * ships, leaving AP_NEED_SET_MUTEX_PERMS def'd as 1 or 0 on all platforms.
63 #ifdef AP_NEED_SET_MUTEX_PERMS
64 # define JK_NEED_SET_MUTEX_PERMS AP_NEED_SET_MUTEX_PERMS
66 /* A special case for httpd-2.0 */
67 # if !defined(OS2) && !defined(WIN32) && !defined(BEOS) && !defined(NETWARE) && !defined(AS400)
68 # define JK_NEED_SET_MUTEX_PERMS 1
70 # define JK_NEED_SET_MUTEX_PERMS 0
74 #if JK_NEED_SET_MUTEX_PERMS
75 #include "unixd.h" /* for unixd_set_global_mutex_perms */
81 #define __sys_types_h__
82 #define __sys_socket_h__
84 #define __netinet_in_h__
85 #define __arpa_inet_h__
86 #define __sys_timeval_h__
89 #include "jk_global.h"
91 #include "jk_logger.h"
94 #include "jk_service.h"
95 #include "jk_uri_worker_map.h"
97 #include "jk_worker.h"
101 #define JK_LOG_DEF_FILE ("logs/mod_jk.log")
102 #define JK_SHM_DEF_FILE ("logs/jk-runtime-status")
103 #define JK_ENV_REMOTE_ADDR ("JK_REMOTE_ADDR")
104 #define JK_ENV_REMOTE_PORT ("JK_REMOTE_PORT")
105 #define JK_ENV_REMOTE_HOST ("JK_REMOTE_HOST")
106 #define JK_ENV_REMOTE_USER ("JK_REMOTE_USER")
107 #define JK_ENV_AUTH_TYPE ("JK_AUTH_TYPE")
108 #define JK_ENV_LOCAL_NAME ("JK_LOCAL_NAME")
109 #define JK_ENV_LOCAL_PORT ("JK_LOCAL_PORT")
110 #define JK_ENV_HTTPS ("HTTPS")
111 #define JK_ENV_CERTS ("SSL_CLIENT_CERT")
112 #define JK_ENV_CIPHER ("SSL_CIPHER")
113 #define JK_ENV_SESSION ("SSL_SESSION_ID")
114 #define JK_ENV_KEY_SIZE ("SSL_CIPHER_USEKEYSIZE")
115 #define JK_ENV_CERTCHAIN_PREFIX ("SSL_CLIENT_CERT_CHAIN_")
116 #define JK_ENV_REPLY_TIMEOUT ("JK_REPLY_TIMEOUT")
117 #define JK_ENV_WORKER_NAME ("JK_WORKER_NAME")
118 #define JK_NOTE_WORKER_NAME ("JK_WORKER_NAME")
119 #define JK_NOTE_WORKER_TYPE ("JK_WORKER_TYPE")
120 #define JK_NOTE_REQUEST_DURATION ("JK_REQUEST_DURATION")
121 #define JK_NOTE_WORKER_ROUTE ("JK_WORKER_ROUTE")
122 #define JK_HANDLER ("jakarta-servlet")
123 #define JK_MAGIC_TYPE ("application/x-jakarta-servlet")
124 #define NULL_FOR_EMPTY(x) ((x && !strlen(x)) ? NULL : x)
125 #define STRNULL_FOR_NULL(x) ((x) ? (x) : "(null)")
126 #define JK_LOG_LOCK_KEY ("jk_log_lock_key")
127 #define JKLOG_MARK __FILE__,__LINE__
130 * If you are not using SSL, comment out the following line. It will make
133 * Personally, I (DM), think this may be a lie.
137 /* Needed for Apache 2.3/2.4 per-module log config */
138 #ifdef APLOG_USE_MODULE
139 APLOG_USE_MODULE(jk);
142 /* module MODULE_VAR_EXPORT jk_module; */
143 AP_MODULE_DECLARE_DATA module jk_module;
146 * Environment variable forward object
156 * Configuration object for the mod_jk module.
173 int mount_file_reload;
174 jk_map_t *uri_to_context;
178 jk_uri_worker_map_t *uw_map;
183 * Automatic context path apache alias
191 char *stamp_format_string;
193 apr_array_header_t *format;
196 * Setting target worker via environment
198 char *worker_indicator;
201 * Configurable environment variables to overwrite
202 * request information using meta data send by a
203 * proxy in front of us.
205 char *remote_addr_indicator;
206 char *remote_port_indicator;
207 char *remote_host_indicator;
208 char *remote_user_indicator;
209 char *auth_type_indicator;
210 char *local_name_indicator;
211 char *local_port_indicator;
217 char *https_indicator;
218 char *certs_indicator;
219 char *cipher_indicator;
220 char *session_indicator; /* Servlet API 2.3 requirement */
221 char *key_size_indicator; /* Servlet API 2.3 requirement */
222 char *certchain_prefix; /* Client certificate chain prefix */
231 char *strip_session_name;
233 * Environment variables support
236 apr_table_t *envvars;
237 apr_table_t *envvars_def;
238 apr_array_header_t *envvar_items;
243 struct apache_private_data
247 int read_body_started;
250 typedef struct apache_private_data apache_private_data_t;
252 static server_rec *main_server = NULL;
253 static jk_logger_t *main_log = NULL;
254 static apr_hash_t *jk_log_fps = NULL;
255 static jk_worker_env_t worker_env;
256 static apr_global_mutex_t *jk_log_lock = NULL;
257 static char *jk_shm_file = NULL;
258 static size_t jk_shm_size = 0;
259 static int jk_shm_size_set = 0;
260 static volatile int jk_watchdog_interval = 0;
261 static volatile int jk_watchdog_running = 0;
266 static jk_map_t *jk_worker_properties = NULL;
267 static char *jk_worker_file = NULL;
268 static int jk_mount_copy_all = JK_FALSE;
270 static int JK_METHOD ws_start_response(jk_ws_service_t *s,
273 const char *const *header_names,
274 const char *const *header_values,
275 unsigned num_of_headers);
277 static int JK_METHOD ws_read(jk_ws_service_t *s,
278 void *b, unsigned len, unsigned *actually_read);
280 static int init_jk(apr_pool_t * pconf, jk_server_conf_t * conf,
283 static int JK_METHOD ws_write(jk_ws_service_t *s, const void *b, unsigned l);
285 static void JK_METHOD ws_add_log_items(jk_ws_service_t *s,
286 const char *const *log_names,
287 const char *const *log_values,
288 unsigned num_of_log_items);
290 static void * JK_METHOD ws_next_vhost(void *d);
292 static void JK_METHOD ws_vhost_to_text(void *d, char *buf, size_t len);
294 static jk_uri_worker_map_t * JK_METHOD ws_vhost_to_uw_map(void *d);
296 /* ========================================================================= */
297 /* JK Service step callbacks */
298 /* ========================================================================= */
300 static int JK_METHOD ws_start_response(jk_ws_service_t *s,
303 const char *const *header_names,
304 const char *const *header_values,
305 unsigned num_of_headers)
308 apache_private_data_t *p = s->ws_private;
309 request_rec *r = p->r;
311 /* If we use proxy error pages, still pass
312 * through context headers needed for special status codes.
314 if (s->extension.use_server_error_pages &&
315 status >= s->extension.use_server_error_pages) {
316 if (status == HTTP_UNAUTHORIZED) {
317 int found = JK_FALSE;
318 for (h = 0; h < num_of_headers; h++) {
319 if (!strcasecmp(header_names[h], "WWW-Authenticate")) {
320 char *tmp = apr_pstrdup(r->pool, header_values[h]);
321 apr_table_set(r->err_headers_out,
322 "WWW-Authenticate", tmp);
326 if (found == JK_FALSE) {
327 jk_server_conf_t *xconf = (jk_server_conf_t *)
328 ap_get_module_config(r->server->module_config,
330 jk_log(xconf->log, JK_LOG_INFO,
331 "origin server sent 401 without"
332 " WWW-Authenticate header");
338 /* If there is no reason given (or an empty one),
339 * we'll try to guess a good one.
341 if (!reason || *reason == '\0') {
342 /* We ask Apache httpd about a good reason phrase. */
343 reason = ap_get_status_line(status);
344 /* Unfortunately it returns with a 500 reason phrase,
345 * whenever it does not know about the given status code,
346 * e.g. in the case of custom status codes.
348 if (status != 500 && !strncmp(reason, "500 ", 4)) {
349 reason = "Unknown Reason";
351 /* Apache httpd returns a full status line,
352 * but we only want a reason phrase, so skip
353 * the prepended status code.
359 r->status_line = apr_psprintf(r->pool, "%d %s", status, reason);
361 for (h = 0; h < num_of_headers; h++) {
362 if (!strcasecmp(header_names[h], "Content-type")) {
363 char *tmp = apr_pstrdup(r->pool, header_values[h]);
364 ap_content_type_tolower(tmp);
365 /* It should be done like this in Apache 2.0 */
366 /* This way, Apache 2.0 will be able to set the output filter */
367 /* and it make jk useable with deflate using */
368 /* AddOutputFilterByType DEFLATE text/html */
369 ap_set_content_type(r, tmp);
371 else if (!strcasecmp(header_names[h], "Location")) {
372 #if defined(AS400) && !defined(AS400_UTF8)
373 /* Fix escapes in Location Header URL */
374 ap_fixup_escapes((char *)header_values[h],
375 strlen(header_values[h]), ap_hdrs_from_ascii);
377 apr_table_set(r->headers_out, header_names[h], header_values[h]);
379 else if (!strcasecmp(header_names[h], "Content-Length")) {
380 apr_table_set(r->headers_out, header_names[h], header_values[h]);
382 else if (!strcasecmp(header_names[h], "Transfer-Encoding")) {
383 apr_table_set(r->headers_out, header_names[h], header_values[h]);
385 else if (!strcasecmp(header_names[h], "Last-Modified")) {
387 * If the script gave us a Last-Modified header, we can't just
388 * pass it on blindly because of restrictions on future values.
390 ap_update_mtime(r, apr_date_parse_http(header_values[h]));
391 ap_set_last_modified(r);
394 apr_table_add(r->headers_out, header_names[h], header_values[h]);
398 /* this NOP function was removed in apache 2.0 alpha14 */
399 /* ap_send_http_header(r); */
400 s->response_started = JK_TRUE;
406 * Read a chunk of the request body into a buffer. Attempt to read len
407 * bytes into the buffer. Write the number of bytes actually read into
410 * Think of this function as a method of the apache1.3-specific subclass of
411 * the jk_ws_service class. Think of the *s param as a "this" or "self"
414 static int JK_METHOD ws_read(jk_ws_service_t *s,
415 void *b, unsigned len, unsigned *actually_read)
417 if (s && s->ws_private && b && actually_read) {
418 apache_private_data_t *p = s->ws_private;
419 if (!p->read_body_started) {
420 if (ap_should_client_block(p->r)) {
421 p->read_body_started = JK_TRUE;
425 if (p->read_body_started) {
426 #if defined(AS400) && !defined(AS400_UTF8)
428 if (rv = ap_change_request_body_xlate(p->r, 65535, 65535)) { /* turn off request body translation */
429 ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_CRIT, 0, NULL,
430 "mod_jk: Error on ap_change_request_body_xlate, rc=%d",
438 if ((rv = ap_get_client_block(p->r, b, len)) < 0) {
442 *actually_read = (unsigned)rv;
450 static void JK_METHOD ws_flush(jk_ws_service_t *s)
452 #if ! (defined(AS400) && !defined(AS400_UTF8))
453 if (s && s->ws_private) {
454 apache_private_data_t *p = s->ws_private;
460 static void JK_METHOD ws_done(jk_ws_service_t *s)
462 #if ! (defined(AS400) && !defined(AS400_UTF8))
463 if (s && s->ws_private) {
464 apache_private_data_t *p = s->ws_private;
465 ap_finalize_request_protocol(p->r);
471 * Write a chunk of response data back to the browser. If the headers
472 * haven't yet been sent over, send over default header values (Status =
475 * Write len bytes from buffer b.
477 * Think of this function as a method of the apache1.3-specific subclass of
478 * the jk_ws_service class. Think of the *s param as a "this" or "self"
481 /* Works with 4096, fails with 8192 */
483 #define CHUNK_SIZE 4096
486 static int JK_METHOD ws_write(jk_ws_service_t *s, const void *b, unsigned int l)
488 #if defined(AS400) && !defined(AS400_UTF8)
492 if (s && s->ws_private && b) {
493 apache_private_data_t *p = s->ws_private;
496 /* BUFF *bf = p->r->connection->client; */
499 const char *bb = (const char *)b;
501 if (!s->response_started) {
503 jk_log(main_log, JK_LOG_INFO,
504 "Write without start, starting with defaults");
505 if (!s->start_response(s, 200, NULL, NULL, NULL, 0)) {
509 if (p->r->header_only) {
510 #if ! (defined(AS400) && !defined(AS400_UTF8))
515 #if defined(AS400) && !defined(AS400_UTF8)
516 /* turn off response body translation */
517 rc = ap_change_response_body_xlate(p->r, 65535, 65535);
519 ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_CRIT, 0, NULL,
520 "mod_jk: Error on ap_change_response_body_xlate, rc=%d",
526 while (ll > 0 && !p->r->connection->aborted) {
528 /* Apache 2 output filter does not write
529 * directly to the wire.
531 int toSend = (ll > CHUNK_SIZE) ? CHUNK_SIZE : ll;
532 r = ap_rwrite(bb, toSend, p->r);
534 r = ap_rwrite(bb, ll, p->r);
536 if (JK_IS_DEBUG_LEVEL(main_log))
537 jk_log(main_log, JK_LOG_DEBUG,
538 "written %d out of %d", r, ll);
545 if (ll && p->r->connection->aborted) {
546 /* Fail if there is something left to send and
547 * the connection was aborted by the client
558 static void JK_METHOD ws_add_log_items(jk_ws_service_t *s,
559 const char *const *log_names,
560 const char *const *log_values,
561 unsigned num_of_log_items)
564 apache_private_data_t *p = s->ws_private;
565 request_rec *r = p->r;
567 for (h = 0; h < num_of_log_items; h++) {
568 if (log_names[h] && log_values[h]) {
569 apr_table_setn(r->notes, log_names[h], log_values[h]);
574 static void * JK_METHOD ws_next_vhost(void *d)
576 server_rec *s = (server_rec *)d;
582 static void JK_METHOD ws_vhost_to_text(void *d, char *buf, size_t len)
584 server_rec *s = (server_rec *)d;
587 if (s->server_hostname)
588 used += strlen(s->server_hostname);
589 if (!s->is_virtual) {
591 used += strlen(":XXXXX");
594 used += strlen(" [");
595 if (s->addrs->virthost)
596 used += strlen(s->addrs->virthost);
597 if (s->addrs->host_port)
598 used += strlen(":XXXXX");
602 if (len < used && len > strlen("XXX")) {
609 if (s->server_hostname) {
610 strcpy(buf + used, s->server_hostname);
611 used += strlen(s->server_hostname);
613 if (!s->is_virtual) {
615 sprintf(buf + used, ":%hu", s->port);
620 strcpy(buf + used, " [");
621 used += strlen(" [");
622 if (s->addrs->virthost) {
623 strcpy(buf + used, s->addrs->virthost);
624 used += strlen(s->addrs->virthost);
626 if (s->addrs->host_port) {
627 sprintf(buf + used, ":%hu", s->addrs->host_port);
630 strcpy(buf + used, "]");
635 static jk_uri_worker_map_t * JK_METHOD ws_vhost_to_uw_map(void *d)
637 server_rec *s = (server_rec *)d;
638 jk_server_conf_t *conf = NULL;
641 conf = (jk_server_conf_t *) ap_get_module_config(s->module_config,
646 /* ========================================================================= */
647 /* Utility functions */
648 /* ========================================================================= */
650 /* ========================================================================= */
651 /* Log something to Jk log file then exit */
652 static void jk_error_exit(const char *file,
655 const server_rec * s,
656 apr_pool_t * p, const char *fmt, ...)
663 res = apr_pvsprintf(s->process->pool, fmt, ap);
665 /* Replace all format characters in the resulting message */
666 /* because we feed the message to ap_log_error(). */
675 #if (MODULE_MAGIC_NUMBER_MAJOR >= 20100606)
676 ap_log_error(file, line, APLOG_MODULE_INDEX, level, 0, s, res);
678 ap_log_error(file, line, level, 0, s, res);
681 #if (MODULE_MAGIC_NUMBER_MAJOR >= 20100606)
682 ap_log_error(file, line, APLOG_MODULE_INDEX, level, 0, NULL, res);
684 ap_log_error(file, line, level, 0, NULL, res);
692 static jk_uint64_t get_content_length(request_rec * r)
694 if (r->clength > 0) {
695 return (jk_uint64_t)r->clength;
697 else if (r->main == NULL || r->main == r) {
698 char *lenp = (char *)apr_table_get(r->headers_in, "Content-Length");
702 if (sscanf(lenp, "%" JK_UINT64_T_FMT, &rc) > 0 && rc > 0) {
711 /* Retrieve string value from env var, use default if env var does not exist. */
712 static const char *get_env_string(request_rec *r, const char *def,
713 char *env, int null_for_empty)
715 char *value = (char *)apr_table_get(r->subprocess_env, env);
717 return null_for_empty ? NULL_FOR_EMPTY(value) : value;
718 return null_for_empty ? NULL_FOR_EMPTY(def) : def;
721 /* Retrieve integer value from env var, use default if env var does not exist. */
722 static int get_env_int(request_rec *r, int def, char *env)
724 char *value = (char *)apr_table_get(r->subprocess_env, env);
730 static int init_ws_service(apache_private_data_t * private_data,
731 jk_ws_service_t *s, jk_server_conf_t * conf)
734 request_rec *r = private_data->r;
735 char *ssl_temp = NULL;
736 const char *reply_timeout = NULL;
739 /* Copy in function pointers (which are really methods) */
740 s->start_response = ws_start_response;
745 s->add_log_items = ws_add_log_items;
746 s->next_vhost = ws_next_vhost;
747 s->vhost_to_text = ws_vhost_to_text;
748 s->vhost_to_uw_map = ws_vhost_to_uw_map;
750 s->auth_type = get_env_string(r, r->ap_auth_type,
751 conf->auth_type_indicator, 1);
752 s->remote_user = get_env_string(r, r->user,
753 conf->remote_user_indicator, 1);
755 s->protocol = r->protocol;
756 s->remote_host = (char *)ap_get_remote_host(r->connection,
759 s->remote_host = get_env_string(r, s->remote_host,
760 conf->remote_host_indicator, 1);
761 if (conf->options & JK_OPT_FWDLOCAL) {
762 s->remote_addr = r->connection->local_ip;
763 /* We don't know the client port of the backend connection. */
764 s->remote_port = "0";
767 s->remote_addr = r->connection->remote_ip;
768 s->remote_port = apr_itoa(r->pool, r->connection->remote_addr->port);
770 s->remote_addr = get_env_string(r, s->remote_addr,
771 conf->remote_addr_indicator, 1);
772 s->remote_port = get_env_string(r, s->remote_port,
773 conf->remote_port_indicator, 1);
775 if (conf->options & JK_OPT_FLUSHPACKETS)
776 s->flush_packets = 1;
777 if (conf->options & JK_OPT_FLUSHEADER)
780 e = (rule_extension_t *)ap_get_module_config(r->request_config, &jk_module);
782 s->extension.reply_timeout = e->reply_timeout;
783 s->extension.use_server_error_pages = e->use_server_error_pages;
785 s->extension.activation = apr_palloc(r->pool, e->activation_size * sizeof(int));
786 memcpy(s->extension.activation, e->activation, e->activation_size * sizeof(int));
788 if (e->fail_on_status_size > 0) {
789 s->extension.fail_on_status_size = e->fail_on_status_size;
790 s->extension.fail_on_status = apr_palloc(r->pool, e->fail_on_status_size * sizeof(int));
791 memcpy(s->extension.fail_on_status, e->fail_on_status, e->fail_on_status_size * sizeof(int));
794 reply_timeout = apr_table_get(r->subprocess_env, "JK_REPLY_TIMEOUT");
796 int r = atoi(reply_timeout);
798 s->extension.reply_timeout = r;
801 if (conf->options & JK_OPT_DISABLEREUSE)
802 s->disable_reuse = 1;
804 /* get server name */
805 s->server_name = get_env_string(r, (char *)ap_get_server_name(r),
806 conf->local_name_indicator, 0);
808 /* get the real port (otherwise redirect failed) */
809 /* XXX: use apache API for getting server port
811 * Pre 1.2.7 versions used:
812 * s->server_port = r->connection->local_addr->port;
814 s->server_port = get_env_int(r, ap_get_server_port(r),
815 conf->local_port_indicator);
817 #if ((AP_MODULE_MAGIC_AT_LEAST(20051115,4)) && !defined(API_COMPATIBILITY)) || (MODULE_MAGIC_NUMBER_MAJOR >= 20060905)
818 s->server_software = (char *)ap_get_server_description();
820 s->server_software = (char *)ap_get_server_version();
822 s->method = (char *)r->method;
823 s->content_length = get_content_length(r);
824 s->is_chunked = r->read_chunked;
825 s->no_more_chunks = 0;
826 #if defined(AS400) && !defined(AS400_UTF8)
827 /* Get the query string that is not translated to EBCDIC */
828 s->query_string = ap_get_original_query_string(r);
830 s->query_string = r->args;
834 * The 2.2 servlet spec errata says the uri from
835 * HttpServletRequest.getRequestURI() should remain encoded.
836 * [http://java.sun.com/products/servlet/errata_042700.html]
838 * We use JkOptions to determine which method to be used
840 * ap_escape_uri is the latest recommanded but require
841 * some java decoding (in TC 3.3 rc2)
843 * unparsed_uri is used for strict compliance with spec and
844 * old Tomcat (3.2.3 for example)
846 * uri is use for compatibilty with mod_rewrite with old Tomcats
849 switch (conf->options & JK_OPT_FWDURIMASK) {
851 case JK_OPT_FWDURICOMPATUNPARSED:
852 s->req_uri = r->unparsed_uri;
853 if (s->req_uri != NULL) {
854 char *query_str = strchr(s->req_uri, '?');
855 if (query_str != NULL) {
862 case JK_OPT_FWDURICOMPAT:
866 case JK_OPT_FWDURIPROXY:
867 size = 3 * strlen(r->uri) + 1;
868 s->req_uri = apr_palloc(r->pool, size);
869 jk_canonenc(r->uri, s->req_uri, size);
872 case JK_OPT_FWDURIESCAPED:
873 s->req_uri = ap_escape_uri(r->pool, r->uri);
880 if (conf->ssl_enable || conf->envvars) {
881 ap_add_common_vars(r);
883 if (conf->ssl_enable) {
885 (char *)apr_table_get(r->subprocess_env,
886 conf->https_indicator);
887 if (ssl_temp && !strcasecmp(ssl_temp, "on")) {
890 (char *)apr_table_get(r->subprocess_env,
891 conf->certs_indicator);
893 if (conf->options & JK_OPT_FWDCERTCHAIN) {
894 const apr_array_header_t *t = apr_table_elts(r->subprocess_env);
897 const apr_table_entry_t *elts = (const apr_table_entry_t *) t->elts;
898 apr_array_header_t *certs = apr_array_make(r->pool, 1, sizeof(char *));
899 *(const char **)apr_array_push(certs) = s->ssl_cert;
900 for (i = 0; i < t->nelts; i++) {
903 if (!strncasecmp(elts[i].key, conf->certchain_prefix,
904 strlen(conf->certchain_prefix)))
905 *(const char **)apr_array_push(certs) = elts[i].val;
907 s->ssl_cert = apr_array_pstrcat(r->pool, certs, '\0');
912 s->ssl_cert_len = strlen(s->ssl_cert);
913 if (JK_IS_DEBUG_LEVEL(conf->log)) {
914 jk_log(conf->log, JK_LOG_DEBUG,
915 "SSL client certificate (%d bytes): %s",
916 s->ssl_cert_len, s->ssl_cert);
919 /* Servlet 2.3 API */
921 (char *)apr_table_get(r->subprocess_env,
922 conf->cipher_indicator);
924 (char *)apr_table_get(r->subprocess_env,
925 conf->session_indicator);
927 if (conf->options & JK_OPT_FWDKEYSIZE) {
928 /* Servlet 2.3 API */
929 ssl_temp = (char *)apr_table_get(r->subprocess_env,
933 s->ssl_key_size = atoi(ssl_temp);
941 const apr_array_header_t *t = conf->envvar_items;
945 envvar_item *elts = (envvar_item *) t->elts;
946 s->attributes_names = apr_palloc(r->pool,
947 sizeof(char *) * t->nelts);
948 s->attributes_values = apr_palloc(r->pool,
949 sizeof(char *) * t->nelts);
951 for (i = 0; i < t->nelts; i++) {
952 s->attributes_names[i - j] = elts[i].name;
953 s->attributes_values[i - j] =
954 (char *)apr_table_get(r->subprocess_env, elts[i].name);
955 if (!s->attributes_values[i - j]) {
956 if (elts[i].has_default) {
957 s->attributes_values[i - j] = elts[i].value;
960 s->attributes_values[i - j] = "";
961 s->attributes_names[i - j] = "";
967 s->num_attributes = t->nelts - j;
972 if (r->headers_in && apr_table_elts(r->headers_in)) {
973 int need_content_length_header = (!s->is_chunked
974 && s->content_length ==
975 0) ? JK_TRUE : JK_FALSE;
976 const apr_array_header_t *t = apr_table_elts(r->headers_in);
979 apr_table_entry_t *elts = (apr_table_entry_t *) t->elts;
980 s->num_headers = t->nelts;
981 /* allocate an extra header slot in case we need to add a content-length header */
983 apr_palloc(r->pool, sizeof(char *) * (t->nelts + 1));
985 apr_palloc(r->pool, sizeof(char *) * (t->nelts + 1));
986 if (!s->headers_names || !s->headers_values)
988 for (i = 0; i < t->nelts; i++) {
989 char *hname = apr_pstrdup(r->pool, elts[i].key);
990 s->headers_values[i] = apr_pstrdup(r->pool, elts[i].val);
991 s->headers_names[i] = hname;
992 if (need_content_length_header &&
993 !strcasecmp(s->headers_names[i], "content-length")) {
994 need_content_length_header = JK_FALSE;
997 /* Add a content-length = 0 header if needed.
998 * Ajp13 assumes an absent content-length header means an unknown,
999 * but non-zero length body.
1001 if (need_content_length_header) {
1002 s->headers_names[s->num_headers] = "content-length";
1003 s->headers_values[s->num_headers] = "0";
1007 /* Add a content-length = 0 header if needed. */
1008 else if (need_content_length_header) {
1009 s->headers_names = apr_palloc(r->pool, sizeof(char *));
1010 s->headers_values = apr_palloc(r->pool, sizeof(char *));
1011 if (!s->headers_names || !s->headers_values)
1013 s->headers_names[0] = "content-length";
1014 s->headers_values[0] = "0";
1018 s->uw_map = conf->uw_map;
1020 /* Dump all connection param so we can trace what's going to
1023 if (JK_IS_DEBUG_LEVEL(conf->log)) {
1024 jk_log(conf->log, JK_LOG_DEBUG,
1025 "Service protocol=%s method=%s ssl=%s host=%s addr=%s name=%s port=%d auth=%s user=%s laddr=%s raddr=%s uri=%s",
1026 STRNULL_FOR_NULL(s->protocol),
1027 STRNULL_FOR_NULL(s->method),
1028 s->is_ssl ? "true" : "false",
1029 STRNULL_FOR_NULL(s->remote_host),
1030 STRNULL_FOR_NULL(s->remote_addr),
1031 STRNULL_FOR_NULL(s->server_name),
1033 STRNULL_FOR_NULL(s->auth_type),
1034 STRNULL_FOR_NULL(s->remote_user),
1035 STRNULL_FOR_NULL(r->connection->local_ip),
1036 STRNULL_FOR_NULL(r->connection->remote_ip),
1037 STRNULL_FOR_NULL(s->req_uri));
1044 * The JK module command processors
1046 * The below are all installed so that Apache calls them while it is
1047 * processing its config files. This allows configuration info to be
1048 * copied into a jk_server_conf_t object, which is then used for request
1049 * filtering/processing.
1051 * See jk_cmds definition below for explanations of these options.
1055 * JkMountCopy directive handling
1057 * JkMountCopy On/Off/All
1060 static const char *jk_set_mountcopy(cmd_parms * cmd,
1061 void *dummy, const char *mount_copy)
1063 server_rec *s = cmd->server;
1064 jk_server_conf_t *conf =
1065 (jk_server_conf_t *) ap_get_module_config(s->module_config,
1068 if (! strcasecmp(mount_copy, "all")) {
1069 const char *err_string = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1070 if (err_string != NULL) {
1073 jk_mount_copy_all = JK_TRUE;
1075 else if (strcasecmp(mount_copy, "on") && strcasecmp(mount_copy, "off")) {
1076 return "JkMountCopy must be All, On or Off";
1079 conf->mountcopy = strcasecmp(mount_copy, "off") ? JK_TRUE : JK_FALSE;
1086 * JkMount directive handling
1088 * JkMount URI(context) worker
1091 static const char *jk_mount_context(cmd_parms * cmd,
1093 const char *context,
1096 server_rec *s = cmd->server;
1097 jk_server_conf_t *conf =
1098 (jk_server_conf_t *) ap_get_module_config(s->module_config,
1102 if (worker != NULL && cmd->path == NULL ) {
1106 else if (worker == NULL && cmd->path != NULL) {
1112 return "JkMount needs a path when not defined in a location";
1114 return "JkMount can not have a path when defined in a location";
1118 return "JkMount context should start with /";
1120 if (!conf->uri_to_context) {
1121 if (!jk_map_alloc(&(conf->uri_to_context))) {
1122 return "JkMount Memory error";
1126 * Add the new worker to the alias map.
1128 jk_map_put(conf->uri_to_context, c, w, NULL);
1133 * JkUnMount directive handling
1135 * JkUnMount URI(context) worker
1138 static const char *jk_unmount_context(cmd_parms * cmd,
1140 const char *context,
1143 server_rec *s = cmd->server;
1144 jk_server_conf_t *conf =
1145 (jk_server_conf_t *) ap_get_module_config(s->module_config,
1150 if (worker != NULL && cmd->path == NULL ) {
1154 else if (worker == NULL && cmd->path != NULL) {
1160 return "JkUnMount needs a path when not defined in a location";
1162 return "JkUnMount can not have a path when defined in a location";
1166 return "JkUnMount context should start with /";
1168 uri = apr_pstrcat(cmd->temp_pool, "!", c, NULL);
1170 if (!conf->uri_to_context) {
1171 if (!jk_map_alloc(&(conf->uri_to_context))) {
1172 return "JkUnMount Memory error";
1176 * Add the new worker to the alias map.
1178 jk_map_put(conf->uri_to_context, uri, w, NULL);
1184 * JkWorkersFile Directive Handling
1186 * JkWorkersFile file
1189 static const char *jk_set_worker_file(cmd_parms * cmd,
1190 void *dummy, const char *worker_file)
1192 const char *err_string = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1193 if (err_string != NULL) {
1197 if (jk_worker_file != NULL)
1198 return "JkWorkersFile only allowed once";
1200 /* we need an absolute path (ap_server_root_relative does the ap_pstrdup) */
1201 jk_worker_file = ap_server_root_relative(cmd->pool, worker_file);
1203 if (jk_worker_file == NULL)
1204 return "JkWorkersFile file name invalid";
1206 if (jk_file_exists(jk_worker_file) != JK_TRUE)
1207 return "JkWorkersFile: Can't find the workers file specified";
1213 * JkMountFile Directive Handling
1218 static const char *jk_set_mount_file(cmd_parms * cmd,
1219 void *dummy, const char *mount_file)
1221 server_rec *s = cmd->server;
1223 jk_server_conf_t *conf =
1224 (jk_server_conf_t *) ap_get_module_config(s->module_config,
1227 /* we need an absolute path (ap_server_root_relative does the ap_pstrdup) */
1228 conf->mount_file = ap_server_root_relative(cmd->pool, mount_file);
1230 if (conf->mount_file == NULL)
1231 return "JkMountFile file name invalid";
1233 if (jk_file_exists(conf->mount_file) != JK_TRUE)
1234 return "JkMountFile: Can't find the mount file specified";
1236 if (!conf->uri_to_context) {
1237 if (!jk_map_alloc(&(conf->uri_to_context))) {
1238 return "JkMountFile Memory error";
1246 * JkMountFileReload Directive Handling
1248 * JkMountFileReload seconds
1251 static const char *jk_set_mount_file_reload(cmd_parms * cmd,
1252 void *dummy, const char *mount_file_reload)
1254 server_rec *s = cmd->server;
1257 jk_server_conf_t *conf =
1258 (jk_server_conf_t *) ap_get_module_config(s->module_config,
1261 interval = atoi(mount_file_reload);
1266 conf->mount_file_reload = interval;
1272 * JkWatchdogInterval Directive Handling
1274 * JkWatchdogInterval seconds
1277 static const char *jk_set_watchdog_interval(cmd_parms * cmd,
1278 void *dummy, const char *watchdog_interval)
1280 const char *err_string = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1281 if (err_string != NULL) {
1286 jk_watchdog_interval = atoi(watchdog_interval);
1287 if (jk_watchdog_interval < 0) {
1288 jk_watchdog_interval = 0;
1292 return "JkWatchdogInterval: APR was compiled without threading support. Cannot create watchdog thread";
1297 * JkLogFile Directive Handling
1302 static const char *jk_set_log_file(cmd_parms * cmd,
1303 void *dummy, const char *log_file)
1305 server_rec *s = cmd->server;
1306 jk_server_conf_t *conf =
1307 (jk_server_conf_t *) ap_get_module_config(s->module_config,
1310 /* we need an absolute path */
1311 if (*log_file != '|')
1312 conf->log_file = ap_server_root_relative(cmd->pool, log_file);
1314 conf->log_file = apr_pstrdup(cmd->pool, log_file);
1316 if (conf->log_file == NULL)
1317 return "JkLogFile file name invalid";
1323 * JkShmFile Directive Handling
1328 static const char *jk_set_shm_file(cmd_parms * cmd,
1329 void *dummy, const char *shm_file)
1331 const char *err_string = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1332 if (err_string != NULL) {
1336 /* we need an absolute path */
1337 jk_shm_file = ap_server_root_relative(cmd->pool, shm_file);
1338 if (jk_shm_file == NULL)
1339 return "JkShmFile file name invalid";
1345 * JkShmSize Directive Handling
1347 * JkShmSize size in kilobytes
1350 static const char *jk_set_shm_size(cmd_parms * cmd,
1351 void *dummy, const char *shm_size)
1354 const char *err_string = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1355 if (err_string != NULL) {
1359 sz = atoi(shm_size) * 1024;
1360 if (sz < JK_SHM_DEF_SIZE)
1361 sz = JK_SHM_DEF_SIZE;
1363 sz = JK_SHM_ALIGN(sz);
1364 jk_shm_size = (size_t)sz;
1366 jk_shm_size_set = 1;
1371 * JkLogLevel Directive Handling
1373 * JkLogLevel debug/info/error/emerg
1376 static const char *jk_set_log_level(cmd_parms * cmd,
1377 void *dummy, const char *log_level)
1379 server_rec *s = cmd->server;
1380 jk_server_conf_t *conf =
1381 (jk_server_conf_t *) ap_get_module_config(s->module_config,
1384 conf->log_level = jk_parse_log_level(log_level);
1390 * JkLogStampFormat Directive Handling
1392 * JkLogStampFormat "[%a %b %d %H:%M:%S %Y] "
1395 static const char *jk_set_log_fmt(cmd_parms * cmd,
1396 void *dummy, const char *log_format)
1398 server_rec *s = cmd->server;
1399 jk_server_conf_t *conf =
1400 (jk_server_conf_t *) ap_get_module_config(s->module_config,
1403 conf->stamp_format_string = apr_pstrdup(cmd->pool, log_format);
1410 * JkAutoAlias Directive Handling
1412 * JkAutoAlias application directory
1415 static const char *jk_set_auto_alias(cmd_parms * cmd,
1416 void *dummy, const char *directory)
1418 server_rec *s = cmd->server;
1419 jk_server_conf_t *conf =
1420 (jk_server_conf_t *) ap_get_module_config(s->module_config,
1423 conf->alias_dir = apr_pstrdup(cmd->pool, directory);
1425 if (conf->alias_dir == NULL)
1426 return "JkAutoAlias directory invalid";
1432 * JkStripSession directive handling
1434 * JkStripSession On/Off [session path identifier]
1437 static const char *jk_set_strip_session(cmd_parms * cmd, void *dummy,
1438 const char *flag, const char *name)
1440 server_rec *s = cmd->server;
1441 jk_server_conf_t *conf =
1442 (jk_server_conf_t *) ap_get_module_config(s->module_config,
1445 if (strcasecmp(flag, "on") && strcasecmp(flag, "off")) {
1446 return "JkStripSession must be On or Off";
1449 conf->strip_session = strcasecmp(flag, "off") ? JK_TRUE : JK_FALSE;
1452 /* Check for optional path value */
1454 conf->strip_session_name = apr_pstrdup(cmd->pool, name);
1456 conf->strip_session_name = apr_pstrdup(cmd->pool, JK_PATH_SESSION_IDENTIFIER);
1461 /*****************************************************************
1466 typedef const char *(*item_key_func) (request_rec *, char *);
1472 } request_log_format_item;
1474 static const char *process_item(request_rec * r,
1475 request_log_format_item * item)
1479 cp = (*item->func) (r, item->arg);
1480 return cp ? cp : "-";
1483 static void request_log_transaction(request_rec * r, jk_server_conf_t * conf)
1485 request_log_format_item *items;
1491 apr_array_header_t *format = conf->format;
1493 strs = apr_palloc(r->pool, sizeof(char *) * (format->nelts));
1494 strl = apr_palloc(r->pool, sizeof(int) * (format->nelts));
1495 items = (request_log_format_item *) format->elts;
1496 for (i = 0; i < format->nelts; ++i) {
1497 strs[i] = process_item(r, &items[i]);
1499 for (i = 0; i < format->nelts; ++i) {
1500 len += strl[i] = strlen(strs[i]);
1502 str = apr_palloc(r->pool, len + 1);
1503 for (i = 0, s = str; i < format->nelts; ++i) {
1504 memcpy(s, strs[i], strl[i]);
1509 jk_log(conf->log, JK_LOG_REQUEST, "%s", str);
1513 /*****************************************************************
1515 * Parsing the log format string
1518 static char *format_integer(apr_pool_t * p, int i)
1520 return apr_psprintf(p, "%d", i);
1523 static char *pfmt(apr_pool_t * p, int i)
1529 return format_integer(p, i);
1533 static const char *constant_item(request_rec * dummy, char *stuff)
1538 static const char *log_worker_name(request_rec * r, char *a)
1540 return apr_table_get(r->notes, JK_NOTE_WORKER_NAME);
1543 static const char *log_worker_route(request_rec * r, char *a)
1545 return apr_table_get(r->notes, JK_NOTE_WORKER_ROUTE);
1549 static const char *log_request_duration(request_rec * r, char *a)
1551 return apr_table_get(r->notes, JK_NOTE_REQUEST_DURATION);
1554 static const char *log_request_line(request_rec * r, char *a)
1556 /* NOTE: If the original request contained a password, we
1557 * re-write the request line here to contain XXXXXX instead:
1558 * (note the truncation before the protocol string for HTTP/0.9 requests)
1559 * (note also that r->the_request contains the unmodified request)
1561 return (r->parsed_uri.password) ? apr_pstrcat(r->pool, r->method, " ",
1562 apr_uri_unparse(r->pool,
1567 assbackwards ? NULL : " ",
1572 /* These next two routines use the canonical name:port so that log
1573 * parsers don't need to duplicate all the vhost parsing crud.
1575 static const char *log_virtual_host(request_rec * r, char *a)
1577 return r->server->server_hostname;
1580 static const char *log_server_port(request_rec * r, char *a)
1582 return apr_psprintf(r->pool, "%u",
1583 r->server->port ? r->server->
1584 port : ap_default_port(r));
1587 /* This respects the setting of UseCanonicalName so that
1588 * the dynamic mass virtual hosting trick works better.
1590 static const char *log_server_name(request_rec * r, char *a)
1592 return ap_get_server_name(r);
1595 static const char *log_request_uri(request_rec * r, char *a)
1599 static const char *log_request_method(request_rec * r, char *a)
1604 static const char *log_request_protocol(request_rec * r, char *a)
1608 static const char *log_request_query(request_rec * r, char *a)
1610 return (r->args != NULL) ? apr_pstrcat(r->pool, "?", r->args, NULL)
1613 static const char *log_status(request_rec * r, char *a)
1615 return pfmt(r->pool, r->status);
1618 static const char *clf_log_bytes_sent(request_rec * r, char *a)
1620 if (!r->sent_bodyct) {
1624 return apr_off_t_toa(r->pool, r->bytes_sent);
1628 static const char *log_bytes_sent(request_rec * r, char *a)
1630 if (!r->sent_bodyct) {
1634 return apr_psprintf(r->pool, "%" APR_OFF_T_FMT, r->bytes_sent);
1638 static struct log_item_list
1642 } log_item_keys[] = {
1645 'T', log_request_duration}, {
1646 'r', log_request_line}, {
1647 'U', log_request_uri}, {
1649 'b', clf_log_bytes_sent}, {
1650 'B', log_bytes_sent}, {
1651 'V', log_server_name}, {
1652 'v', log_virtual_host}, {
1653 'p', log_server_port}, {
1654 'H', log_request_protocol}, {
1655 'm', log_request_method}, {
1656 'q', log_request_query}, {
1657 'w', log_worker_name}, {
1658 'R', log_worker_route}, {
1662 static struct log_item_list *find_log_func(char k)
1666 for (i = 0; log_item_keys[i].ch; ++i)
1667 if (k == log_item_keys[i].ch) {
1668 return &log_item_keys[i];
1674 static char *parse_request_log_misc_string(apr_pool_t * p,
1675 request_log_format_item * it,
1681 it->func = constant_item;
1684 while (*s && *s != '%') {
1688 * This might allocate a few chars extra if there's a backslash
1689 * escape in the format string.
1691 it->arg = apr_palloc(p, s - *sa + 1);
1695 while (*s && *s != '%') {
1718 * Allow the loop to deal with this *s in the normal
1719 * fashion so that it handles end of string etc.
1732 static char *parse_request_log_item(apr_pool_t * p,
1733 request_log_format_item * it,
1736 const char *s = *sa;
1737 struct log_item_list *l;
1740 return parse_request_log_misc_string(p, it, sa);
1744 it->arg = ""; /* For safety's sake... */
1746 l = find_log_func(*s++);
1752 return apr_pstrcat(p, "Unrecognized JkRequestLogFormat directive %",
1760 static apr_array_header_t *parse_request_log_string(apr_pool_t * p,
1764 apr_array_header_t *a =
1765 apr_array_make(p, 0, sizeof(request_log_format_item));
1770 parse_request_log_item(p,
1771 (request_log_format_item *)
1772 apr_array_push(a), &s))) {
1782 * JkRequestLogFormat Directive Handling
1784 * JkRequestLogFormat format string
1786 * %b - Bytes sent, excluding HTTP headers. In CLF format
1787 * %B - Bytes sent, excluding HTTP headers.
1788 * %H - The request protocol
1789 * %m - The request method
1790 * %p - The canonical Port of the server serving the request
1791 * %q - The query string (prepended with a ? if a query string exists,
1792 * otherwise an empty string)
1793 * %r - First line of request
1794 * %s - request HTTP status code
1795 * %T - Requset duration, elapsed time to handle request in seconds '.' micro seconds
1796 * %U - The URL path requested, not including any query string.
1797 * %v - The canonical ServerName of the server serving the request.
1798 * %V - The server name according to the UseCanonicalName setting.
1799 * %w - Tomcat worker name
1802 static const char *jk_set_request_log_format(cmd_parms * cmd,
1803 void *dummy, const char *format)
1805 server_rec *s = cmd->server;
1806 jk_server_conf_t *conf =
1807 (jk_server_conf_t *) ap_get_module_config(s->module_config,
1810 conf->format_string = apr_pstrdup(cmd->pool, format);
1817 * JkWorkerIndicator Directive Handling
1819 * JkWorkerIndicator JkWorker
1822 static const char *jk_set_worker_indicator(cmd_parms * cmd,
1823 void *dummy, const char *indicator)
1825 server_rec *s = cmd->server;
1826 jk_server_conf_t *conf =
1827 (jk_server_conf_t *) ap_get_module_config(s->module_config,
1830 conf->worker_indicator = apr_pstrdup(cmd->pool, indicator);
1836 * Directives Handling for setting various environment names
1837 * used to overwrite the following request information:
1846 static const char *jk_set_remote_addr_indicator(cmd_parms * cmd,
1847 void *dummy, const char *indicator)
1849 server_rec *s = cmd->server;
1850 jk_server_conf_t *conf =
1851 (jk_server_conf_t *) ap_get_module_config(s->module_config, &jk_module);
1852 conf->remote_addr_indicator = apr_pstrdup(cmd->pool, indicator);
1856 static const char *jk_set_remote_port_indicator(cmd_parms * cmd,
1857 void *dummy, const char *indicator)
1859 server_rec *s = cmd->server;
1860 jk_server_conf_t *conf =
1861 (jk_server_conf_t *) ap_get_module_config(s->module_config, &jk_module);
1862 conf->remote_port_indicator = apr_pstrdup(cmd->pool, indicator);
1866 static const char *jk_set_remote_host_indicator(cmd_parms * cmd,
1867 void *dummy, const char *indicator)
1869 server_rec *s = cmd->server;
1870 jk_server_conf_t *conf =
1871 (jk_server_conf_t *) ap_get_module_config(s->module_config, &jk_module);
1872 conf->remote_host_indicator = apr_pstrdup(cmd->pool, indicator);
1876 static const char *jk_set_remote_user_indicator(cmd_parms * cmd,
1877 void *dummy, const char *indicator)
1879 server_rec *s = cmd->server;
1880 jk_server_conf_t *conf =
1881 (jk_server_conf_t *) ap_get_module_config(s->module_config, &jk_module);
1882 conf->remote_user_indicator = apr_pstrdup(cmd->pool, indicator);
1886 static const char *jk_set_auth_type_indicator(cmd_parms * cmd,
1887 void *dummy, const char *indicator)
1889 server_rec *s = cmd->server;
1890 jk_server_conf_t *conf =
1891 (jk_server_conf_t *) ap_get_module_config(s->module_config, &jk_module);
1892 conf->auth_type_indicator = apr_pstrdup(cmd->pool, indicator);
1896 static const char *jk_set_local_name_indicator(cmd_parms * cmd,
1897 void *dummy, const char *indicator)
1899 server_rec *s = cmd->server;
1900 jk_server_conf_t *conf =
1901 (jk_server_conf_t *) ap_get_module_config(s->module_config, &jk_module);
1902 conf->local_name_indicator = apr_pstrdup(cmd->pool, indicator);
1906 static const char *jk_set_local_port_indicator(cmd_parms * cmd,
1907 void *dummy, const char *indicator)
1909 server_rec *s = cmd->server;
1910 jk_server_conf_t *conf =
1911 (jk_server_conf_t *) ap_get_module_config(s->module_config, &jk_module);
1912 conf->local_port_indicator = apr_pstrdup(cmd->pool, indicator);
1917 * JkExtractSSL Directive Handling
1919 * JkExtractSSL On/Off
1922 static const char *jk_set_enable_ssl(cmd_parms * cmd, void *dummy, int flag)
1924 server_rec *s = cmd->server;
1925 jk_server_conf_t *conf =
1926 (jk_server_conf_t *) ap_get_module_config(s->module_config,
1929 /* Set up our value */
1930 conf->ssl_enable = flag ? JK_TRUE : JK_FALSE;
1936 * JkHTTPSIndicator Directive Handling
1938 * JkHTTPSIndicator HTTPS
1941 static const char *jk_set_https_indicator(cmd_parms * cmd,
1942 void *dummy, const char *indicator)
1944 server_rec *s = cmd->server;
1945 jk_server_conf_t *conf =
1946 (jk_server_conf_t *) ap_get_module_config(s->module_config,
1949 conf->https_indicator = apr_pstrdup(cmd->pool, indicator);
1955 * JkCERTSIndicator Directive Handling
1957 * JkCERTSIndicator SSL_CLIENT_CERT
1960 static const char *jk_set_certs_indicator(cmd_parms * cmd,
1961 void *dummy, const char *indicator)
1963 server_rec *s = cmd->server;
1964 jk_server_conf_t *conf =
1965 (jk_server_conf_t *) ap_get_module_config(s->module_config,
1968 conf->certs_indicator = apr_pstrdup(cmd->pool, indicator);
1974 * JkCIPHERIndicator Directive Handling
1976 * JkCIPHERIndicator SSL_CIPHER
1979 static const char *jk_set_cipher_indicator(cmd_parms * cmd,
1980 void *dummy, const char *indicator)
1982 server_rec *s = cmd->server;
1983 jk_server_conf_t *conf =
1984 (jk_server_conf_t *) ap_get_module_config(s->module_config,
1987 conf->cipher_indicator = apr_pstrdup(cmd->pool, indicator);
1993 * JkCERTCHAINPrefix Directive Handling
1995 * JkCERTCHAINPrefix SSL_CLIENT_CERT_CHAIN_
1998 static const char *jk_set_certchain_prefix(cmd_parms * cmd,
1999 void *dummy, const char *prefix)
2001 server_rec *s = cmd->server;
2002 jk_server_conf_t *conf =
2003 (jk_server_conf_t *) ap_get_module_config(s->module_config,
2006 conf->certchain_prefix = apr_pstrdup(cmd->pool, prefix);
2012 * JkSESSIONIndicator Directive Handling
2014 * JkSESSIONIndicator SSL_SESSION_ID
2017 static const char *jk_set_session_indicator(cmd_parms * cmd,
2019 const char *indicator)
2021 server_rec *s = cmd->server;
2022 jk_server_conf_t *conf =
2023 (jk_server_conf_t *) ap_get_module_config(s->module_config,
2026 conf->session_indicator = apr_pstrdup(cmd->pool, indicator);
2032 * JkKEYSIZEIndicator Directive Handling
2034 * JkKEYSIZEIndicator SSL_CIPHER_USEKEYSIZE
2037 static const char *jk_set_key_size_indicator(cmd_parms * cmd,
2039 const char *indicator)
2041 server_rec *s = cmd->server;
2042 jk_server_conf_t *conf =
2043 (jk_server_conf_t *) ap_get_module_config(s->module_config,
2046 conf->key_size_indicator = apr_pstrdup(cmd->pool, indicator);
2052 * JkOptions Directive Handling
2055 * +ForwardSSLKeySize => Forward SSL Key Size, to follow 2.3 specs but may broke old TC 3.2
2056 * -ForwardSSLKeySize => Don't Forward SSL Key Size, will make mod_jk works with all TC release
2057 * ForwardURICompat => Forward URI normally, less spec compliant but mod_rewrite compatible (old TC)
2058 * ForwardURICompatUnparsed => Forward URI as unparsed, spec compliant but broke mod_rewrite (old TC)
2059 * ForwardURIEscaped => Forward URI escaped and Tomcat (3.3 rc2) stuff will do the decoding part
2060 * ForwardDirectories => Forward all directory requests with no index files to Tomcat
2061 * +ForwardSSLCertChain => Forward SSL Cert Chain
2062 * -ForwardSSLCertChain => Don't Forward SSL Cert Chain (default)
2065 static const char *jk_set_options(cmd_parms * cmd, void *dummy,
2073 server_rec *s = cmd->server;
2074 jk_server_conf_t *conf =
2075 (jk_server_conf_t *) ap_get_module_config(s->module_config,
2078 while (line[0] != 0) {
2079 w = ap_getword_conf(cmd->pool, &line);
2082 if (*w == '+' || *w == '-') {
2088 if (action == '-' && !strncasecmp(w, "ForwardURI", strlen("ForwardURI")))
2089 return apr_pstrcat(cmd->pool, "JkOptions: Illegal option '-", w,
2090 "': ForwardURI* options can not be disabled", NULL);
2092 if (!strcasecmp(w, "ForwardURICompat")) {
2093 opt = JK_OPT_FWDURICOMPAT;
2094 mask = JK_OPT_FWDURIMASK;
2096 else if (!strcasecmp(w, "ForwardURICompatUnparsed")) {
2097 opt = JK_OPT_FWDURICOMPATUNPARSED;
2098 mask = JK_OPT_FWDURIMASK;
2100 else if (!strcasecmp(w, "ForwardURIEscaped")) {
2101 opt = JK_OPT_FWDURIESCAPED;
2102 mask = JK_OPT_FWDURIMASK;
2104 else if (!strcasecmp(w, "ForwardURIProxy")) {
2105 opt = JK_OPT_FWDURIPROXY;
2106 mask = JK_OPT_FWDURIMASK;
2108 else if (!strcasecmp(w, "ForwardDirectories")) {
2109 opt = JK_OPT_FWDDIRS;
2111 else if (!strcasecmp(w, "ForwardLocalAddress")) {
2112 opt = JK_OPT_FWDLOCAL;
2114 else if (!strcasecmp(w, "FlushPackets")) {
2115 opt = JK_OPT_FLUSHPACKETS;
2117 else if (!strcasecmp(w, "FlushHeader")) {
2118 opt = JK_OPT_FLUSHEADER;
2120 else if (!strcasecmp(w, "DisableReuse")) {
2121 opt = JK_OPT_DISABLEREUSE;
2123 else if (!strcasecmp(w, "ForwardSSLCertChain")) {
2124 opt = JK_OPT_FWDCERTCHAIN;
2126 else if (!strcasecmp(w, "ForwardKeySize")) {
2127 opt = JK_OPT_FWDKEYSIZE;
2129 else if (!strcasecmp(w, "RejectUnsafeURI")) {
2130 opt = JK_OPT_REJECTUNSAFE;
2133 return apr_pstrcat(cmd->pool, "JkOptions: Illegal option '", w,
2136 conf->options &= ~mask;
2138 if (action == '-') {
2139 conf->exclude_options |= opt;
2141 else if (action == '+') {
2142 conf->options |= opt;
2144 else { /* for now +Opt == Opt */
2145 conf->options |= opt;
2152 * JkEnvVar Directive Handling
2157 static const char *jk_add_env_var(cmd_parms * cmd,
2159 const char *env_name,
2160 const char *default_value)
2162 server_rec *s = cmd->server;
2163 jk_server_conf_t *conf =
2164 (jk_server_conf_t *) ap_get_module_config(s->module_config,
2167 conf->envvars_has_own = JK_TRUE;
2168 if (!conf->envvars) {
2169 conf->envvars = apr_table_make(cmd->pool, 0);
2170 conf->envvars_def = apr_table_make(cmd->pool, 0);
2171 conf->envvar_items = apr_array_make(cmd->pool, 0,
2172 sizeof(envvar_item));
2175 /* env_name is mandatory, default_value is optional.
2176 * No value means send the attribute only, if the env var is set during runtime.
2178 apr_table_setn(conf->envvars, env_name, default_value ? default_value : "");
2179 apr_table_setn(conf->envvars_def, env_name, default_value ? "1" : "0");
2185 * JkWorkerProperty Directive Handling
2187 * JkWorkerProperty name=value
2190 static const char *jk_set_worker_property(cmd_parms * cmd,
2194 server_rec *s = cmd->server;
2195 jk_server_conf_t *conf =
2196 (jk_server_conf_t *) ap_get_module_config(s->module_config,
2199 const char *err_string = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2200 if (err_string != NULL) {
2204 if (!jk_worker_properties)
2205 jk_map_alloc(&jk_worker_properties);
2206 if (jk_map_read_property(jk_worker_properties, NULL, line,
2207 JK_MAP_HANDLE_DUPLICATES, conf->log) == JK_FALSE)
2208 return apr_pstrcat(cmd->temp_pool, "Invalid JkWorkerProperty ", line, NULL);
2213 static const command_rec jk_cmds[] = {
2215 * JkWorkersFile specifies a full path to the location of the worker
2218 * This file defines the different workers used by apache to redirect
2221 AP_INIT_TAKE1("JkWorkersFile", jk_set_worker_file, NULL, RSRC_CONF,
2222 "The name of a worker file for the Tomcat servlet containers"),
2225 * JkMountFile specifies a full path to the location of the
2226 * uriworker properties file.
2228 * This file defines the different mapping for workers used by apache
2229 * to redirect servlet requests.
2231 AP_INIT_TAKE1("JkMountFile", jk_set_mount_file, NULL, RSRC_CONF,
2232 "The name of a mount file for the Tomcat servlet uri mapping"),
2235 * JkMountFileReload specifies the reload check interval for the
2236 * uriworker properties file.
2238 * Default value is: JK_URIMAP_DEF_RELOAD
2240 AP_INIT_TAKE1("JkMountFileReload", jk_set_mount_file_reload, NULL, RSRC_CONF,
2241 "The reload check interval of the mount file"),
2244 * JkWatchdogInterval specifies the maintain interval for the
2247 * Default value is: 0 meaning watchdog thread will not be created
2249 AP_INIT_TAKE1("JkWatchdogInterval", jk_set_watchdog_interval, NULL, RSRC_CONF,
2250 "The maintain interval of the watchdog thread"),
2253 * JkMount mounts a url prefix to a worker (the worker need to be
2254 * defined in the worker properties file.
2256 AP_INIT_TAKE12("JkMount", jk_mount_context, NULL, RSRC_CONF|ACCESS_CONF,
2257 "A mount point from a context to a Tomcat worker"),
2260 * JkUnMount unmounts a url prefix to a worker (the worker need to be
2261 * defined in the worker properties file.
2263 AP_INIT_TAKE12("JkUnMount", jk_unmount_context, NULL, RSRC_CONF|ACCESS_CONF,
2264 "A no mount point from a context to a Tomcat worker"),
2267 * JkMountCopy specifies if mod_jk should copy the mount points
2268 * from the main server to the virtual servers.
2270 AP_INIT_TAKE1("JkMountCopy", jk_set_mountcopy, NULL, RSRC_CONF,
2271 "Should the base server mounts be copied to the virtual server"),
2274 * JkStripSession specifies if mod_jk should strip the ;jsessionid
2275 * from the unmapped urls
2277 AP_INIT_TAKE12("JkStripSession", jk_set_strip_session, NULL, RSRC_CONF,
2278 "Should the server strip the jsessionid from unmapped URLs"),
2281 * JkLogFile & JkLogLevel specifies to where should the plugin log
2282 * its information and how much.
2283 * JkLogStampFormat specify the time-stamp to be used on log
2285 AP_INIT_TAKE1("JkLogFile", jk_set_log_file, NULL, RSRC_CONF,
2286 "Full path to the Tomcat module log file"),
2288 AP_INIT_TAKE1("JkShmFile", jk_set_shm_file, NULL, RSRC_CONF,
2289 "Full path to the Tomcat module shared memory file"),
2291 AP_INIT_TAKE1("JkShmSize", jk_set_shm_size, NULL, RSRC_CONF,
2292 "Size of the shared memory file in KBytes"),
2294 AP_INIT_TAKE1("JkLogLevel", jk_set_log_level, NULL, RSRC_CONF,
2295 "The Tomcat module log level, can be debug, "
2296 "info, error or emerg"),
2297 AP_INIT_TAKE1("JkLogStampFormat", jk_set_log_fmt, NULL, RSRC_CONF,
2298 "The Tomcat module log format, follow strftime syntax"),
2299 AP_INIT_TAKE1("JkRequestLogFormat", jk_set_request_log_format, NULL,
2301 "The mod_jk module request log format string"),
2304 * Automatically Alias webapp context directories into the Apache
2307 AP_INIT_TAKE1("JkAutoAlias", jk_set_auto_alias, NULL, RSRC_CONF,
2308 "The mod_jk module automatic context apache alias directory"),
2311 * Enable worker name to be set in an environment variable.
2312 * This way one can use LocationMatch together with mod_env,
2313 * mod_setenvif and mod_rewrite to set the target worker.
2314 * Use this in combination with SetHandler jakarta-servlet to
2315 * make mod_jk the handler for the request.
2318 AP_INIT_TAKE1("JkWorkerIndicator", jk_set_worker_indicator, NULL, RSRC_CONF,
2319 "Name of the Apache environment that contains the worker name"),
2322 * Environment variables used to overwrite the following
2323 * request information which gets forwarded:
2332 AP_INIT_TAKE1("JkRemoteAddrIndicator", jk_set_remote_addr_indicator, NULL, RSRC_CONF,
2333 "Name of the Apache environment that contains the remote address"),
2334 AP_INIT_TAKE1("JkRemotePortIndicator", jk_set_remote_port_indicator, NULL, RSRC_CONF,
2335 "Name of the Apache environment that contains the remote port"),
2336 AP_INIT_TAKE1("JkRemoteHostIndicator", jk_set_remote_host_indicator, NULL, RSRC_CONF,
2337 "Name of the Apache environment that contains the remote host name"),
2338 AP_INIT_TAKE1("JkRemoteUserIndicator", jk_set_remote_user_indicator, NULL, RSRC_CONF,
2339 "Name of the Apache environment that contains the remote user name"),
2340 AP_INIT_TAKE1("JkAuthTypeIndicator", jk_set_auth_type_indicator, NULL, RSRC_CONF,
2341 "Name of the Apache environment that contains the type of authentication"),
2342 AP_INIT_TAKE1("JkLocalNameIndicator", jk_set_local_name_indicator, NULL, RSRC_CONF,
2343 "Name of the Apache environment that contains the local name"),
2344 AP_INIT_TAKE1("JkLocalPortIndicator", jk_set_local_port_indicator, NULL, RSRC_CONF,
2345 "Name of the Apache environment that contains the local port"),
2348 * Apache has multiple SSL modules (for example apache_ssl, stronghold
2349 * IHS ...). Each of these can have a different SSL environment names
2350 * The following properties let the administrator specify the envoiroment
2353 * HTTPS - indication for SSL
2354 * CERTS - Base64-Der-encoded client certificates.
2355 * CIPHER - A string specifing the ciphers suite in use.
2356 * KEYSIZE - Size of Key used in dialogue (#bits are secure)
2357 * SESSION - A string specifing the current SSL session.
2359 AP_INIT_TAKE1("JkHTTPSIndicator", jk_set_https_indicator, NULL, RSRC_CONF,
2360 "Name of the Apache environment that contains SSL indication"),
2361 AP_INIT_TAKE1("JkCERTSIndicator", jk_set_certs_indicator, NULL, RSRC_CONF,
2362 "Name of the Apache environment that contains SSL client certificates"),
2363 AP_INIT_TAKE1("JkCIPHERIndicator", jk_set_cipher_indicator, NULL,
2365 "Name of the Apache environment that contains SSL client cipher"),
2366 AP_INIT_TAKE1("JkSESSIONIndicator", jk_set_session_indicator, NULL,
2368 "Name of the Apache environment that contains SSL session"),
2369 AP_INIT_TAKE1("JkKEYSIZEIndicator", jk_set_key_size_indicator, NULL,
2371 "Name of the Apache environment that contains SSL key size in use"),
2372 AP_INIT_TAKE1("JkCERTCHAINPrefix", jk_set_certchain_prefix, NULL, RSRC_CONF,
2373 "Name of the Apache environment (prefix) that contains SSL client chain certificates"),
2374 AP_INIT_FLAG("JkExtractSSL", jk_set_enable_ssl, NULL, RSRC_CONF,
2375 "Turns on SSL processing and information gathering by mod_jk"),
2378 * Options to tune mod_jk configuration
2379 * for now we understand :
2380 * +ForwardSSLKeySize => Forward SSL Key Size, to follow 2.3 specs but may broke old TC 3.2
2381 * -ForwardSSLKeySize => Don't Forward SSL Key Size, will make mod_jk works with all TC release
2382 * ForwardURICompat => Forward URI normally, less spec compliant but mod_rewrite compatible (old TC)
2383 * ForwardURICompatUnparsed => Forward URI as unparsed, spec compliant but broke mod_rewrite (old TC)
2384 * ForwardURIEscaped => Forward URI escaped and Tomcat (3.3 rc2) stuff will do the decoding part
2385 * +ForwardSSLCertChain => Forward SSL certificate chain
2386 * -ForwardSSLCertChain => Don't forward SSL certificate chain
2388 AP_INIT_RAW_ARGS("JkOptions", jk_set_options, NULL, RSRC_CONF,
2389 "Set one of more options to configure the mod_jk module"),
2392 * JkEnvVar let user defines envs var passed from WebServer to
2395 AP_INIT_TAKE12("JkEnvVar", jk_add_env_var, NULL, RSRC_CONF,
2396 "Adds a name of environment variable and an optional value "
2397 "that should be sent to servlet-engine"),
2399 AP_INIT_RAW_ARGS("JkWorkerProperty", jk_set_worker_property,
2401 "Set workers.properties formated directive"),
2406 /* ========================================================================= */
2407 /* The JK module handlers */
2408 /* ========================================================================= */
2410 /** Util - cleanup shmem.
2412 static apr_status_t jk_cleanup_shmem(void *data)
2414 /* Force the watchdog thread exit */
2415 if (jk_watchdog_interval > 0) {
2416 jk_watchdog_interval = 0;
2417 while (jk_watchdog_running)
2418 apr_sleep(apr_time_from_sec(1));
2424 /** Main service method, called to forward a request to tomcat
2426 static int jk_handler(request_rec * r)
2428 const char *worker_name;
2429 jk_server_conf_t *xconf;
2432 /* We do DIR_MAGIC_TYPE here to make sure TC gets all requests, even
2433 * if they are directory requests, in case there are no static files
2434 * visible to Apache and/or DirectoryIndex was not used. This is only
2435 * used when JkOptions has ForwardDirectories set. */
2436 /* Not for me, try next handler */
2437 if (strcmp(r->handler, JK_HANDLER)
2438 && (dmt = strcmp(r->handler, DIR_MAGIC_TYPE)))
2441 xconf = (jk_server_conf_t *) ap_get_module_config(r->server->module_config,
2443 JK_TRACE_ENTER(xconf->log);
2444 if (apr_table_get(r->subprocess_env, "no-jk")) {
2445 if (JK_IS_DEBUG_LEVEL(xconf->log))
2446 jk_log(xconf->log, JK_LOG_DEBUG,
2447 "Into handler no-jk env var detected for uri=%s, declined",
2450 JK_TRACE_EXIT(xconf->log);
2454 /* Was the option to forward directories to Tomcat set? */
2455 if (!dmt && !(xconf->options & JK_OPT_FWDDIRS)) {
2456 JK_TRACE_EXIT(xconf->log);
2459 worker_name = apr_table_get(r->notes, JK_NOTE_WORKER_NAME);
2461 /* Set up r->read_chunked flags for chunked encoding, if present */
2462 if ((rc = ap_setup_client_block(r, REQUEST_CHUNKED_DECHUNK)) != APR_SUCCESS) {
2463 JK_TRACE_EXIT(xconf->log);
2467 if (worker_name == NULL) {
2468 /* we may be here because of a manual directive ( that overrides
2470 sets the handler directly ). We still need to know the worker.
2472 worker_name = apr_table_get(r->subprocess_env, xconf->worker_indicator);
2474 /* The JkWorkerIndicator environment variable has
2475 * been used to explicitely set the worker without JkMount.
2476 * This is useful in combination with LocationMatch or mod_rewrite.
2478 if (JK_IS_DEBUG_LEVEL(xconf->log))
2479 jk_log(xconf->log, JK_LOG_DEBUG,
2480 "Retrieved worker (%s) from env %s for %s",
2481 worker_name, xconf->worker_indicator, r->uri);
2483 else if (worker_env.num_of_workers == 1) {
2484 /** We have a single worker ( the common case ).
2485 ( lb is a bit special, it should count as a single worker but
2486 I'm not sure how ). We also have a manual config directive that
2487 explicitely give control to us. */
2488 worker_name = worker_env.worker_list[0];
2489 if (JK_IS_DEBUG_LEVEL(xconf->log))
2490 jk_log(xconf->log, JK_LOG_DEBUG,
2491 "Single worker (%s) configuration for %s",
2492 worker_name, r->uri);
2495 if (!xconf->uw_map) {
2496 if (JK_IS_DEBUG_LEVEL(xconf->log))
2497 jk_log(xconf->log, JK_LOG_DEBUG,
2498 "missing uri map for %s:%s",
2499 xconf->s->server_hostname ? xconf->s->server_hostname : "_default_",
2503 rule_extension_t *e;
2504 worker_name = map_uri_to_worker_ext(xconf->uw_map, r->uri,
2505 NULL, &e, NULL, xconf->log);
2506 ap_set_module_config(r->request_config, &jk_module, e);
2509 if (worker_name == NULL && worker_env.num_of_workers) {
2510 worker_name = worker_env.worker_list[0];
2511 if (JK_IS_DEBUG_LEVEL(xconf->log))
2512 jk_log(xconf->log, JK_LOG_DEBUG,
2513 "Using first worker (%s) from %d workers for %s",
2514 worker_name, worker_env.num_of_workers, r->uri);
2518 apr_table_setn(r->notes, JK_NOTE_WORKER_NAME, worker_name);
2521 if (JK_IS_DEBUG_LEVEL(xconf->log))
2522 jk_log(xconf->log, JK_LOG_DEBUG, "Into handler %s worker=%s"
2524 r->handler, STRNULL_FOR_NULL(worker_name), r->proxyreq);
2526 /* If this is a proxy request, we'll notify an error */
2528 jk_log(xconf->log, JK_LOG_INFO, "Proxy request for worker=%s"
2530 STRNULL_FOR_NULL(worker_name));
2531 JK_TRACE_EXIT(xconf->log);
2532 return HTTP_INTERNAL_SERVER_ERROR;
2536 jk_worker_t *worker = wc_get_worker_for_name(worker_name, xconf->log);
2538 /* If the remote client has aborted, just ignore the request */
2539 if (r->connection->aborted) {
2540 jk_log(xconf->log, JK_LOG_INFO, "Client connection aborted for"
2543 JK_TRACE_EXIT(xconf->log);
2548 long micro, seconds;
2549 char *duration = NULL;
2551 apr_time_t request_begin = 0;
2552 int is_error = HTTP_INTERNAL_SERVER_ERROR;
2554 apache_private_data_t private_data;
2556 jk_pool_atom_t buf[SMALL_POOL_SIZE];
2557 jk_open_pool(&private_data.p, buf, sizeof(buf));
2559 private_data.read_body_started = JK_FALSE;
2562 /* Maintain will be done by watchdog thread */
2563 if (!jk_watchdog_interval)
2564 wc_maintain(xconf->log);
2565 jk_init_ws_service(&s);
2566 s.ws_private = &private_data;
2567 s.pool = &private_data.p;
2568 apr_table_setn(r->notes, JK_NOTE_WORKER_TYPE,
2569 wc_get_name_for_type(worker->type, xconf->log));
2571 request_begin = apr_time_now();
2573 if (init_ws_service(&private_data, &s, xconf)) {
2574 jk_endpoint_t *end = NULL;
2576 /* Use per/thread pool ( or "context" ) to reuse the
2577 endpoint. It's a bit faster, but I don't know
2578 how to deal with load balancing - but it's usefull for JNI
2581 /* worker->get_endpoint might fail if we are out of memory so check */
2583 if (worker->get_endpoint(worker, &end, xconf->log)) {
2584 rc = end->service(end, &s, xconf->log,
2586 end->done(&end, xconf->log);
2587 if (s.content_read < s.content_length ||
2588 (s.is_chunked && !s.no_more_chunks)) {
2590 * If the servlet engine didn't consume all of the
2591 * request data, consume and discard all further
2592 * characters left to read from client
2594 char *buff = apr_palloc(r->pool, 2048);
2599 ap_get_client_block(r, buff, 2048)) > 0) {
2600 s.content_read += rd;
2604 if (JK_IS_DEBUG_LEVEL(xconf->log)) {
2605 jk_log(xconf->log, JK_LOG_DEBUG,
2606 "Consumed %d bytes of remaining request data for worker=%s",
2607 consumed, STRNULL_FOR_NULL(worker_name));
2611 else { /* this means we couldn't get an endpoint */
2612 jk_log(xconf->log, JK_LOG_ERROR, "Could not get endpoint"
2615 rc = 0; /* just to make sure that we know we've failed */
2619 jk_log(xconf->log, JK_LOG_ERROR, "Could not init service"
2622 jk_close_pool(&private_data.p);
2623 JK_TRACE_EXIT(xconf->log);
2624 return HTTP_INTERNAL_SERVER_ERROR;
2626 rd = apr_time_now() - request_begin;
2627 seconds = (long)apr_time_sec(rd);
2628 micro = (long)(rd - apr_time_from_sec(seconds));
2630 duration = apr_psprintf(r->pool, "%.1ld.%.6ld", seconds, micro);
2631 apr_table_setn(r->notes, JK_NOTE_REQUEST_DURATION, duration);
2632 if (s.route && *s.route)
2633 apr_table_setn(r->notes, JK_NOTE_WORKER_ROUTE, s.route);
2635 if (xconf->format != NULL) {
2636 request_log_transaction(r, xconf);
2639 jk_close_pool(&private_data.p);
2642 if (s.extension.use_server_error_pages &&
2643 s.http_response_status >= s.extension.use_server_error_pages) {
2644 if (JK_IS_DEBUG_LEVEL(xconf->log))
2645 jk_log(xconf->log, JK_LOG_DEBUG, "Forwarding status=%d"
2647 s.http_response_status, worker_name);
2648 JK_TRACE_EXIT(xconf->log);
2649 return s.http_response_status;
2651 /* If tomcat returned no body and the status is not OK,
2652 let apache handle the error code */
2654 if (!r->sent_bodyct && r->status >= HTTP_BAD_REQUEST) {
2655 jk_log(xconf->log, JK_LOG_INFO, "No body with status=%d"
2657 r->status, worker_name);
2658 JK_TRACE_EXIT(xconf->log);
2661 if (JK_IS_DEBUG_LEVEL(xconf->log))
2662 jk_log(xconf->log, JK_LOG_DEBUG, "Service finished"
2663 " with status=%d for worker=%s",
2664 r->status, worker_name);
2665 JK_TRACE_EXIT(xconf->log);
2666 return OK; /* NOT r->status, even if it has changed. */
2668 else if (rc == JK_CLIENT_ERROR) {
2669 if (is_error != HTTP_REQUEST_ENTITY_TOO_LARGE)
2670 r->connection->aborted = 1;
2671 jk_log(xconf->log, JK_LOG_INFO, "Aborting connection"
2674 JK_TRACE_EXIT(xconf->log);
2678 jk_log(xconf->log, JK_LOG_INFO, "Service error=%d"
2681 JK_TRACE_EXIT(xconf->log);
2686 jk_log(xconf->log, JK_LOG_INFO, "Could not find a worker"
2687 " for worker name=%s",
2689 JK_TRACE_EXIT(xconf->log);
2690 return HTTP_INTERNAL_SERVER_ERROR;
2694 JK_TRACE_EXIT(xconf->log);
2698 /** Standard apache hook, cleanup jk
2700 static apr_status_t jk_apr_pool_cleanup(void *data)
2702 server_rec *s = data;
2704 if (jk_worker_properties) {
2705 jk_map_free(&jk_worker_properties);
2706 jk_worker_properties = NULL;
2707 jk_worker_file = NULL;
2708 jk_mount_copy_all = JK_FALSE;
2712 jk_server_conf_t *conf =
2713 (jk_server_conf_t *) ap_get_module_config(s->module_config,
2716 if (conf && conf->was_initialized == JK_TRUE) {
2717 /* On pool cleanup pass NULL for the jk_logger to
2718 prevent segmentation faults on Windows because
2719 we can't guarantee what order pools get cleaned
2720 up between APR implementations. */
2722 if (conf->uri_to_context) {
2723 jk_map_free(&conf->uri_to_context);
2724 /* We cannot have allocated uw_map
2725 * unless we've allocated uri_to_context
2728 uri_worker_map_free(&conf->uw_map, NULL);
2730 conf->was_initialized = JK_FALSE;
2737 /** Create default jk_config. XXX This is mostly server-independent,
2738 all servers are using something similar - should go to common.
2740 static void *create_jk_config(apr_pool_t * p, server_rec * s)
2742 jk_server_conf_t *c =
2743 (jk_server_conf_t *) apr_pcalloc(p, sizeof(jk_server_conf_t));
2745 c->was_initialized = JK_FALSE;
2747 if (s->is_virtual) {
2748 c->mountcopy = JK_UNSET;
2749 c->mount_file_reload = JK_UNSET;
2750 c->log_level = JK_UNSET;
2751 c->ssl_enable = JK_UNSET;
2752 c->strip_session = JK_UNSET;
2754 if (!jk_map_alloc(&(c->uri_to_context))) {
2755 ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "Memory error");
2757 c->mountcopy = JK_FALSE;
2758 c->mount_file_reload = JK_URIMAP_DEF_RELOAD;
2759 c->log_level = JK_LOG_DEF_LEVEL;
2760 c->options = JK_OPT_DEFAULT;
2761 c->worker_indicator = JK_ENV_WORKER_NAME;
2764 * Configurable environment variables to overwrite
2765 * request information using meta data send by a
2766 * proxy in front of us.
2768 c->remote_addr_indicator = JK_ENV_REMOTE_ADDR;
2769 c->remote_port_indicator = JK_ENV_REMOTE_PORT;
2770 c->remote_host_indicator = JK_ENV_REMOTE_HOST;
2771 c->remote_user_indicator = JK_ENV_REMOTE_USER;
2772 c->auth_type_indicator = JK_ENV_AUTH_TYPE;
2773 c->local_name_indicator = JK_ENV_LOCAL_NAME;
2774 c->local_port_indicator = JK_ENV_LOCAL_PORT;
2777 * By default we will try to gather SSL info.
2778 * Disable this functionality through JkExtractSSL
2780 c->ssl_enable = JK_TRUE;
2782 * The defaults ssl indicators match those in mod_ssl (seems
2783 * to be in more use).
2785 c->https_indicator = JK_ENV_HTTPS;
2786 c->certs_indicator = JK_ENV_CERTS;
2787 c->cipher_indicator = JK_ENV_CIPHER;
2788 c->certchain_prefix = JK_ENV_CERTCHAIN_PREFIX;
2789 c->session_indicator = JK_ENV_SESSION;
2790 c->key_size_indicator = JK_ENV_KEY_SIZE;
2791 c->strip_session = JK_FALSE;
2793 c->envvars_has_own = JK_FALSE;
2796 apr_pool_cleanup_register(p, s, jk_apr_pool_cleanup, apr_pool_cleanup_null);
2802 * Utility - copy items from apr table src to dst,
2803 * for keys that exist in src but not in dst.
2805 static void merge_apr_table(apr_table_t *src, apr_table_t *dst)
2808 const apr_array_header_t *arr;
2809 const apr_table_entry_t *elts;
2811 arr = apr_table_elts(src);
2812 elts = (const apr_table_entry_t *)arr->elts;
2813 for (i = 0; i < arr->nelts; ++i) {
2814 if (!apr_table_get(dst, elts[i].key)) {
2815 apr_table_setn(dst, elts[i].key, elts[i].val);
2821 /** Standard apache callback, merge jk options specified in <Directory>
2824 static void *merge_jk_config(apr_pool_t * p, void *basev, void *overridesv)
2826 jk_server_conf_t *base = (jk_server_conf_t *) basev;
2827 jk_server_conf_t *overrides = (jk_server_conf_t *) overridesv;
2829 if (!overrides->log_file)
2830 overrides->log_file = base->log_file;
2831 if (overrides->log_level == JK_UNSET)
2832 overrides->log_level = base->log_level;
2834 if (!overrides->stamp_format_string)
2835 overrides->stamp_format_string = base->stamp_format_string;
2836 if (!overrides->format_string)
2837 overrides->format_string = base->format_string;
2839 if (!overrides->worker_indicator)
2840 overrides->worker_indicator = base->worker_indicator;
2842 if (!overrides->remote_addr_indicator)
2843 overrides->remote_addr_indicator = base->remote_addr_indicator;
2844 if (!overrides->remote_port_indicator)
2845 overrides->remote_port_indicator = base->remote_port_indicator;
2846 if (!overrides->remote_host_indicator)
2847 overrides->remote_host_indicator = base->remote_host_indicator;
2848 if (!overrides->remote_user_indicator)
2849 overrides->remote_user_indicator = base->remote_user_indicator;
2850 if (!overrides->auth_type_indicator)
2851 overrides->auth_type_indicator = base->auth_type_indicator;
2852 if (!overrides->local_name_indicator)
2853 overrides->local_name_indicator = base->local_name_indicator;
2854 if (!overrides->local_port_indicator)
2855 overrides->local_port_indicator = base->local_port_indicator;
2857 if (overrides->ssl_enable == JK_UNSET)
2858 overrides->ssl_enable = base->ssl_enable;
2859 if (!overrides->https_indicator)
2860 overrides->https_indicator = base->https_indicator;
2861 if (!overrides->certs_indicator)
2862 overrides->certs_indicator = base->certs_indicator;
2863 if (!overrides->cipher_indicator)
2864 overrides->cipher_indicator = base->cipher_indicator;
2865 if (!overrides->certchain_prefix)
2866 overrides->certchain_prefix = base->certchain_prefix;
2867 if (!overrides->session_indicator)
2868 overrides->session_indicator = base->session_indicator;
2869 if (!overrides->key_size_indicator)
2870 overrides->key_size_indicator = base->key_size_indicator;
2872 /* Don't simply accumulate bits in the JK_OPT_FWDURIMASK region, */
2873 /* because those are multi-bit values. */
2874 if (overrides->options & JK_OPT_FWDURIMASK)
2875 overrides->options |= (base->options & ~base->exclude_options) & ~JK_OPT_FWDURIMASK;
2877 overrides->options |= (base->options & ~base->exclude_options);
2879 if (base->envvars) {
2880 if (overrides->envvars && overrides->envvars_has_own) {
2881 /* merge_apr_table() preserves existing entries in overrides table */
2882 merge_apr_table(base->envvars, overrides->envvars);
2883 merge_apr_table(base->envvars_def, overrides->envvars_def);
2886 overrides->envvars = base->envvars;
2887 overrides->envvars_def = base->envvars_def;
2888 overrides->envvar_items = base->envvar_items;
2892 if (overrides->mountcopy == JK_UNSET && jk_mount_copy_all == JK_TRUE) {
2893 overrides->mountcopy = JK_TRUE;
2895 if (overrides->uri_to_context && overrides->mountcopy == JK_TRUE) {
2896 /* jk_map_copy() preserves existing entries in overrides map */
2897 if (jk_map_copy(base->uri_to_context, overrides->uri_to_context) == JK_FALSE) {
2898 jk_error_exit(JKLOG_MARK, APLOG_EMERG, overrides->s, p, "Memory error");
2900 if (!overrides->mount_file)
2901 overrides->mount_file = base->mount_file;
2903 if (overrides->mountcopy == JK_TRUE) {
2904 if (!overrides->alias_dir)
2905 overrides->alias_dir = base->alias_dir;
2907 if (overrides->mount_file_reload == JK_UNSET)
2908 overrides->mount_file_reload = base->mount_file_reload;
2909 if (overrides->strip_session == JK_UNSET) {
2910 overrides->strip_session = base->strip_session;
2911 overrides->strip_session_name = base->strip_session_name;
2916 static int JK_METHOD jk_log_to_file(jk_logger_t *l, int level,
2917 int used, char *what)
2920 (l->level <= level || level == JK_LOG_REQUEST_LEVEL) &&
2921 l->logger_private && what && used > 0) {
2922 jk_file_logger_t *p = l->logger_private;
2927 what[used++] = '\r';
2929 what[used++] = '\n';
2931 rv = apr_global_mutex_lock(jk_log_lock);
2932 if (rv != APR_SUCCESS) {
2933 ap_log_error(APLOG_MARK, APLOG_ERR, rv, NULL,
2934 "apr_global_mutex_lock(jk_log_lock) failed");
2935 /* XXX: Maybe this should be fatal? */
2937 rv = apr_file_write(p->jklogfp, what, &wrote);
2938 if (rv != APR_SUCCESS) {
2940 apr_strerror(rv, error, 254);
2941 ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
2942 "mod_jk: jk_log_to_file %s failed: %s",
2945 rv = apr_global_mutex_unlock(jk_log_lock);
2946 if (rv != APR_SUCCESS) {
2947 ap_log_error(APLOG_MARK, APLOG_ERR, rv, NULL,
2948 "apr_global_mutex_unlock(jk_log_lock) failed");
2949 /* XXX: Maybe this should be fatal? */
2960 ** +-------------------------------------------------------+
2962 ** | jk logfile support |
2964 ** +-------------------------------------------------------+
2967 static apr_status_t jklog_cleanup(void *d)
2969 /* hgomez@20070425 */
2970 /* Clean up pointer content */
2972 *(jk_logger_t **)d = NULL;
2977 static int open_jklog(server_rec * s, apr_pool_t * p)
2979 jk_server_conf_t *conf;
2982 apr_file_t *jklogfp;
2985 jk_file_logger_t *flp;
2986 int jklog_flags = (APR_WRITE | APR_APPEND | APR_CREATE);
2987 apr_fileperms_t jklog_mode =
2988 (APR_UREAD | APR_UWRITE | APR_GREAD | APR_WREAD);
2990 conf = ap_get_module_config(s->module_config, &jk_module);
2992 if (conf->log_file == NULL) {
2993 conf->log_file = ap_server_root_relative(p, JK_LOG_DEF_FILE);
2995 ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s,
2996 "No JkLogFile defined in httpd.conf. "
2997 "Using default %s", conf->log_file);
2999 if (*(conf->log_file) == '\0') {
3000 ap_log_error(APLOG_MARK, APLOG_ERR, APR_EBADPATH, s,
3001 "mod_jk: Invalid JkLogFile EMPTY");
3002 conf->log = main_log;
3006 jklogfp = apr_hash_get(jk_log_fps, conf->log_file, APR_HASH_KEY_STRING);
3008 if (*conf->log_file == '|') {
3009 if ((pl = ap_open_piped_log(p, conf->log_file + 1)) == NULL) {
3010 ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
3011 "mod_jk: could not open reliable pipe "
3012 "to jk log %s", conf->log_file + 1);
3015 jklogfp = (void *)ap_piped_log_write_fd(pl);
3018 fname = ap_server_root_relative(p, conf->log_file);
3020 ap_log_error(APLOG_MARK, APLOG_ERR, APR_EBADPATH, s,
3021 "mod_jk: Invalid JkLog " "path %s", conf->log_file);
3024 if ((rc = apr_file_open(&jklogfp, fname,
3025 jklog_flags, jklog_mode, p))
3027 ap_log_error(APLOG_MARK, APLOG_ERR, rc, s,
3028 "mod_jk: could not open JkLog " "file %s", fname);
3032 apr_file_inherit_set(jklogfp);
3033 apr_hash_set(jk_log_fps, conf->log_file, APR_HASH_KEY_STRING, jklogfp);
3035 conf->jklogfp = jklogfp;
3036 jkl = (jk_logger_t *)apr_palloc(p, sizeof(jk_logger_t));
3037 flp = (jk_file_logger_t *) apr_palloc(p, sizeof(jk_file_logger_t));
3039 jkl->log = jk_log_to_file;
3040 jkl->level = conf->log_level;
3041 jkl->logger_private = flp;
3042 flp->jklogfp = conf->jklogfp;
3044 jk_set_time_fmt(conf->log, conf->stamp_format_string);
3045 if (main_log == NULL) {
3046 main_log = conf->log;
3048 /* hgomez@20070425 */
3049 /* Shouldn't we clean both conf->log and main_log ? */
3050 /* Also should we pass pointer (ie: main_log) or handle (*main_log) ? */
3051 apr_pool_cleanup_register(p, &main_log,
3053 apr_pool_cleanup_null);
3064 static void * APR_THREAD_FUNC jk_watchdog_func(apr_thread_t *thd, void *data)
3067 jk_server_conf_t *conf = (jk_server_conf_t *)data;
3069 if (JK_IS_DEBUG_LEVEL(conf->log))
3070 jk_log(conf->log, JK_LOG_DEBUG,
3071 "Watchdog thread initialized with %d second interval",
3072 jk_watchdog_interval);
3074 for (i = 0; i < (jk_watchdog_interval * 10); i++) {
3075 /* apr_sleep() uses microseconds */
3076 apr_sleep((apr_time_t)(100000));
3077 if (!jk_watchdog_interval)
3080 if (!jk_watchdog_interval)
3082 if (JK_IS_DEBUG_LEVEL(conf->log))
3083 jk_log(conf->log, JK_LOG_DEBUG,
3084 "Watchdog thread running");
3085 jk_watchdog_running = 1;
3086 wc_maintain(conf->log);
3087 if (!jk_watchdog_interval)
3090 jk_watchdog_running = 0;
3096 /** Standard apache callback, initialize jk.
3098 static void jk_child_init(apr_pool_t * pconf, server_rec * s)
3100 jk_server_conf_t *conf;
3105 conf = ap_get_module_config(s->module_config, &jk_module);
3107 rv = apr_global_mutex_child_init(&jk_log_lock, NULL, pconf);
3108 if (rv != APR_SUCCESS) {
3109 ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
3110 "mod_jk: could not init JK log lock in child");
3113 JK_TRACE_ENTER(conf->log);
3115 if (jk_watchdog_interval) {
3117 rv = apr_thread_create(&wdt, NULL, jk_watchdog_func, conf, pconf);
3118 if (rv != APR_SUCCESS) {
3119 jk_log(conf->log, JK_LOG_ERROR,
3120 "Could not init watchdog thread, error=%d", rv);
3121 jk_watchdog_interval = 0;
3123 apr_thread_detach(wdt);
3127 if ((rc = jk_shm_attach(jk_shm_file, jk_shm_size, conf->log)) == 0) {
3128 apr_pool_cleanup_register(pconf, conf->log, jk_cleanup_shmem,
3129 apr_pool_cleanup_null);
3132 jk_log(conf->log, JK_LOG_ERROR, "Attaching shm:%s errno=%d",
3135 if (JK_IS_DEBUG_LEVEL(conf->log))
3136 jk_log(conf->log, JK_LOG_DEBUG, "Initialized %s", JK_FULL_EXPOSED_VERSION);
3137 JK_TRACE_EXIT(conf->log);
3140 /** Initialize jk, using worker.properties.
3141 We also use apache commands ( JkWorker, etc), but this use is
3142 deprecated, as we'll try to concentrate all config in
3143 workers.properties, urimap.properties, and ajp14 autoconf.
3145 Apache config will only be used for manual override, using
3146 SetHandler and normal apache directives ( but minimal jk-specific
3149 static int init_jk(apr_pool_t * pconf, jk_server_conf_t * conf,
3154 int mpm_threads = 1;
3156 if (!jk_worker_properties)
3157 jk_map_alloc(&jk_worker_properties);
3158 jk_map_put(jk_worker_properties, "ServerRoot", ap_server_root, NULL);
3160 /* Set default connection cache size for multi-threaded MPMs */
3161 if (ap_mpm_query(AP_MPMQ_IS_THREADED, &is_threaded) == APR_SUCCESS &&
3162 is_threaded != AP_MPMQ_NOT_SUPPORTED) {
3163 if (ap_mpm_query(AP_MPMQ_MAX_THREADS, &mpm_threads) != APR_SUCCESS)
3166 if (mpm_threads > 1) {
3169 if (JK_IS_DEBUG_LEVEL(conf->log)) {
3170 #if !defined(WIN32) && !defined(NETWARE)
3172 jk_log(conf->log, JK_LOG_DEBUG,
3173 "Using flock() for locking.");
3175 jk_log(conf->log, JK_LOG_DEBUG,
3176 "Using fcntl() for locking.");
3177 #endif /* USE_FLOCK_LK */
3179 jk_log(conf->log, JK_LOG_DEBUG,
3180 "Not using locking.");
3185 ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s,
3186 "Cannot run prefork mod_jk on threaded server.");
3190 if (JK_IS_DEBUG_LEVEL(conf->log))
3191 jk_log(conf->log, JK_LOG_DEBUG,
3192 "Setting default connection pool max size to %d",
3194 jk_set_worker_def_cache_size(mpm_threads);
3196 if ((jk_worker_file != NULL) &&
3197 !jk_map_read_properties(jk_worker_properties, NULL, jk_worker_file, NULL,
3198 JK_MAP_HANDLE_DUPLICATES, conf->log)) {
3199 ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s,
3200 "Error in reading worker properties from '%s'",
3205 if (jk_map_resolve_references(jk_worker_properties, "worker.",
3206 1, 1, conf->log) == JK_FALSE) {
3207 ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s,
3208 "Error in resolving configuration references");
3212 #if !defined(WIN32) && !defined(NETWARE)
3214 jk_shm_file = ap_server_root_relative(pconf, JK_SHM_DEF_FILE);
3216 ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s,
3217 "No JkShmFile defined in httpd.conf. "
3218 "Using default %s", jk_shm_file);
3221 if (jk_shm_size == 0)
3222 jk_shm_size = jk_shm_calculate_size(jk_worker_properties, conf->log);
3223 else if (jk_shm_size_set) {
3224 jk_log(conf->log, JK_LOG_WARNING,
3225 "The optimal shared memory size can now be determined automatically.");
3226 jk_log(conf->log, JK_LOG_WARNING,
3227 "You can remove the JkShmSize directive if you want to use the optimal size.");
3229 if ((rc = jk_shm_open(jk_shm_file, jk_shm_size, conf->log)) == 0) {
3230 apr_pool_cleanup_register(pconf, conf->log,
3232 apr_pool_cleanup_null);
3235 jk_log(conf->log, JK_LOG_ERROR,
3236 "Initializing shm:%s errno=%d. Load balancing workers will not function properly.",
3239 /* we add the URI->WORKER MAP since workers using AJP14
3241 worker_env.uri_to_worker = conf->uw_map;
3242 worker_env.virtual = "*"; /* for now */
3243 #if ((AP_MODULE_MAGIC_AT_LEAST(20051115,4)) && !defined(API_COMPATIBILITY)) || (MODULE_MAGIC_NUMBER_MAJOR >= 20060905)
3244 worker_env.server_name = (char *)ap_get_server_description();
3246 worker_env.server_name = (char *)ap_get_server_version();
3248 worker_env.pool = pconf;
3250 if (wc_open(jk_worker_properties, &worker_env, conf->log)) {
3251 ap_add_version_component(pconf, JK_EXPOSED_VERSION);
3252 jk_log(conf->log, JK_LOG_INFO,
3254 JK_FULL_EXPOSED_VERSION);
3257 ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s,
3258 "Error in creating the workers."
3259 " Please consult your mod_jk log file '%s'.", conf->log_file);
3265 static int jk_post_config(apr_pool_t * pconf,
3267 apr_pool_t * ptemp, server_rec * s)
3270 jk_server_conf_t *conf;
3271 server_rec *srv = s;
3272 const char *err_string = NULL;
3275 apr_pool_userdata_get(&data, JK_LOG_LOCK_KEY, s->process->pool);
3277 /* create the jk log lockfiles in the parent */
3278 if ((rv = apr_global_mutex_create(&jk_log_lock, NULL,
3280 s->process->pool)) != APR_SUCCESS) {
3281 ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
3282 "mod_jk: could not create jk_log_lock");
3283 return HTTP_INTERNAL_SERVER_ERROR;
3286 #if JK_NEED_SET_MUTEX_PERMS
3287 #if (MODULE_MAGIC_NUMBER_MAJOR >= 20090208)
3288 rv = ap_unixd_set_global_mutex_perms(jk_log_lock);
3290 rv = unixd_set_global_mutex_perms(jk_log_lock);
3292 if (rv != APR_SUCCESS) {
3293 ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
3294 "mod_jk: Could not set permissions on "
3295 "jk_log_lock; check User and Group directives");
3296 return HTTP_INTERNAL_SERVER_ERROR;
3299 apr_pool_userdata_set((const void *)jk_log_lock, JK_LOG_LOCK_KEY,
3300 apr_pool_cleanup_null, s->process->pool);
3302 jk_log_lock = (apr_global_mutex_t *)data;
3306 jk_log_fps = apr_hash_make(pconf);
3308 if (!s->is_virtual) {
3309 conf = (jk_server_conf_t *)ap_get_module_config(s->module_config,
3311 if (conf->was_initialized == JK_FALSE) {
3312 /* step through the servers and open each jk logfile
3313 * and do additional post config initialization.
3315 for (; srv; srv = srv->next) {
3316 jk_server_conf_t *sconf = (jk_server_conf_t *)ap_get_module_config(srv->module_config,
3320 * If a virtual server contains no JK directive, httpd shares
3321 * the config structure. But we don't want to share some settings
3322 * by default, especially the JkMount rules.
3323 * Therefore we check, if this config structure really belongs to this
3324 * vhost, otherwise we create a new one and merge.
3326 if (sconf && sconf->s != srv) {
3327 jk_server_conf_t *srvconf = (jk_server_conf_t *)create_jk_config(pconf, srv);
3328 sconf = (jk_server_conf_t *)merge_jk_config(pconf, sconf, srvconf);
3329 ap_set_module_config(srv->module_config, &jk_module, sconf);
3333 if (sconf && sconf->was_initialized == JK_FALSE) {
3334 sconf->was_initialized = JK_TRUE;
3335 if (open_jklog(srv, pconf))
3336 return HTTP_INTERNAL_SERVER_ERROR;
3337 sconf->options &= ~sconf->exclude_options;
3338 if (sconf->uri_to_context) {
3339 if (!uri_worker_map_alloc(&(sconf->uw_map),
3340 sconf->uri_to_context, sconf->log))
3341 jk_error_exit(JKLOG_MARK, APLOG_EMERG, srv,
3342 srv->process->pool, "Memory error");
3343 if (sconf->options & JK_OPT_REJECTUNSAFE)
3344 sconf->uw_map->reject_unsafe = 1;
3346 sconf->uw_map->reject_unsafe = 0;
3347 if (sconf->mount_file) {
3348 sconf->uw_map->fname = sconf->mount_file;
3349 sconf->uw_map->reload = sconf->mount_file_reload;
3350 uri_worker_map_switch(sconf->uw_map, sconf->log);
3351 uri_worker_map_load(sconf->uw_map, sconf->log);
3355 if (sconf->mountcopy == JK_TRUE) {
3356 sconf->uw_map = conf->uw_map;
3359 if (sconf->format_string) {
3361 parse_request_log_string(pconf, sconf->format_string, &err_string);
3362 if (sconf->format == NULL)
3363 ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
3364 "JkRequestLogFormat format array NULL");
3366 if (sconf->envvars && sconf->envvars_has_own) {
3368 const apr_array_header_t *arr;
3369 const apr_table_entry_t *elts;
3371 const char *envvar_def;
3373 arr = apr_table_elts(sconf->envvars);
3375 elts = (const apr_table_entry_t *)arr->elts;
3376 for (i = 0; i < arr->nelts; ++i) {
3377 item = (envvar_item *)apr_array_push(sconf->envvar_items);
3379 return HTTP_INTERNAL_SERVER_ERROR;
3380 item->name = elts[i].key;
3381 envvar_def = apr_table_get(sconf->envvars_def, elts[i].key);
3382 if (envvar_def && !strcmp("1", envvar_def) ) {
3383 item->value = elts[i].val;
3384 item->has_default = 1;
3388 item->has_default = 0;
3395 conf->was_initialized = JK_TRUE;
3396 if (init_jk(pconf, conf, s) == JK_FALSE)
3397 return HTTP_INTERNAL_SERVER_ERROR;
3399 uri_worker_map_ext(conf->uw_map, conf->log);
3400 uri_worker_map_switch(conf->uw_map, conf->log);
3402 for (srv = s; srv; srv = srv->next) {
3403 jk_server_conf_t *sconf = (jk_server_conf_t *)ap_get_module_config(srv->module_config,
3405 if (conf->uw_map != sconf->uw_map && sconf->uw_map) {
3406 uri_worker_map_ext(sconf->uw_map, sconf->log);
3407 uri_worker_map_switch(sconf->uw_map, sconf->log);
3417 /** Use the internal mod_jk mappings to find if this is a request for
3418 * tomcat and what worker to use.
3420 static int jk_translate(request_rec * r)
3422 ap_set_module_config(r->request_config, &jk_module, NULL);
3425 jk_server_conf_t *conf =
3426 (jk_server_conf_t *) ap_get_module_config(r->server->
3432 if ((r->handler != NULL) && (!strcmp(r->handler, JK_HANDLER))) {
3433 /* Somebody already set the handler, probably manual config
3434 * or "native" configuration, no need for extra overhead
3436 if (JK_IS_DEBUG_LEVEL(conf->log))
3437 jk_log(conf->log, JK_LOG_DEBUG,
3438 "Manually mapped, no need to call uri_to_worker");
3442 if (apr_table_get(r->subprocess_env, "no-jk")) {
3443 if (JK_IS_DEBUG_LEVEL(conf->log))
3444 jk_log(conf->log, JK_LOG_DEBUG,
3445 "Into translate no-jk env var detected for uri=%s, declined",
3451 /* Special case to make sure that apache can serve a directory
3452 listing if there are no matches for the DirectoryIndex and
3453 Tomcat webapps are mapped into apache using JkAutoAlias. */
3454 if (r->main != NULL && r->main->handler != NULL &&
3455 (conf->alias_dir != NULL) &&
3456 !strcmp(r->main->handler, DIR_MAGIC_TYPE)) {
3458 /* Append the request uri to the JkAutoAlias directory and
3459 determine if the file exists. */
3462 finfo.filetype = APR_NOFILE;
3463 clean_uri = apr_pstrdup(r->pool, r->uri);
3464 ap_no2slash(clean_uri);
3465 /* Map uri to a context static file */
3466 if (strlen(clean_uri) > 1) {
3467 char *context_path = NULL;
3469 context_path = apr_pstrcat(r->pool, conf->alias_dir,
3470 ap_os_escape_path(r->pool,
3473 if (context_path != NULL) {
3474 apr_stat(&finfo, context_path, APR_FINFO_TYPE,
3478 if (finfo.filetype != APR_REG) {
3479 if (JK_IS_DEBUG_LEVEL(conf->log))
3480 jk_log(conf->log, JK_LOG_DEBUG,
3481 "JkAutoAlias, no DirectoryIndex file for URI %s",
3486 if (!conf->uw_map) {
3487 if (JK_IS_DEBUG_LEVEL(conf->log))
3488 jk_log(conf->log, JK_LOG_DEBUG,
3489 "missing uri map for %s:%s",
3490 conf->s->server_hostname ? conf->s->server_hostname : "_default_",
3495 rule_extension_t *e;
3496 worker = map_uri_to_worker_ext(conf->uw_map, r->uri,
3497 NULL, &e, NULL, conf->log);
3498 ap_set_module_config(r->request_config, &jk_module, e);
3502 r->handler = apr_pstrdup(r->pool, JK_HANDLER);
3503 apr_table_setn(r->notes, JK_NOTE_WORKER_NAME, worker);
3505 /* This could be a sub-request, possibly from mod_dir */
3506 /* Also add the the HANDLER to the main request */
3508 r->main->handler = apr_pstrdup(r->main->pool, JK_HANDLER);
3509 apr_table_setn(r->main->notes, JK_NOTE_WORKER_NAME, worker);
3514 else if (conf->alias_dir != NULL) {
3515 char *clean_uri = apr_pstrdup(r->pool, r->uri);
3516 ap_no2slash(clean_uri);
3517 /* Automatically map uri to a context static file */
3518 if (JK_IS_DEBUG_LEVEL(conf->log))
3519 jk_log(conf->log, JK_LOG_DEBUG,
3520 "check alias_dir: %s",
3522 if (strlen(clean_uri) > 1) {
3523 /* Get the context directory name */
3524 char *context_dir = NULL;
3525 char *context_path = NULL;
3526 char *child_dir = NULL;
3527 char *index = clean_uri;
3528 char *suffix = strchr(index + 1, '/');
3529 if (suffix != NULL) {
3530 int size = suffix - index;
3531 context_dir = apr_pstrndup(r->pool, index, size);
3532 /* Get the context child directory name */
3533 index = index + size + 1;
3534 suffix = strchr(index, '/');
3535 if (suffix != NULL) {
3536 size = suffix - index;
3537 child_dir = apr_pstrndup(r->pool, index, size);
3542 /* Deny access to WEB-INF and META-INF directories */
3543 if (child_dir != NULL) {
3544 if (JK_IS_DEBUG_LEVEL(conf->log))
3545 jk_log(conf->log, JK_LOG_DEBUG,
3546 "AutoAlias child_dir: %s",
3548 if (!strcasecmp(child_dir, "WEB-INF")
3549 || !strcasecmp(child_dir, "META-INF")) {
3550 if (JK_IS_DEBUG_LEVEL(conf->log))
3551 jk_log(conf->log, JK_LOG_DEBUG,
3552 "AutoAlias HTTP_NOT_FOUND for URI: %s",
3554 return HTTP_NOT_FOUND;
3559 context_dir = apr_pstrdup(r->pool, index);
3562 context_path = apr_pstrcat(r->pool, conf->alias_dir,
3563 ap_os_escape_path(r->pool,
3566 if (context_path != NULL) {
3568 finfo.filetype = APR_NOFILE;
3569 apr_stat(&finfo, context_path, APR_FINFO_TYPE,
3571 if (finfo.filetype == APR_DIR) {
3573 ap_os_escape_path(r->pool, clean_uri, 1);
3575 apr_pstrcat(r->pool, conf->alias_dir, escurl,
3577 /* Add code to verify real path ap_os_canonical_name */
3579 if (JK_IS_DEBUG_LEVEL(conf->log))
3580 jk_log(conf->log, JK_LOG_DEBUG,
3581 "AutoAlias OK for file: %s",
3588 /* Deny access to war files in web app directory */
3589 int size = strlen(context_dir);
3591 && !strcasecmp(context_dir + (size - 4),
3593 if (JK_IS_DEBUG_LEVEL(conf->log))
3594 jk_log(conf->log, JK_LOG_DEBUG,
3595 "AutoAlias HTTP_FORBIDDEN for URI: %s",
3597 return HTTP_FORBIDDEN;
3604 if (JK_IS_DEBUG_LEVEL(conf->log))
3605 jk_log(conf->log, JK_LOG_DEBUG,
3606 "no match for %s found",
3615 /* bypass the directory_walk and file_walk for non-file requests */
3616 static int jk_map_to_storage(request_rec * r)
3619 if (!r->proxyreq && !apr_table_get(r->notes, JK_NOTE_WORKER_NAME)) {
3620 jk_server_conf_t *conf =
3621 (jk_server_conf_t *) ap_get_module_config(r->server->
3627 if ((r->handler != NULL) && (!strcmp(r->handler, JK_HANDLER))) {
3628 /* Somebody already set the handler, probably manual config
3629 * or "native" configuration, no need for extra overhead
3631 if (JK_IS_DEBUG_LEVEL(conf->log))
3632 jk_log(conf->log, JK_LOG_DEBUG,
3633 "Manually mapped, no need to call uri_to_worker");
3637 if (apr_table_get(r->subprocess_env, "no-jk")) {
3638 if (JK_IS_DEBUG_LEVEL(conf->log))
3639 jk_log(conf->log, JK_LOG_DEBUG,
3640 "Into map_to_storage no-jk env var detected for uri=%s, declined",
3645 if (!conf->uw_map) {
3646 if (JK_IS_DEBUG_LEVEL(conf->log))
3647 jk_log(conf->log, JK_LOG_DEBUG,
3648 "missing uri map for %s:%s",
3649 conf->s->server_hostname ? conf->s->server_hostname : "_default_",
3654 rule_extension_t *e;
3655 worker = map_uri_to_worker_ext(conf->uw_map, r->uri,
3656 NULL, &e, NULL, conf->log);
3657 ap_set_module_config(r->request_config, &jk_module, e);
3661 r->handler = apr_pstrdup(r->pool, JK_HANDLER);
3662 apr_table_setn(r->notes, JK_NOTE_WORKER_NAME, worker);
3664 /* This could be a sub-request, possibly from mod_dir */
3666 apr_table_setn(r->main->notes, JK_NOTE_WORKER_NAME, worker);
3670 if (JK_IS_DEBUG_LEVEL(conf->log))
3671 jk_log(conf->log, JK_LOG_DEBUG,
3672 "no match for %s found",
3674 if (conf->strip_session == JK_TRUE &&
3675 conf->strip_session_name) {
3678 jsessionid = strstr(r->uri, conf->strip_session_name);
3680 if (JK_IS_DEBUG_LEVEL(conf->log))
3681 jk_log(conf->log, JK_LOG_DEBUG,
3682 "removing session identifier [%s] for non servlet url [%s]",
3683 jsessionid, r->uri);
3688 jsessionid = strstr(r->filename, conf->strip_session_name);
3698 if (apr_table_get(r->notes, JK_NOTE_WORKER_NAME)) {
3700 /* First find just the name of the file, no directory */
3701 r->filename = (char *)apr_filepath_name_get(r->uri);
3703 /* Only if sub-request for a directory, most likely from mod_dir */
3704 if (r->main && r->main->filename &&
3705 (!apr_filepath_name_get(r->main->filename) ||
3706 !strlen(apr_filepath_name_get(r->main->filename)))) {
3708 /* The filename from the main request will be set to what should
3709 * be picked up, aliases included. Tomcat will need to know about
3710 * those aliases or things won't work for them. Normal files should
3713 /* Need absolute path to stat */
3714 if (apr_filepath_merge(&r->filename,
3715 r->main->filename, r->filename,
3716 APR_FILEPATH_SECUREROOT |
3717 APR_FILEPATH_TRUENAME, r->pool)
3719 return DECLINED; /* We should never get here, very bad */
3722 /* Stat the file so that mod_dir knows it's there */
3723 apr_stat(&r->finfo, r->filename, APR_FINFO_TYPE, r->pool);
3731 static void jk_register_hooks(apr_pool_t * p)
3733 ap_hook_handler(jk_handler, NULL, NULL, APR_HOOK_MIDDLE);
3734 ap_hook_post_config(jk_post_config, NULL, NULL, APR_HOOK_MIDDLE);
3735 ap_hook_child_init(jk_child_init, NULL, NULL, APR_HOOK_MIDDLE);
3736 ap_hook_translate_name(jk_translate, NULL, NULL, APR_HOOK_MIDDLE);
3737 ap_hook_map_to_storage(jk_map_to_storage, NULL, NULL, APR_HOOK_MIDDLE);
3740 module AP_MODULE_DECLARE_DATA jk_module = {
3741 STANDARD20_MODULE_STUFF,
3742 NULL, /* dir config creater */
3743 NULL, /* dir merger --- default is to override */
3744 create_jk_config, /* server config */
3745 merge_jk_config, /* merge server config */
3746 jk_cmds, /* command ap_table_t */
3747 jk_register_hooks /* register hooks */