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 1.3 plugin for Tomcat *
20 * See ../common/jk_service.h for general mod_jk info *
21 * Author: Gal Shachor <shachor@il.ibm.com> *
22 * Dan Milstein <danmil@shore.net> *
23 * Henri Gomez <hgomez@apache.org> *
24 * Version: $Revision: 1126561 $ *
25 ***************************************************************************/
28 * mod_jk: keeps all servlet related ramblings together.
31 /* #include "ap_config.h" */
33 #include "http_config.h"
34 #include "http_request.h"
35 #include "http_core.h"
36 #include "http_protocol.h"
37 #include "http_main.h"
39 #include "util_script.h"
40 #include "util_date.h"
41 #include "http_conf_globals.h"
48 #define _NETDB_H_INCLUDED
51 #define _SYS_TIMEVAL_H_
52 #define _SYS_SOCKET_H_
54 #include "jk_global.h"
58 #include "jk_service.h"
59 #include "jk_worker.h"
60 #include "jk_uri_worker_map.h"
65 #define JK_LOG_DEF_FILE ("logs/mod_jk.log")
66 #define JK_SHM_DEF_FILE ("logs/jk-runtime-status")
67 #define JK_ENV_REMOTE_ADDR ("JK_REMOTE_ADDR")
68 #define JK_ENV_REMOTE_PORT ("JK_REMOTE_PORT")
69 #define JK_ENV_REMOTE_HOST ("JK_REMOTE_HOST")
70 #define JK_ENV_REMOTE_USER ("JK_REMOTE_USER")
71 #define JK_ENV_AUTH_TYPE ("JK_AUTH_TYPE")
72 #define JK_ENV_LOCAL_NAME ("JK_LOCAL_NAME")
73 #define JK_ENV_LOCAL_PORT ("JK_LOCAL_PORT")
74 #define JK_ENV_HTTPS ("HTTPS")
75 #define JK_ENV_CERTS ("SSL_CLIENT_CERT")
76 #define JK_ENV_CIPHER ("SSL_CIPHER")
77 #define JK_ENV_SESSION ("SSL_SESSION_ID")
78 #define JK_ENV_KEY_SIZE ("SSL_CIPHER_USEKEYSIZE")
79 #define JK_ENV_CERTCHAIN_PREFIX ("SSL_CLIENT_CERT_CHAIN_")
80 #define JK_ENV_REPLY_TIMEOUT ("JK_REPLY_TIMEOUT")
81 #define JK_ENV_WORKER_NAME ("JK_WORKER_NAME")
82 #define JK_NOTE_WORKER_NAME ("JK_WORKER_NAME")
83 #define JK_NOTE_WORKER_TYPE ("JK_WORKER_TYPE")
84 #define JK_NOTE_REQUEST_DURATION ("JK_REQUEST_DURATION")
85 #define JK_NOTE_WORKER_ROUTE ("JK_WORKER_ROUTE")
86 #define JK_HANDLER ("jakarta-servlet")
87 #define JK_MAGIC_TYPE ("application/x-jakarta-servlet")
88 #define NULL_FOR_EMPTY(x) ((x && !strlen(x)) ? NULL : x)
89 #define STRNULL_FOR_NULL(x) ((x) ? (x) : "(null)")
92 * If you are not using SSL, comment out the following line. It will make
95 * Personally, I (DM), think this may be a lie.
99 module MODULE_VAR_EXPORT jk_module;
101 extern __declspec(dllimport) module dir_module;
103 extern module dir_module;
106 static int xfer_flags = (O_WRONLY | O_APPEND | O_CREAT);
107 #if defined(OS2) || defined(WIN32) || defined(NETWARE)
108 /* OS/2 dosen't support users and groups */
109 static mode_t xfer_mode = (S_IREAD | S_IWRITE);
111 static mode_t xfer_mode = (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
115 * Environment variable forward object
125 * Configuration object for the mod_jk module.
142 int mount_file_reload;
143 jk_map_t *uri_to_context;
147 jk_uri_worker_map_t *uw_map;
152 * Automatic context path apache alias
160 char *stamp_format_string;
162 array_header *format;
165 * Setting target worker via environment
167 char *worker_indicator;
170 * Configurable environment variables to overwrite
171 * request information using meta data send by a
172 * proxy in front of us.
174 char *remote_addr_indicator;
175 char *remote_port_indicator;
176 char *remote_host_indicator;
177 char *remote_user_indicator;
178 char *auth_type_indicator;
179 char *local_name_indicator;
180 char *local_port_indicator;
186 char *https_indicator;
187 char *certs_indicator;
188 char *cipher_indicator;
189 char *session_indicator;
190 char *key_size_indicator;
191 char *certchain_prefix; /* Client certificate chain prefix */
201 * Environment variables support
206 array_header *envvar_items;
213 * The "private", or subclass portion of the web server service class for
214 * Apache 1.3. An instance of this class is created for each request
215 * handled. See jk_service.h for details about the ws_service object in
218 struct apache_private_data
221 * For memory management for this request. Aliased to be identical to
222 * the pool in the superclass (jk_ws_service).
226 /* True iff request body data has been read from Apache */
227 int read_body_started;
229 /* Apache request structure */
232 typedef struct apache_private_data apache_private_data_t;
234 typedef struct dir_config_struct
236 array_header *index_names;
239 static server_rec *main_server = NULL;
240 static jk_logger_t *main_log = NULL;
241 static table *jk_log_fds = NULL;
242 static jk_worker_env_t worker_env;
243 static char *jk_shm_file = NULL;
244 static size_t jk_shm_size = 0;
248 static jk_map_t *jk_worker_properties = NULL;
249 static char *jk_worker_file = NULL;
250 static int jk_mount_copy_all = JK_FALSE;
252 static int JK_METHOD ws_start_response(jk_ws_service_t *s,
255 const char *const *header_names,
256 const char *const *header_values,
257 unsigned num_of_headers);
259 static int JK_METHOD ws_read(jk_ws_service_t *s,
260 void *b, unsigned l, unsigned *a);
262 static int JK_METHOD ws_write(jk_ws_service_t *s, const void *b, unsigned l);
264 static void JK_METHOD ws_add_log_items(jk_ws_service_t *s,
265 const char *const *log_names,
266 const char *const *log_values,
267 unsigned num_of_log_items);
269 static void * JK_METHOD ws_next_vhost(void *d);
271 static void JK_METHOD ws_vhost_to_text(void *d, char *buf, size_t len);
273 static jk_uri_worker_map_t * JK_METHOD ws_vhost_to_uw_map(void *d);
275 /* srevilak - new function prototypes */
276 static void jk_server_cleanup(void *data);
277 static void jk_generic_cleanup(server_rec * s);
281 /* ====================================================================== */
282 /* JK Service step callbacks */
283 /* ====================================================================== */
287 * Send the HTTP response headers back to the browser.
289 * Think of this function as a method of the apache1.3-specific subclass of
290 * the jk_ws_service class. Think of the *s param as a "this" or "self"
293 static int JK_METHOD ws_start_response(jk_ws_service_t *s,
296 const char *const *header_names,
297 const char *const *header_values,
298 unsigned num_of_headers)
300 if (s && s->ws_private) {
303 /* Obtain a subclass-specific "this" pointer */
304 apache_private_data_t *p = s->ws_private;
305 request_rec *r = p->r;
307 /* If we use proxy error pages, still pass
308 * through context headers needed for special status codes.
310 if (s->extension.use_server_error_pages &&
311 status >= s->extension.use_server_error_pages) {
312 if (status == HTTP_UNAUTHORIZED) {
313 int found = JK_FALSE;
314 for (h = 0; h < num_of_headers; h++) {
315 if (!strcasecmp(header_names[h], "WWW-Authenticate")) {
316 char *tmp = ap_pstrdup(r->pool, header_values[h]);
317 ap_table_set(r->err_headers_out,
318 "WWW-Authenticate", tmp);
322 if (found == JK_FALSE) {
323 jk_server_conf_t *conf = (jk_server_conf_t *)
324 ap_get_module_config(r->server->module_config,
326 jk_log(conf->log, JK_LOG_INFO,
327 "origin server sent 401 without"
328 " WWW-Authenticate header");
338 r->status_line = ap_psprintf(r->pool, "%d %s", status, reason);
340 for (h = 0; h < num_of_headers; h++) {
341 if (!strcasecmp(header_names[h], "Content-type")) {
342 char *tmp = ap_pstrdup(r->pool, header_values[h]);
343 ap_content_type_tolower(tmp);
344 r->content_type = tmp;
346 else if (!strcasecmp(header_names[h], "Location")) {
347 ap_table_set(r->headers_out, header_names[h],
350 else if (!strcasecmp(header_names[h], "Content-Length")) {
351 ap_table_set(r->headers_out, header_names[h],
354 else if (!strcasecmp(header_names[h], "Transfer-Encoding")) {
355 ap_table_set(r->headers_out, header_names[h],
358 else if (!strcasecmp(header_names[h], "Last-Modified")) {
360 * If the script gave us a Last-Modified header, we can't just
361 * pass it on blindly because of restrictions on future values.
363 ap_update_mtime(r, ap_parseHTTPdate(header_values[h]));
364 ap_set_last_modified(r);
367 ap_table_add(r->headers_out, header_names[h],
372 ap_send_http_header(r);
373 s->response_started = JK_TRUE;
381 * Read a chunk of the request body into a buffer. Attempt to read len
382 * bytes into the buffer. Write the number of bytes actually read into
385 * Think of this function as a method of the apache1.3-specific subclass of
386 * the jk_ws_service class. Think of the *s param as a "this" or "self"
389 static int JK_METHOD ws_read(jk_ws_service_t *s,
390 void *b, unsigned len, unsigned *actually_read)
392 if (s && s->ws_private && b && actually_read) {
393 apache_private_data_t *p = s->ws_private;
394 if (!p->read_body_started) {
395 if (ap_should_client_block(p->r)) {
396 p->read_body_started = JK_TRUE;
400 if (p->read_body_started) {
402 if ((rv = ap_get_client_block(p->r, b, len)) < 0) {
406 *actually_read = (unsigned)rv;
408 /* reset timeout after successful read */
409 ap_reset_timeout(p->r);
416 static void JK_METHOD ws_flush(jk_ws_service_t *s)
418 if (s && s->ws_private) {
419 apache_private_data_t *p = s->ws_private;
420 BUFF *bf = p->r->connection->client;
426 * Write a chunk of response data back to the browser. If the headers
427 * haven't yet been sent over, send over default header values (Status =
430 * Write len bytes from buffer b.
432 * Think of this function as a method of the apache1.3-specific subclass of
433 * the jk_ws_service class. Think of the *s param as a "this" or "self"
436 static int JK_METHOD ws_write(jk_ws_service_t *s, const void *b, unsigned len)
438 if (s && s->ws_private && b) {
439 apache_private_data_t *p = s->ws_private;
442 char *buf = (char *)b;
446 if (!s->response_started) {
448 jk_log(main_log, JK_LOG_INFO,
449 "Write without start, starting with defaults");
450 if (!s->start_response(s, 200, NULL, NULL, NULL, 0)) {
455 if (p->r->header_only) {
456 BUFF *bf = p->r->connection->client;
461 while (len && !p->r->connection->aborted) {
462 w = ap_bwrite(p->r->connection->client, &buf[r], len);
464 /* reset timeout after successful write */
465 ap_reset_timeout(p->r);
470 /* Error writing data -- abort */
471 if (!p->r->connection->aborted) {
472 ap_bsetflag(p->r->connection->client, B_EOUT, 1);
473 p->r->connection->aborted = 1;
479 if (len && p->r->connection->aborted) {
480 /* Fail if there is something left to send and
481 * the connection was aborted by the client
492 static void JK_METHOD ws_add_log_items(jk_ws_service_t *s,
493 const char *const *log_names,
494 const char *const *log_values,
495 unsigned num_of_log_items)
498 apache_private_data_t *p = s->ws_private;
499 request_rec *r = p->r;
501 for (h = 0; h < num_of_log_items; h++) {
502 if (log_names[h] && log_values[h]) {
503 ap_table_setn(r->notes, log_names[h], log_values[h]);
508 static void * JK_METHOD ws_next_vhost(void *d)
510 server_rec *s = (server_rec *)d;
516 static void JK_METHOD ws_vhost_to_text(void *d, char *buf, size_t len)
518 server_rec *s = (server_rec *)d;
521 if (s->server_hostname)
522 used += strlen(s->server_hostname);
523 if (!s->is_virtual) {
525 used += strlen(":XXXXX");
528 used += strlen(" [");
529 if (s->addrs->virthost)
530 used += strlen(s->addrs->virthost);
531 if (s->addrs->host_port)
532 used += strlen(":XXXXX");
536 if (len < used && len > strlen("XXX")) {
543 if (s->server_hostname) {
544 strcpy(buf + used, s->server_hostname);
545 used += strlen(s->server_hostname);
547 if (!s->is_virtual) {
549 sprintf(buf + used, ":%hu", s->port);
554 strcpy(buf + used, " [");
555 used += strlen(" [");
556 if (s->addrs->virthost) {
557 strcpy(buf + used, s->addrs->virthost);
558 used += strlen(s->addrs->virthost);
560 if (s->addrs->host_port) {
561 sprintf(buf + used, ":%hu", s->addrs->host_port);
564 strcpy(buf + used, "]");
569 static jk_uri_worker_map_t * JK_METHOD ws_vhost_to_uw_map(void *d)
571 server_rec *s = (server_rec *)d;
572 jk_server_conf_t *conf = NULL;
575 conf = (jk_server_conf_t *) ap_get_module_config(s->module_config,
580 /* ====================================================================== */
581 /* Utility functions */
582 /* ====================================================================== */
584 /* Log something to JK log file then exit */
585 static void jk_error_exit(const char *file,
588 const server_rec * s,
589 ap_pool * p, const char *fmt, ...)
596 res = ap_pvsprintf(p, fmt, ap);
598 /* Replace all format characters in the resulting message */
599 /* because we feed the message to ap_log_error(). */
608 ap_log_error(file, line, level, s, res);
610 ap_log_error(file, line, level, NULL, res);
617 /* Return the content length associated with an Apache request structure */
618 static jk_uint64_t get_content_length(request_rec * r)
620 if (r->clength > 0) {
621 return (jk_uint64_t)r->clength;
624 char *lenp = (char *)ap_table_get(r->headers_in, "Content-Length");
628 if (sscanf(lenp, "%" JK_UINT64_T_FMT, &rc) > 0 && rc > 0) {
637 /* Retrieve string value from env var, use default if env var does not exist. */
638 static const char *get_env_string(request_rec *r, const char *def,
639 char *env, int null_for_empty)
641 char *value = (char *)ap_table_get(r->subprocess_env, env);
643 return null_for_empty ? NULL_FOR_EMPTY(value) : value;
644 return null_for_empty ? NULL_FOR_EMPTY(def) : def;
647 /* Retrieve integer value from env var, use default if env var does not exist. */
648 static int get_env_int(request_rec *r, int def, char *env)
650 char *value = (char *)ap_table_get(r->subprocess_env, env);
657 * Set up an instance of a ws_service object for a single request. This
658 * particular instance will be of the Apache 1.3-specific subclass. Copies
659 * all of the important request information from the Apache request object
660 * into the jk_ws_service_t object.
664 * private_data: The subclass-specific data structure, already initialized
665 * (with a pointer to the Apache request_rec structure, among other things)
667 * s: The base class object.
669 * conf: Configuration information
671 * Called from jk_handler(). See jk_service.h for explanations of what most
672 * of these fields mean.
674 static int init_ws_service(apache_private_data_t * private_data,
675 jk_ws_service_t *s, jk_server_conf_t * conf)
678 request_rec *r = private_data->r;
679 char *ssl_temp = NULL;
680 const char *reply_timeout = NULL;
683 /* Copy in function pointers (which are really methods) */
684 s->start_response = ws_start_response;
688 s->add_log_items = ws_add_log_items;
689 s->next_vhost = ws_next_vhost;
690 s->vhost_to_text = ws_vhost_to_text;
691 s->vhost_to_uw_map = ws_vhost_to_uw_map;
693 s->auth_type = get_env_string(r, r->connection->ap_auth_type,
694 conf->auth_type_indicator, 1);
695 s->remote_user = get_env_string(r, r->connection->user,
696 conf->remote_user_indicator, 1);
698 s->protocol = r->protocol;
700 (char *)ap_get_remote_host(r->connection, r->per_dir_config,
702 s->remote_host = get_env_string(r, s->remote_host,
703 conf->remote_host_indicator, 1);
705 if (conf->options & JK_OPT_FWDLOCAL) {
706 s->remote_addr = r->connection->local_ip;
707 /* We don't know the client port of the backend connection. */
708 s->remote_port = "0";
711 s->remote_addr = r->connection->remote_ip;
712 s->remote_port = ap_psprintf(r->pool, "%d",
713 ntohs(r->connection->remote_addr.sin_port));
715 s->remote_addr = get_env_string(r, s->remote_addr,
716 conf->remote_addr_indicator, 1);
717 s->remote_port = get_env_string(r, s->remote_port,
718 conf->remote_port_indicator, 1);
720 if (conf->options & JK_OPT_FLUSHPACKETS)
721 s->flush_packets = 1;
722 if (conf->options & JK_OPT_FLUSHEADER)
725 e = (rule_extension_t *)ap_get_module_config(r->request_config, &jk_module);
727 s->extension.reply_timeout = e->reply_timeout;
728 s->extension.use_server_error_pages = e->use_server_error_pages;
730 s->extension.activation = ap_palloc(r->pool, e->activation_size * sizeof(int));
731 memcpy(s->extension.activation, e->activation, e->activation_size * sizeof(int));
733 if (e->fail_on_status_size > 0) {
734 s->extension.fail_on_status_size = e->fail_on_status_size;
735 s->extension.fail_on_status = ap_palloc(r->pool, e->fail_on_status_size * sizeof(int));
736 memcpy(s->extension.fail_on_status, e->fail_on_status, e->fail_on_status_size * sizeof(int));
739 reply_timeout = ap_table_get(r->subprocess_env, "JK_REPLY_TIMEOUT");
741 int r = atoi(reply_timeout);
743 s->extension.reply_timeout = r;
746 if (conf->options & JK_OPT_DISABLEREUSE)
747 s->disable_reuse = 1;
749 /* get server name */
750 /* s->server_name = (char *)(r->hostname ? r->hostname : r->server->server_hostname); */
752 s->server_name = get_env_string(r, (char *)ap_get_server_name(r),
753 conf->local_name_indicator, 0);
755 /* get the real port (otherwise redirect failed) */
756 /* s->server_port = htons( r->connection->local_addr.sin_port ); */
758 s->server_port = get_env_int(r, ap_get_server_port(r),
759 conf->local_port_indicator);
761 s->server_software = (char *)ap_get_server_version();
763 s->method = (char *)r->method;
764 s->content_length = get_content_length(r);
765 s->is_chunked = r->read_chunked;
766 s->no_more_chunks = 0;
767 s->query_string = r->args;
770 * The 2.2 servlet spec errata says the uri from
771 * HttpServletRequest.getRequestURI() should remain encoded.
772 * [http://java.sun.com/products/servlet/errata_042700.html]
774 * We use JkOptions to determine which method to be used
776 * ap_escape_uri is the latest recommanded but require
777 * some java decoding (in TC 3.3 rc2)
779 * unparsed_uri is used for strict compliance with spec and
780 * old Tomcat (3.2.3 for example)
782 * uri is use for compatibilty with mod_rewrite with old Tomcats
785 switch (conf->options & JK_OPT_FWDURIMASK) {
787 case JK_OPT_FWDURICOMPATUNPARSED:
788 s->req_uri = r->unparsed_uri;
789 if (s->req_uri != NULL) {
790 char *query_str = strchr(s->req_uri, '?');
791 if (query_str != NULL) {
798 case JK_OPT_FWDURICOMPAT:
802 case JK_OPT_FWDURIPROXY:
803 size = 3 * strlen(r->uri) + 1;
804 s->req_uri = ap_palloc(r->pool, size);
805 jk_canonenc(r->uri, s->req_uri, size);
808 case JK_OPT_FWDURIESCAPED:
809 s->req_uri = ap_escape_uri(r->pool, r->uri);
816 if (conf->ssl_enable || conf->envvars) {
817 ap_add_common_vars(r);
819 if (conf->ssl_enable) {
821 (char *)ap_table_get(r->subprocess_env,
822 conf->https_indicator);
823 if (ssl_temp && !strcasecmp(ssl_temp, "on")) {
826 (char *)ap_table_get(r->subprocess_env,
827 conf->certs_indicator);
829 if (conf->options & JK_OPT_FWDCERTCHAIN) {
830 array_header *t = ap_table_elts(r->subprocess_env);
833 table_entry *elts = (table_entry *) t->elts;
834 array_header *certs = ap_make_array(r->pool, 1,
836 *(const char **)ap_push_array(certs) = s->ssl_cert;
837 for (i = 0; i < t->nelts; i++) {
840 if (!strncasecmp(elts[i].key,
841 conf->certchain_prefix,
842 strlen(conf->certchain_prefix)))
843 *(const char **)ap_push_array(certs) = elts[i].val;
845 s->ssl_cert = ap_array_pstrcat(r->pool, certs, '\0');
850 s->ssl_cert_len = strlen(s->ssl_cert);
851 if (JK_IS_DEBUG_LEVEL(conf->log)) {
852 jk_log(conf->log, JK_LOG_DEBUG,
853 "SSL client certificate (%d bytes): %s",
854 s->ssl_cert_len, s->ssl_cert);
857 /* Servlet 2.3 API */
859 (char *)ap_table_get(r->subprocess_env,
860 conf->cipher_indicator);
862 (char *)ap_table_get(r->subprocess_env,
863 conf->session_indicator);
865 if (conf->options & JK_OPT_FWDKEYSIZE) {
866 /* Servlet 2.3 API */
868 (char *)ap_table_get(r->subprocess_env,
869 conf->key_size_indicator);
871 s->ssl_key_size = atoi(ssl_temp);
877 const array_header *t = conf->envvar_items;
881 envvar_item *elts = (envvar_item *) t->elts;
882 s->attributes_names =
883 ap_palloc(r->pool, sizeof(char *) * t->nelts);
884 s->attributes_values =
885 ap_palloc(r->pool, sizeof(char *) * t->nelts);
887 for (i = 0; i < t->nelts; i++) {
888 s->attributes_names[i - j] = elts[i].name;
889 s->attributes_values[i - j] =
890 (char *)ap_table_get(r->subprocess_env, elts[i].name);
891 if (!s->attributes_values[i - j]) {
892 if (elts[i].has_default) {
893 s->attributes_values[i - j] = elts[i].value;
896 s->attributes_values[i - j] = "";
897 s->attributes_names[i - j] = "";
903 s->num_attributes = t->nelts - j;
908 if (r->headers_in && ap_table_elts(r->headers_in)) {
909 int need_content_length_header = (!s->is_chunked
910 && s->content_length ==
911 0) ? JK_TRUE : JK_FALSE;
912 array_header *t = ap_table_elts(r->headers_in);
915 table_entry *elts = (table_entry *) t->elts;
916 s->num_headers = t->nelts;
917 /* allocate an extra header slot in case we need to add a content-length header */
919 ap_palloc(r->pool, sizeof(char *) * (t->nelts + 1));
921 ap_palloc(r->pool, sizeof(char *) * (t->nelts + 1));
922 if (!s->headers_names || !s->headers_values)
924 for (i = 0; i < t->nelts; i++) {
925 char *hname = ap_pstrdup(r->pool, elts[i].key);
926 s->headers_values[i] = ap_pstrdup(r->pool, elts[i].val);
927 s->headers_names[i] = hname;
928 if (need_content_length_header &&
929 !strcasecmp(s->headers_names[i], "content-length")) {
930 need_content_length_header = JK_FALSE;
933 /* Add a content-length = 0 header if needed.
934 * Ajp13 assumes an absent content-length header means an unknown,
935 * but non-zero length body.
937 if (need_content_length_header) {
938 s->headers_names[s->num_headers] = "content-length";
939 s->headers_values[s->num_headers] = "0";
943 /* Add a content-length = 0 header if needed. */
944 else if (need_content_length_header) {
945 s->headers_names = ap_palloc(r->pool, sizeof(char *));
946 s->headers_values = ap_palloc(r->pool, sizeof(char *));
947 if (!s->headers_names || !s->headers_values)
949 s->headers_names[0] = "content-length";
950 s->headers_values[0] = "0";
954 s->uw_map = conf->uw_map;
956 /* Dump all connection param so we can trace what's going to
959 if (JK_IS_DEBUG_LEVEL(conf->log)) {
960 jk_log(conf->log, JK_LOG_DEBUG,
961 "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",
962 STRNULL_FOR_NULL(s->protocol),
963 STRNULL_FOR_NULL(s->method),
964 s->is_ssl ? "true" : "false",
965 STRNULL_FOR_NULL(s->remote_host),
966 STRNULL_FOR_NULL(s->remote_addr),
967 STRNULL_FOR_NULL(s->server_name),
969 STRNULL_FOR_NULL(s->auth_type),
970 STRNULL_FOR_NULL(s->remote_user),
971 STRNULL_FOR_NULL(r->connection->local_ip),
972 STRNULL_FOR_NULL(r->connection->remote_ip),
973 STRNULL_FOR_NULL(s->req_uri));
980 * The JK module command processors
982 * The below are all installed so that Apache calls them while it is
983 * processing its config files. This allows configuration info to be
984 * copied into a jk_server_conf_t object, which is then used for request
985 * filtering/processing.
987 * See jk_cmds definition below for explanations of these options.
991 * JkMountCopy directive handling
993 * JkMountCopy On/Off/All
996 static const char *jk_set_mountcopy(cmd_parms * cmd,
997 void *dummy, char *mount_copy)
999 server_rec *s = cmd->server;
1000 jk_server_conf_t *conf =
1001 (jk_server_conf_t *) ap_get_module_config(s->module_config,
1003 if (! strcasecmp(mount_copy, "all")) {
1004 jk_mount_copy_all = JK_TRUE;
1006 else if (strcasecmp(mount_copy, "on") && strcasecmp(mount_copy, "off")) {
1007 return "JkMountCopy must be All, On or Off";
1010 conf->mountcopy = strcasecmp(mount_copy, "off") ? JK_TRUE : JK_FALSE;
1017 * JkMount directive handling
1019 * JkMount URI(context) worker
1022 static const char *jk_mount_context(cmd_parms * cmd,
1027 server_rec *s = cmd->server;
1028 jk_server_conf_t *conf =
1029 (jk_server_conf_t *) ap_get_module_config(s->module_config,
1033 if (worker != NULL && cmd->path == NULL ) {
1037 else if (worker == NULL && cmd->path != NULL) {
1043 return "JkMount needs a path when not defined in a location";
1045 return "JkMount can not have a path when defined in a location";
1049 return "JkMount context should start with /";
1051 if (!conf->uri_to_context) {
1052 if (!jk_map_alloc(&(conf->uri_to_context))) {
1053 return "JkMount Memory error";
1057 * Add the new worker to the alias map.
1059 jk_map_put(conf->uri_to_context, c, w, NULL);
1064 * JkUnMount directive handling
1066 * JkUnMount URI(context) worker
1069 static const char *jk_unmount_context(cmd_parms * cmd,
1071 const char *context,
1074 server_rec *s = cmd->server;
1075 jk_server_conf_t *conf =
1076 (jk_server_conf_t *) ap_get_module_config(s->module_config,
1081 if (worker != NULL && cmd->path == NULL ) {
1085 else if (worker == NULL && cmd->path != NULL) {
1091 return "JkUnMount needs a path when not defined in a location";
1093 return "JkUnMount can not have a path when defined in a location";
1096 return "JkUnMount context should start with /";
1097 uri = ap_pstrcat(cmd->temp_pool, "!", c, NULL);
1099 if (!conf->uri_to_context) {
1100 if (!jk_map_alloc(&(conf->uri_to_context))) {
1101 return "JkUnMount Memory error";
1105 * Add the new worker to the alias map.
1107 jk_map_put(conf->uri_to_context, uri, w, NULL);
1112 * JkWorkersFile Directive Handling
1114 * JkWorkersFile file
1117 static const char *jk_set_worker_file(cmd_parms * cmd,
1118 void *dummy, char *worker_file)
1120 struct stat statbuf;
1122 if (jk_worker_file != NULL)
1123 return "JkWorkersFile only allowed once";
1125 /* we need an absolute path */
1126 jk_worker_file = ap_server_root_relative(cmd->pool, worker_file);
1128 #ifdef CHROOTED_APACHE
1129 ap_server_strip_chroot(jk_worker_file, 0);
1132 if (jk_worker_file == worker_file)
1133 jk_worker_file = ap_pstrdup(cmd->pool, worker_file);
1135 if (jk_worker_file == NULL)
1136 return "JkWorkersFile file name invalid";
1138 if (stat(jk_worker_file, &statbuf) == -1)
1139 return "JkWorkersFile: Can't find the workers file specified";
1145 * JkMountFile Directive Handling
1150 static const char *jk_set_mount_file(cmd_parms * cmd,
1151 void *dummy, char *mount_file)
1153 server_rec *s = cmd->server;
1154 struct stat statbuf;
1156 jk_server_conf_t *conf =
1157 (jk_server_conf_t *) ap_get_module_config(s->module_config,
1160 /* we need an absolute path (ap_server_root_relative does the ap_pstrdup) */
1161 conf->mount_file = ap_server_root_relative(cmd->pool, mount_file);
1163 #ifdef CHROOTED_APACHE
1164 ap_server_strip_chroot(conf->mount_file, 0);
1167 if (conf->mount_file == NULL)
1168 return "JkMountFile file name invalid";
1170 if (stat(conf->mount_file, &statbuf) == -1)
1171 return "JkMountFile: Can't find the mount file specified";
1173 if (!conf->uri_to_context) {
1174 if (!jk_map_alloc(&(conf->uri_to_context))) {
1175 return "JkMountFile Memory error";
1183 * JkMountFileReload Directive Handling
1185 * JkMountFileReload seconds
1188 static const char *jk_set_mount_file_reload(cmd_parms * cmd,
1189 void *dummy, char *mount_file_reload)
1191 server_rec *s = cmd->server;
1194 jk_server_conf_t *conf =
1195 (jk_server_conf_t *) ap_get_module_config(s->module_config,
1198 interval = atoi(mount_file_reload);
1203 conf->mount_file_reload = interval;
1209 * JkLogFile Directive Handling
1214 static const char *jk_set_log_file(cmd_parms * cmd,
1215 void *dummy, char *log_file)
1217 server_rec *s = cmd->server;
1218 jk_server_conf_t *conf =
1219 (jk_server_conf_t *) ap_get_module_config(s->module_config,
1222 /* we need an absolute path */
1223 if (*log_file != '|') {
1224 conf->log_file = ap_server_root_relative(cmd->pool, log_file);
1226 #ifdef CHROOTED_APACHE
1227 ap_server_strip_chroot(conf->log_file, 0);
1232 conf->log_file = ap_pstrdup(cmd->pool, log_file);
1234 if (conf->log_file == NULL)
1235 return "JkLogFile file name invalid";
1241 * JkShmFile Directive Handling
1246 static const char *jk_set_shm_file(cmd_parms * cmd,
1247 void *dummy, char *shm_file)
1250 /* we need an absolute path */
1251 jk_shm_file = ap_server_root_relative(cmd->pool, shm_file);
1253 #ifdef CHROOTED_APACHE
1254 ap_server_strip_chroot(jk_shm_file, 0);
1257 if (jk_shm_file == shm_file)
1258 jk_shm_file = ap_pstrdup(cmd->pool, shm_file);
1260 if (jk_shm_file == NULL)
1261 return "JkShmFile file name invalid";
1267 * JkShmSize Directive Handling
1269 * JkShmSize size in kilobytes
1272 static const char *jk_set_shm_size(cmd_parms * cmd,
1273 void *dummy, const char *shm_size)
1276 /* we need an absolute path */
1277 sz = atoi(shm_size) * 1024;
1278 if (sz < JK_SHM_DEF_SIZE)
1279 sz = JK_SHM_DEF_SIZE;
1281 sz = JK_SHM_ALIGN(sz);
1282 jk_shm_size = (size_t)sz;
1287 * JkLogLevel Directive Handling
1289 * JkLogLevel debug/info/request/error/emerg
1292 static const char *jk_set_log_level(cmd_parms * cmd,
1293 void *dummy, char *log_level)
1295 server_rec *s = cmd->server;
1296 jk_server_conf_t *conf =
1297 (jk_server_conf_t *) ap_get_module_config(s->module_config,
1300 conf->log_level = jk_parse_log_level(log_level);
1306 * JkLogStampFormat Directive Handling
1308 * JkLogStampFormat "[%a %b %d %H:%M:%S %Y] "
1311 static const char *jk_set_log_fmt(cmd_parms * cmd,
1312 void *dummy, char *log_format)
1314 server_rec *s = cmd->server;
1315 jk_server_conf_t *conf =
1316 (jk_server_conf_t *) ap_get_module_config(s->module_config,
1319 conf->stamp_format_string = ap_pstrdup(cmd->pool, log_format);
1325 * JkAutoAlias Directive Handling
1327 * JkAutoAlias application directory
1330 static const char *jk_set_auto_alias(cmd_parms * cmd,
1331 void *dummy, char *directory)
1333 server_rec *s = cmd->server;
1334 jk_server_conf_t *conf =
1335 (jk_server_conf_t *) ap_get_module_config(s->module_config,
1338 conf->alias_dir = directory;
1340 if (conf->alias_dir == NULL)
1341 return "JkAutoAlias directory invalid";
1347 * JkStripSession directive handling
1349 * JkStripSession On/Off
1352 static const char *jk_set_strip_session(cmd_parms * cmd, void *dummy, int flag)
1354 server_rec *s = cmd->server;
1355 jk_server_conf_t *conf =
1356 (jk_server_conf_t *) ap_get_module_config(s->module_config,
1359 /* Set up our value */
1360 conf->strip_session = flag ? JK_TRUE : JK_FALSE;
1365 /*****************************************************************
1370 typedef const char *(*item_key_func) (request_rec *, char *);
1376 } request_log_format_item;
1378 static const char *process_item(request_rec * r,
1379 request_log_format_item * item)
1383 cp = (*item->func) (r, item->arg);
1384 return cp ? cp : "-";
1387 static void request_log_transaction(request_rec * r, jk_server_conf_t * conf)
1389 request_log_format_item *items;
1395 array_header *format = conf->format;
1397 strs = ap_palloc(r->pool, sizeof(char *) * (format->nelts));
1398 strl = ap_palloc(r->pool, sizeof(int) * (format->nelts));
1399 items = (request_log_format_item *) format->elts;
1400 for (i = 0; i < format->nelts; ++i) {
1401 strs[i] = process_item(r, &items[i]);
1403 for (i = 0; i < format->nelts; ++i) {
1404 len += strl[i] = strlen(strs[i]);
1406 str = ap_palloc(r->pool, len + 1);
1407 for (i = 0, s = str; i < format->nelts; ++i) {
1408 memcpy(s, strs[i], strl[i]);
1412 jk_log(conf->log, JK_LOG_REQUEST, "%s", str);
1415 /*****************************************************************
1417 * Parsing the log format string
1420 static char *format_integer(pool * p, int i)
1422 return ap_psprintf(p, "%d", i);
1425 static char *pfmt(pool * p, int i)
1431 return format_integer(p, i);
1435 static const char *constant_item(request_rec * dummy, char *stuff)
1440 static const char *log_worker_name(request_rec * r, char *a)
1442 return ap_table_get(r->notes, JK_NOTE_WORKER_NAME);
1445 static const char *log_worker_route(request_rec * r, char *a)
1447 return ap_table_get(r->notes, JK_NOTE_WORKER_ROUTE);
1450 static const char *log_request_duration(request_rec * r, char *a)
1452 return ap_table_get(r->notes, JK_NOTE_REQUEST_DURATION);
1455 static const char *log_request_line(request_rec * r, char *a)
1457 /* NOTE: If the original request contained a password, we
1458 * re-write the request line here to contain XXXXXX instead:
1459 * (note the truncation before the protocol string for HTTP/0.9 requests)
1460 * (note also that r->the_request contains the unmodified request)
1462 return (r->parsed_uri.password) ? ap_pstrcat(r->pool, r->method, " ",
1463 ap_unparse_uri_components(r->
1468 r->assbackwards ? NULL : " ",
1473 /* These next two routines use the canonical name:port so that log
1474 * parsers don't need to duplicate all the vhost parsing crud.
1476 static const char *log_virtual_host(request_rec * r, char *a)
1478 return r->server->server_hostname;
1481 static const char *log_server_port(request_rec * r, char *a)
1483 return ap_psprintf(r->pool, "%u",
1484 r->server->port ? r->server->
1485 port : ap_default_port(r));
1488 /* This respects the setting of UseCanonicalName so that
1489 * the dynamic mass virtual hosting trick works better.
1491 static const char *log_server_name(request_rec * r, char *a)
1493 return ap_get_server_name(r);
1496 static const char *log_request_uri(request_rec * r, char *a)
1500 static const char *log_request_method(request_rec * r, char *a)
1505 static const char *log_request_protocol(request_rec * r, char *a)
1509 static const char *log_request_query(request_rec * r, char *a)
1511 return (r->args != NULL) ? ap_pstrcat(r->pool, "?", r->args, NULL)
1514 static const char *log_status(request_rec * r, char *a)
1516 return pfmt(r->pool, r->status);
1519 static const char *clf_log_bytes_sent(request_rec * r, char *a)
1521 if (!r->sent_bodyct) {
1526 ap_bgetopt(r->connection->client, BO_BYTECT, &bs);
1527 return ap_psprintf(r->pool, "%ld", bs);
1531 static const char *log_bytes_sent(request_rec * r, char *a)
1533 if (!r->sent_bodyct) {
1538 ap_bgetopt(r->connection->client, BO_BYTECT, &bs);
1539 return ap_psprintf(r->pool, "%ld", bs);
1543 static struct log_item_list
1547 } log_item_keys[] = {
1550 'T', log_request_duration}, {
1551 'r', log_request_line}, {
1552 'U', log_request_uri}, {
1554 'b', clf_log_bytes_sent}, {
1555 'B', log_bytes_sent}, {
1556 'V', log_server_name}, {
1557 'v', log_virtual_host}, {
1558 'p', log_server_port}, {
1559 'H', log_request_protocol}, {
1560 'm', log_request_method}, {
1561 'q', log_request_query}, {
1562 'w', log_worker_name}, {
1563 'R', log_worker_route}, {
1567 static struct log_item_list *find_log_func(char k)
1571 for (i = 0; log_item_keys[i].ch; ++i)
1572 if (k == log_item_keys[i].ch) {
1573 return &log_item_keys[i];
1579 static char *parse_request_log_misc_string(pool * p,
1580 request_log_format_item * it,
1586 it->func = constant_item;
1589 while (*s && *s != '%') {
1593 * This might allocate a few chars extra if there's a backslash
1594 * escape in the format string.
1596 it->arg = ap_palloc(p, s - *sa + 1);
1600 while (*s && *s != '%') {
1623 * Allow the loop to deal with this *s in the normal
1624 * fashion so that it handles end of string etc.
1637 static char *parse_request_log_item(pool * p,
1638 request_log_format_item * it,
1641 const char *s = *sa;
1642 struct log_item_list *l;
1645 return parse_request_log_misc_string(p, it, sa);
1649 it->arg = ""; /* For safety's sake... */
1651 l = find_log_func(*s++);
1657 return ap_pstrcat(p, "Unrecognized JkRequestLogFormat directive %",
1665 static array_header *parse_request_log_string(pool * p, const char *s,
1668 array_header *a = ap_make_array(p, 0, sizeof(request_log_format_item));
1673 parse_request_log_item(p,
1674 (request_log_format_item *)
1675 ap_push_array(a), &s))) {
1685 * JkRequestLogFormat Directive Handling
1687 * JkRequestLogFormat format string
1689 * %b - Bytes sent, excluding HTTP headers. In CLF format
1690 * %B - Bytes sent, excluding HTTP headers.
1691 * %H - The request protocol
1692 * %m - The request method
1693 * %p - The canonical Port of the server serving the request
1694 * %q - The query string (prepended with a ? if a query string exists,
1695 * otherwise an empty string)
1696 * %r - First line of request
1697 * %s - request HTTP status code
1698 * %T - Requset duration, elapsed time to handle request in seconds '.' micro seconds
1699 * %U - The URL path requested, not including any query string.
1700 * %v - The canonical ServerName of the server serving the request.
1701 * %V - The server name according to the UseCanonicalName setting.
1702 * %w - Tomcat worker name
1705 static const char *jk_set_request_log_format(cmd_parms * cmd,
1706 void *dummy, char *format)
1708 server_rec *s = cmd->server;
1709 jk_server_conf_t *conf =
1710 (jk_server_conf_t *) ap_get_module_config(s->module_config,
1713 conf->format_string = ap_pstrdup(cmd->pool, format);
1719 * JkWorkerIndicator Directive Handling
1721 * JkWorkerIndicator JkWorker
1724 static const char *jk_set_worker_indicator(cmd_parms * cmd,
1725 void *dummy, char *indicator)
1727 server_rec *s = cmd->server;
1728 jk_server_conf_t *conf =
1729 (jk_server_conf_t *) ap_get_module_config(s->module_config,
1732 conf->worker_indicator = ap_pstrdup(cmd->pool, indicator);
1738 * Directives Handling for setting various environment names
1739 * used to overwrite the following request information:
1748 static const char *jk_set_remote_addr_indicator(cmd_parms * cmd,
1749 void *dummy, char *indicator)
1751 server_rec *s = cmd->server;
1752 jk_server_conf_t *conf =
1753 (jk_server_conf_t *) ap_get_module_config(s->module_config, &jk_module);
1754 conf->remote_addr_indicator = ap_pstrdup(cmd->pool, indicator);
1758 static const char *jk_set_remote_port_indicator(cmd_parms * cmd,
1759 void *dummy, char *indicator)
1761 server_rec *s = cmd->server;
1762 jk_server_conf_t *conf =
1763 (jk_server_conf_t *) ap_get_module_config(s->module_config, &jk_module);
1764 conf->remote_port_indicator = ap_pstrdup(cmd->pool, indicator);
1768 static const char *jk_set_remote_host_indicator(cmd_parms * cmd,
1769 void *dummy, char *indicator)
1771 server_rec *s = cmd->server;
1772 jk_server_conf_t *conf =
1773 (jk_server_conf_t *) ap_get_module_config(s->module_config, &jk_module);
1774 conf->remote_host_indicator = ap_pstrdup(cmd->pool, indicator);
1778 static const char *jk_set_remote_user_indicator(cmd_parms * cmd,
1779 void *dummy, char *indicator)
1781 server_rec *s = cmd->server;
1782 jk_server_conf_t *conf =
1783 (jk_server_conf_t *) ap_get_module_config(s->module_config, &jk_module);
1784 conf->remote_user_indicator = ap_pstrdup(cmd->pool, indicator);
1788 static const char *jk_set_auth_type_indicator(cmd_parms * cmd,
1789 void *dummy, char *indicator)
1791 server_rec *s = cmd->server;
1792 jk_server_conf_t *conf =
1793 (jk_server_conf_t *) ap_get_module_config(s->module_config, &jk_module);
1794 conf->auth_type_indicator = ap_pstrdup(cmd->pool, indicator);
1798 static const char *jk_set_local_name_indicator(cmd_parms * cmd,
1799 void *dummy, char *indicator)
1801 server_rec *s = cmd->server;
1802 jk_server_conf_t *conf =
1803 (jk_server_conf_t *) ap_get_module_config(s->module_config, &jk_module);
1804 conf->local_name_indicator = ap_pstrdup(cmd->pool, indicator);
1808 static const char *jk_set_local_port_indicator(cmd_parms * cmd,
1809 void *dummy, char *indicator)
1811 server_rec *s = cmd->server;
1812 jk_server_conf_t *conf =
1813 (jk_server_conf_t *) ap_get_module_config(s->module_config, &jk_module);
1814 conf->local_port_indicator = ap_pstrdup(cmd->pool, indicator);
1819 * JkExtractSSL Directive Handling
1821 * JkExtractSSL On/Off
1824 static const char *jk_set_enable_ssl(cmd_parms * cmd, void *dummy, int flag)
1826 server_rec *s = cmd->server;
1827 jk_server_conf_t *conf =
1828 (jk_server_conf_t *) ap_get_module_config(s->module_config,
1831 /* Set up our value */
1832 conf->ssl_enable = flag ? JK_TRUE : JK_FALSE;
1837 * JkHTTPSIndicator Directive Handling
1839 * JkHTTPSIndicator HTTPS
1842 static const char *jk_set_https_indicator(cmd_parms * cmd,
1843 void *dummy, char *indicator)
1845 server_rec *s = cmd->server;
1846 jk_server_conf_t *conf =
1847 (jk_server_conf_t *) ap_get_module_config(s->module_config,
1850 conf->https_indicator = ap_pstrdup(cmd->pool, indicator);
1855 * JkCERTSIndicator Directive Handling
1857 * JkCERTSIndicator SSL_CLIENT_CERT
1860 static const char *jk_set_certs_indicator(cmd_parms * cmd,
1861 void *dummy, char *indicator)
1863 server_rec *s = cmd->server;
1864 jk_server_conf_t *conf =
1865 (jk_server_conf_t *) ap_get_module_config(s->module_config,
1868 conf->certs_indicator = ap_pstrdup(cmd->pool, indicator);
1873 * JkCIPHERIndicator Directive Handling
1875 * JkCIPHERIndicator SSL_CIPHER
1878 static const char *jk_set_cipher_indicator(cmd_parms * cmd,
1879 void *dummy, char *indicator)
1881 server_rec *s = cmd->server;
1882 jk_server_conf_t *conf =
1883 (jk_server_conf_t *) ap_get_module_config(s->module_config,
1886 conf->cipher_indicator = ap_pstrdup(cmd->pool, indicator);
1891 * JkCERTCHAINPrefix Directive Handling
1893 * JkCERTCHAINPrefix SSL_CLIENT_CERT_CHAIN_
1896 static const char *jk_set_certchain_prefix(cmd_parms * cmd,
1897 void *dummy, const char *prefix)
1899 server_rec *s = cmd->server;
1900 jk_server_conf_t *conf =
1901 (jk_server_conf_t *) ap_get_module_config(s->module_config,
1904 conf->certchain_prefix = ap_pstrdup(cmd->pool, prefix);
1910 * JkSESSIONIndicator Directive Handling
1912 * JkSESSIONIndicator SSL_SESSION_ID
1915 static const char *jk_set_session_indicator(cmd_parms * cmd,
1916 void *dummy, char *indicator)
1918 server_rec *s = cmd->server;
1919 jk_server_conf_t *conf =
1920 (jk_server_conf_t *) ap_get_module_config(s->module_config,
1923 conf->session_indicator = ap_pstrdup(cmd->pool, indicator);
1928 * JkKEYSIZEIndicator Directive Handling
1930 * JkKEYSIZEIndicator SSL_CIPHER_USEKEYSIZE
1933 static const char *jk_set_key_size_indicator(cmd_parms * cmd,
1934 void *dummy, char *indicator)
1936 server_rec *s = cmd->server;
1937 jk_server_conf_t *conf =
1938 (jk_server_conf_t *) ap_get_module_config(s->module_config,
1941 conf->key_size_indicator = ap_pstrdup(cmd->pool, indicator);
1946 * JkOptions Directive Handling
1949 * +ForwardSSLKeySize => Forward SSL Key Size, to follow 2.3 specs but may broke old TC 3.2
1950 * -ForwardSSLKeySize => Don't Forward SSL Key Size, will make mod_jk works with all TC release
1951 * ForwardURICompat => Forward URI normally, less spec compliant but mod_rewrite compatible (old TC)
1952 * ForwardURICompatUnparsed => Forward URI as unparsed, spec compliant but broke mod_rewrite (old TC)
1953 * ForwardURIEscaped => Forward URI escaped and Tomcat (3.3 rc2) stuff will do the decoding part
1954 * ForwardDirectories => Forward all directory requests with no index files to Tomcat
1955 * +ForwardSSLCertChain => Forward SSL certificate chain
1956 * -ForwardSSLCertChain => Don't forward SSL certificate chain
1959 const char *jk_set_options(cmd_parms * cmd, void *dummy, const char *line)
1966 server_rec *s = cmd->server;
1967 jk_server_conf_t *conf =
1968 (jk_server_conf_t *) ap_get_module_config(s->module_config,
1971 while (line[0] != 0) {
1972 w = ap_getword_conf(cmd->pool, &line);
1975 if (*w == '+' || *w == '-') {
1981 if (action == '-' && !strncasecmp(w, "ForwardURI", strlen("ForwardURI")))
1982 return ap_pstrcat(cmd->pool, "JkOptions: Illegal option '-", w,
1983 "': ForwardURI* options can not be disabled", NULL);
1985 if (!strcasecmp(w, "ForwardURICompat")) {
1986 opt = JK_OPT_FWDURICOMPAT;
1987 mask = JK_OPT_FWDURIMASK;
1989 else if (!strcasecmp(w, "ForwardURICompatUnparsed")) {
1990 opt = JK_OPT_FWDURICOMPATUNPARSED;
1991 mask = JK_OPT_FWDURIMASK;
1993 else if (!strcasecmp(w, "ForwardURIEscaped")) {
1994 opt = JK_OPT_FWDURIESCAPED;
1995 mask = JK_OPT_FWDURIMASK;
1997 else if (!strcasecmp(w, "ForwardURIProxy")) {
1998 opt = JK_OPT_FWDURIPROXY;
1999 mask = JK_OPT_FWDURIMASK;
2001 else if (!strcasecmp(w, "ForwardDirectories")) {
2002 opt = JK_OPT_FWDDIRS;
2004 else if (!strcasecmp(w, "ForwardLocalAddress")) {
2005 opt = JK_OPT_FWDLOCAL;
2007 else if (!strcasecmp(w, "FlushPackets")) {
2008 opt = JK_OPT_FLUSHPACKETS;
2010 else if (!strcasecmp(w, "FlushHeader")) {
2011 opt = JK_OPT_FLUSHEADER;
2013 else if (!strcasecmp(w, "DisableReuse")) {
2014 opt = JK_OPT_DISABLEREUSE;
2016 else if (!strcasecmp(w, "ForwardSSLCertChain")) {
2017 opt = JK_OPT_FWDCERTCHAIN;
2019 else if (!strcasecmp(w, "ForwardKeySize")) {
2020 opt = JK_OPT_FWDKEYSIZE;
2022 else if (!strcasecmp(w, "RejectUnsafeURI")) {
2023 opt = JK_OPT_REJECTUNSAFE;
2026 return ap_pstrcat(cmd->pool, "JkOptions: Illegal option '", w,
2029 conf->options &= ~mask;
2031 if (action == '-') {
2032 conf->exclude_options |= opt;
2034 else if (action == '+') {
2035 conf->options |= opt;
2037 else { /* for now +Opt == Opt */
2038 conf->options |= opt;
2045 * JkEnvVar Directive Handling
2050 static const char *jk_add_env_var(cmd_parms * cmd,
2052 char *env_name, char *default_value)
2054 server_rec *s = cmd->server;
2055 jk_server_conf_t *conf =
2056 (jk_server_conf_t *) ap_get_module_config(s->module_config,
2059 conf->envvars_has_own = JK_TRUE;
2060 if (!conf->envvars) {
2061 conf->envvars = ap_make_table(cmd->pool, 0);
2062 conf->envvars_def = ap_make_table(cmd->pool, 0);
2063 conf->envvar_items = ap_make_array(cmd->pool, 0,
2064 sizeof(envvar_item));
2067 /* env_name is mandatory, default_value is optional.
2068 * No value means send the attribute only, if the env var is set during runtime.
2070 ap_table_setn(conf->envvars, env_name, default_value ? default_value : "");
2071 ap_table_setn(conf->envvars_def, env_name, default_value ? "1" : "0");
2077 * JkWorkerProperty Directive Handling
2079 * JkWorkerProperty name=value
2082 static const char *jk_set_worker_property(cmd_parms * cmd,
2086 server_rec *s = cmd->server;
2087 jk_server_conf_t *conf =
2088 (jk_server_conf_t *) ap_get_module_config(s->module_config,
2091 if (!jk_worker_properties)
2092 jk_map_alloc(&jk_worker_properties);
2093 if (jk_map_read_property(jk_worker_properties, NULL, line,
2094 JK_MAP_HANDLE_DUPLICATES, conf->log) == JK_FALSE)
2095 return ap_pstrcat(cmd->temp_pool, "Invalid JkWorkerProperty ", line, NULL);
2100 static const command_rec jk_cmds[] = {
2102 * JkWorkersFile specifies a full path to the location of the worker
2105 * This file defines the different workers used by apache to redirect
2108 {"JkWorkersFile", jk_set_worker_file, NULL, RSRC_CONF, TAKE1,
2109 "The name of a worker file for the Tomcat servlet containers"},
2112 * JkMountFile specifies a full path to the location of the
2113 * uriworker properties file.
2115 * This file defines the different mapping for workers used by apache
2116 * to redirect servlet requests.
2118 {"JkMountFile", jk_set_mount_file, NULL, RSRC_CONF, TAKE1,
2119 "The name of a mount file for the Tomcat servlet uri mappings"},
2122 * JkMountFileReload specifies the reload check interval for the
2123 * uriworker properties file.
2125 * Default value is: JK_URIMAP_DEF_RELOAD
2127 {"JkMountFileReload", jk_set_mount_file_reload, NULL, RSRC_CONF, TAKE1,
2128 "The reload check interval of the mount file"},
2131 * JkMount mounts a url prefix to a worker (the worker need to be
2132 * defined in the worker properties file.
2134 {"JkMount", jk_mount_context, NULL, RSRC_CONF|ACCESS_CONF, TAKE12,
2135 "A mount point from a context to a servlet-engine worker"},
2138 * JkUnMount unmounts a url prefix to a worker (the worker need to be
2139 * defined in the worker properties file.
2141 {"JkUnMount", jk_unmount_context, NULL, RSRC_CONF|ACCESS_CONF, TAKE12,
2142 "A no mount point from a context to a servlet-engine worker"},
2145 * JkMountCopy specifies if mod_jk should copy the mount points
2146 * from the main server to the virtual servers.
2148 {"JkMountCopy", jk_set_mountcopy, NULL, RSRC_CONF, TAKE1,
2149 "Should the base server mounts be copied to the virtual server"},
2152 * JkStripSession specifies if mod_jk should strip the ;jsessionid
2153 * from the unmapped urls
2155 {"JkStripSession", jk_set_strip_session, NULL, RSRC_CONF, FLAG,
2156 "Should the server strip the jsessionid from unmapped URLs"},
2159 * JkLogFile & JkLogLevel specifies to where should the plugin log
2160 * its information and how much.
2161 * JkLogStampFormat specify the time-stamp to be used on log
2163 {"JkLogFile", jk_set_log_file, NULL, RSRC_CONF, TAKE1,
2164 "Full path to the mod_jk module log file"},
2165 {"JkShmFile", jk_set_shm_file, NULL, RSRC_CONF, TAKE1,
2166 "Full path to the mod_jk module shared memory file"},
2167 {"JkShmSize", jk_set_shm_size, NULL, RSRC_CONF, TAKE1,
2168 "Size of the shared memory file in KBytes"},
2169 {"JkLogLevel", jk_set_log_level, NULL, RSRC_CONF, TAKE1,
2170 "The mod_jk module log level, can be debug, info, request, error, or emerg"},
2171 {"JkLogStampFormat", jk_set_log_fmt, NULL, RSRC_CONF, TAKE1,
2172 "The mod_jk module log format, follow strftime syntax"},
2173 {"JkRequestLogFormat", jk_set_request_log_format, NULL, RSRC_CONF, TAKE1,
2174 "The mod_jk module request log format string"},
2177 * Automatically Alias webapp context directories into the Apache
2180 {"JkAutoAlias", jk_set_auto_alias, NULL, RSRC_CONF, TAKE1,
2181 "The mod_jk module automatic context apache alias directory"},
2184 * Enable worker name to be set in an environment variable.
2185 * This way one can use LocationMatch together with mod_env,
2186 * mod_setenvif and mod_rewrite to set the target worker.
2187 * Use this in combination with SetHandler jakarta-servlet to
2188 * make mod_jk the handler for the request.
2191 {"JkWorkerIndicator", jk_set_worker_indicator, NULL, RSRC_CONF, TAKE1,
2192 "Name of the Apache environment that contains the worker name"},
2195 * Environment variables used to overwrite the following
2196 * request information which gets forwarded:
2205 {"JkRemoteAddrIndicator", jk_set_remote_addr_indicator, NULL, RSRC_CONF, TAKE1,
2206 "Name of the Apache environment that contains the remote address"},
2207 {"JkRemotePortIndicator", jk_set_remote_port_indicator, NULL, RSRC_CONF, TAKE1,
2208 "Name of the Apache environment that contains the remote port"},
2209 {"JkRemoteHostIndicator", jk_set_remote_host_indicator, NULL, RSRC_CONF, TAKE1,
2210 "Name of the Apache environment that contains the remote host name"},
2211 {"JkRemoteUserIndicator", jk_set_remote_user_indicator, NULL, RSRC_CONF, TAKE1,
2212 "Name of the Apache environment that contains the remote user name"},
2213 {"JkAuthTypeIndicator", jk_set_auth_type_indicator, NULL, RSRC_CONF, TAKE1,
2214 "Name of the Apache environment that contains the type of authentication"},
2215 {"JkLocalNameIndicator", jk_set_local_name_indicator, NULL, RSRC_CONF, TAKE1,
2216 "Name of the Apache environment that contains the local name"},
2217 {"JkLocalPortIndicator", jk_set_local_port_indicator, NULL, RSRC_CONF, TAKE1,
2218 "Name of the Apache environment that contains the local port"},
2221 * Apache has multiple SSL modules (for example apache_ssl, stronghold
2222 * IHS ...). Each of these can have a different SSL environment names
2223 * The following properties let the administrator specify the envoiroment
2226 * HTTPS - indication for SSL
2227 * CERTS - Base64-Der-encoded client certificates.
2228 * CIPHER - A string specifing the ciphers suite in use.
2229 * SESSION - A string specifing the current SSL session.
2230 * KEYSIZE - Size of Key used in dialogue (#bits are secure)
2232 {"JkHTTPSIndicator", jk_set_https_indicator, NULL, RSRC_CONF, TAKE1,
2233 "Name of the Apache environment that contains SSL indication"},
2234 {"JkCERTSIndicator", jk_set_certs_indicator, NULL, RSRC_CONF, TAKE1,
2235 "Name of the Apache environment that contains SSL client certificates"},
2236 {"JkCIPHERIndicator", jk_set_cipher_indicator, NULL, RSRC_CONF, TAKE1,
2237 "Name of the Apache environment that contains SSL client cipher"},
2238 {"JkCERTCHAINPrefix", jk_set_certchain_prefix, NULL, RSRC_CONF, TAKE1,
2239 "Name of the Apache environment (prefix) that contains SSL client chain certificates"},
2240 {"JkSESSIONIndicator", jk_set_session_indicator, NULL, RSRC_CONF, TAKE1,
2241 "Name of the Apache environment that contains SSL session"},
2242 {"JkKEYSIZEIndicator", jk_set_key_size_indicator, NULL, RSRC_CONF, TAKE1,
2243 "Name of the Apache environment that contains SSL key size in use"},
2244 {"JkExtractSSL", jk_set_enable_ssl, NULL, RSRC_CONF, FLAG,
2245 "Turns on SSL processing and information gathering by mod_jk"},
2248 * Options to tune mod_jk configuration
2249 * for now we understand :
2250 * +ForwardSSLKeySize => Forward SSL Key Size, to follow 2.3 specs but may broke old TC 3.2
2251 * -ForwardSSLKeySize => Don't Forward SSL Key Size, will make mod_jk works with all TC release
2252 * ForwardURICompat => Forward URI normally, less spec compliant but mod_rewrite compatible (old TC)
2253 * ForwardURICompatUnparsed => Forward URI as unparsed, spec compliant but broke mod_rewrite (old TC)
2254 * ForwardURIEscaped => Forward URI escaped and Tomcat (3.3 rc2) stuff will do the decoding part
2255 * +ForwardSSLCertChain => Forward SSL certificate chain
2256 * -ForwardSSLCertChain => Don't forward SSL certificate chain
2258 {"JkOptions", jk_set_options, NULL, RSRC_CONF, RAW_ARGS,
2259 "Set one of more options to configure the mod_jk module"},
2262 * JkEnvVar let user defines envs var passed from WebServer to
2265 {"JkEnvVar", jk_add_env_var, NULL, RSRC_CONF, TAKE12,
2266 "Adds a name of environment variable and an optional value "
2267 "that should be sent to servlet-engine"},
2269 {"JkWorkerProperty", jk_set_worker_property, NULL, RSRC_CONF, RAW_ARGS,
2270 "Set workers.properties formated directive"},
2275 /* ====================================================================== */
2276 /* The JK module handlers */
2277 /* ====================================================================== */
2280 * Called to handle a single request.
2282 static int jk_handler(request_rec * r)
2284 jk_server_conf_t *conf =
2285 (jk_server_conf_t *) ap_get_module_config(r->server->
2288 /* Retrieve the worker name stored by jk_translate() */
2289 const char *worker_name = ap_table_get(r->notes, JK_NOTE_WORKER_NAME);
2292 JK_TRACE_ENTER(conf->log);
2294 if (ap_table_get(r->subprocess_env, "no-jk")) {
2295 if (JK_IS_DEBUG_LEVEL(conf->log))
2296 jk_log(conf->log, JK_LOG_DEBUG,
2297 "Into handler no-jk env var detected for uri=%s, declined",
2299 JK_TRACE_EXIT(conf->log);
2304 jk_log(conf->log, JK_LOG_ERROR,
2305 "Request has proxyreq flag set in mod_jk handler - aborting.");
2306 JK_TRACE_EXIT(conf->log);
2307 return HTTP_INTERNAL_SERVER_ERROR;
2310 /* Set up r->read_chunked flags for chunked encoding, if present */
2311 if ((rc = ap_setup_client_block(r, REQUEST_CHUNKED_DECHUNK))) {
2312 jk_log(conf->log, JK_LOG_ERROR,
2313 "Could not setup client_block for chunked encoding - aborting");
2314 JK_TRACE_EXIT(conf->log);
2318 if (worker_name == NULL && r->handler && !strcmp(r->handler, JK_HANDLER)) {
2319 /* we may be here because of a manual directive ( that overrides
2321 * sets the handler directly ). We still need to know the worker.
2323 if (JK_IS_DEBUG_LEVEL(conf->log))
2324 jk_log(conf->log, JK_LOG_DEBUG,
2325 "Retrieving environment %s", conf->worker_indicator);
2326 worker_name = (char *)ap_table_get(r->subprocess_env, conf->worker_indicator);
2328 /* The JkWorkerIndicator environment variable has
2329 * been used to explicitely set the worker without JkMount.
2330 * This is useful in combination with LocationMatch or mod_rewrite.
2332 if (JK_IS_DEBUG_LEVEL(conf->log))
2333 jk_log(conf->log, JK_LOG_DEBUG,
2334 "Retrieved worker (%s) from env %s for %s",
2335 worker_name, conf->worker_indicator, r->uri);
2337 else if (worker_env.num_of_workers == 1) {
2338 /* We have a single worker ( the common case ).
2339 * ( lb is a bit special, it should count as a single worker but
2340 * I'm not sure how ). We also have a manual config directive that
2341 * explicitely give control to us.
2343 worker_name = worker_env.worker_list[0];
2344 if (JK_IS_DEBUG_LEVEL(conf->log))
2345 jk_log(conf->log, JK_LOG_DEBUG,
2346 "Single worker (%s) configuration for %s",
2347 worker_name, r->uri);
2349 else if (worker_env.num_of_workers) {
2350 worker_name = worker_env.worker_list[0];
2351 if (JK_IS_DEBUG_LEVEL(conf->log))
2352 jk_log(conf->log, JK_LOG_DEBUG,
2353 "Using first worker (%s) from %d workers for %s",
2354 worker_name, worker_env.num_of_workers, r->uri);
2359 jk_worker_t *worker;
2361 worker = wc_get_worker_for_name(worker_name, conf->log);
2364 #ifndef NO_GETTIMEOFDAY
2365 struct timeval tv_begin, tv_end;
2366 long micro, seconds;
2367 char *duration = NULL;
2370 int is_error = JK_HTTP_SERVER_ERROR;
2371 apache_private_data_t private_data;
2373 jk_pool_atom_t buf[SMALL_POOL_SIZE];
2374 jk_open_pool(&private_data.p, buf, sizeof(buf));
2376 private_data.read_body_started = JK_FALSE;
2379 wc_maintain(conf->log);
2380 jk_init_ws_service(&s);
2382 s.ws_private = &private_data;
2383 s.pool = &private_data.p;
2384 ap_table_setn(r->notes, JK_NOTE_WORKER_TYPE,
2385 wc_get_name_for_type(worker->type, conf->log));
2386 #ifndef NO_GETTIMEOFDAY
2387 gettimeofday(&tv_begin, NULL);
2390 if (init_ws_service(&private_data, &s, conf)) {
2391 jk_endpoint_t *end = NULL;
2392 if (worker->get_endpoint(worker, &end, conf->log)) {
2393 rc = end->service(end, &s, conf->log, &is_error);
2394 end->done(&end, conf->log);
2396 if (s.content_read < s.content_length ||
2397 (s.is_chunked && !s.no_more_chunks)) {
2399 * If the servlet engine didn't consume all of the
2400 * request data, consume and discard all further
2401 * characters left to read from client
2403 char *buff = ap_palloc(r->pool, 2048);
2407 ap_get_client_block(r, buff, 2048)) > 0) {
2408 s.content_read += rd;
2413 #ifndef NO_GETTIMEOFDAY
2414 gettimeofday(&tv_end, NULL);
2415 if (tv_end.tv_usec < tv_begin.tv_usec) {
2416 tv_end.tv_usec += 1000000;
2419 micro = tv_end.tv_usec - tv_begin.tv_usec;
2420 seconds = tv_end.tv_sec - tv_begin.tv_sec;
2422 ap_psprintf(r->pool, "%.1ld.%.6ld", seconds, micro);
2423 ap_table_setn(r->notes, JK_NOTE_REQUEST_DURATION, duration);
2425 if (s.route && *s.route)
2426 ap_table_setn(r->notes, JK_NOTE_WORKER_ROUTE, s.route);
2427 if (conf->format != NULL) {
2428 request_log_transaction(r, conf);
2432 jk_log(conf->log, JK_LOG_ERROR, "Could not init service"
2435 jk_close_pool(&private_data.p);
2436 JK_TRACE_EXIT(conf->log);
2439 jk_close_pool(&private_data.p);
2442 if (s.extension.use_server_error_pages &&
2443 s.http_response_status >= s.extension.use_server_error_pages) {
2444 if (JK_IS_DEBUG_LEVEL(conf->log))
2445 jk_log(conf->log, JK_LOG_DEBUG, "Forwarding status=%d"
2447 s.http_response_status, worker_name);
2448 JK_TRACE_EXIT(conf->log);
2449 return s.http_response_status;
2451 /* If tomcat returned no body and the status is not OK,
2452 let apache handle the error code */
2453 if (!r->sent_bodyct && r->status >= HTTP_BAD_REQUEST) {
2454 jk_log(conf->log, JK_LOG_INFO, "No body with status=%d"
2456 r->status, worker_name);
2457 JK_TRACE_EXIT(conf->log);
2460 if (JK_IS_DEBUG_LEVEL(conf->log))
2461 jk_log(conf->log, JK_LOG_DEBUG, "Service finished"
2462 " with status=%d for worker=%s",
2463 r->status, worker_name);
2464 JK_TRACE_EXIT(conf->log);
2465 return OK; /* NOT r->status, even if it has changed. */
2467 else if (rc == JK_CLIENT_ERROR) {
2468 if (is_error != HTTP_REQUEST_ENTITY_TOO_LARGE)
2469 r->connection->aborted = 1;
2470 jk_log(conf->log, JK_LOG_INFO, "Aborting connection"
2473 JK_TRACE_EXIT(conf->log);
2477 jk_log(conf->log, JK_LOG_INFO, "Service error=%d"
2480 JK_TRACE_EXIT(conf->log);
2485 jk_log(conf->log, JK_LOG_ERROR, "Could not init service"
2488 JK_TRACE_EXIT(conf->log);
2489 return HTTP_INTERNAL_SERVER_ERROR;
2493 JK_TRACE_EXIT(conf->log);
2494 return HTTP_INTERNAL_SERVER_ERROR;
2498 * Create a default config object.
2500 static void *create_jk_config(ap_pool * p, server_rec * s)
2502 jk_server_conf_t *c =
2503 (jk_server_conf_t *) ap_pcalloc(p, sizeof(jk_server_conf_t));
2506 c->mountcopy = JK_FALSE;
2507 c->was_initialized = JK_FALSE;
2509 if (s->is_virtual) {
2510 c->mountcopy = JK_UNSET;
2511 c->mount_file_reload = JK_UNSET;
2512 c->log_level = JK_UNSET;
2513 c->ssl_enable = JK_UNSET;
2514 c->strip_session = JK_UNSET;
2516 if (!jk_map_alloc(&(c->uri_to_context))) {
2517 ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, NULL, "Memory error");
2519 c->mountcopy = JK_FALSE;
2520 c->mount_file_reload = JK_URIMAP_DEF_RELOAD;
2521 c->log_level = JK_LOG_DEF_LEVEL;
2522 c->options = JK_OPT_DEFAULT;
2523 c->worker_indicator = JK_ENV_WORKER_NAME;
2526 * Configurable environment variables to overwrite
2527 * request information using meta data send by a
2528 * proxy in front of us.
2530 c->remote_addr_indicator = JK_ENV_REMOTE_ADDR;
2531 c->remote_port_indicator = JK_ENV_REMOTE_PORT;
2532 c->remote_host_indicator = JK_ENV_REMOTE_HOST;
2533 c->remote_user_indicator = JK_ENV_REMOTE_USER;
2534 c->auth_type_indicator = JK_ENV_AUTH_TYPE;
2535 c->local_name_indicator = JK_ENV_LOCAL_NAME;
2536 c->local_port_indicator = JK_ENV_LOCAL_PORT;
2539 * By default we will try to gather SSL info.
2540 * Disable this functionality through JkExtractSSL
2542 c->ssl_enable = JK_TRUE;
2544 * The defaults ssl indicators match those in mod_ssl (seems
2545 * to be in more use).
2547 c->https_indicator = JK_ENV_HTTPS;
2548 c->certs_indicator = JK_ENV_CERTS;
2549 c->cipher_indicator = JK_ENV_CIPHER;
2550 c->certchain_prefix = JK_ENV_CERTCHAIN_PREFIX;
2551 c->session_indicator = JK_ENV_SESSION;
2552 c->key_size_indicator = JK_ENV_KEY_SIZE;
2553 c->strip_session = JK_FALSE;
2555 c->envvars_has_own = JK_FALSE;
2564 * Utility - copy items from apr table src to dst,
2565 * for keys that exist in src but not in dst.
2567 static void merge_apr_table(table *src, table *dst)
2570 const array_header *arr;
2571 const table_entry *elts;
2573 arr = ap_table_elts(src);
2574 elts = (const table_entry *)arr->elts;
2575 for (i = 0; i < arr->nelts; ++i) {
2576 if (!ap_table_get(dst, elts[i].key)) {
2577 ap_table_setn(dst, elts[i].key, elts[i].val);
2583 static void *merge_jk_config(ap_pool * p, void *basev, void *overridesv)
2585 jk_server_conf_t *base = (jk_server_conf_t *) basev;
2586 jk_server_conf_t *overrides = (jk_server_conf_t *) overridesv;
2588 if (!overrides->log_file)
2589 overrides->log_file = base->log_file;
2590 if (overrides->log_level == JK_UNSET)
2591 overrides->log_level = base->log_level;
2593 if (!overrides->stamp_format_string)
2594 overrides->stamp_format_string = base->stamp_format_string;
2595 if (!overrides->format_string)
2596 overrides->format_string = base->format_string;
2598 if (!overrides->worker_indicator)
2599 overrides->worker_indicator = base->worker_indicator;
2601 if (!overrides->remote_addr_indicator)
2602 overrides->remote_addr_indicator = base->remote_addr_indicator;
2603 if (!overrides->remote_port_indicator)
2604 overrides->remote_port_indicator = base->remote_port_indicator;
2605 if (!overrides->remote_host_indicator)
2606 overrides->remote_host_indicator = base->remote_host_indicator;
2607 if (!overrides->remote_user_indicator)
2608 overrides->remote_user_indicator = base->remote_user_indicator;
2609 if (!overrides->auth_type_indicator)
2610 overrides->auth_type_indicator = base->auth_type_indicator;
2611 if (!overrides->local_name_indicator)
2612 overrides->local_name_indicator = base->local_name_indicator;
2613 if (!overrides->local_port_indicator)
2614 overrides->local_port_indicator = base->local_port_indicator;
2616 if (overrides->ssl_enable == JK_UNSET)
2617 overrides->ssl_enable = base->ssl_enable;
2618 if (!overrides->https_indicator)
2619 overrides->https_indicator = base->https_indicator;
2620 if (!overrides->certs_indicator)
2621 overrides->certs_indicator = base->certs_indicator;
2622 if (!overrides->cipher_indicator)
2623 overrides->cipher_indicator = base->cipher_indicator;
2624 if (!overrides->certchain_prefix)
2625 overrides->certchain_prefix = base->certchain_prefix;
2626 if (!overrides->session_indicator)
2627 overrides->session_indicator = base->session_indicator;
2628 if (!overrides->key_size_indicator)
2629 overrides->key_size_indicator = base->key_size_indicator;
2631 /* Don't simply accumulate bits in the JK_OPT_FWDURIMASK region, */
2632 /* because those are multi-bit values. */
2633 if (overrides->options & JK_OPT_FWDURIMASK)
2634 overrides->options |= (base->options & ~base->exclude_options) & ~JK_OPT_FWDURIMASK;
2636 overrides->options |= (base->options & ~base->exclude_options);
2638 if (base->envvars) {
2639 if (overrides->envvars && overrides->envvars_has_own) {
2640 /* merge_apr_table() preserves existing entries in overrides table */
2641 merge_apr_table(base->envvars, overrides->envvars);
2642 merge_apr_table(base->envvars_def, overrides->envvars_def);
2645 overrides->envvars = base->envvars;
2646 overrides->envvars_def = base->envvars_def;
2647 overrides->envvar_items = base->envvar_items;
2651 if (overrides->mountcopy == JK_UNSET && jk_mount_copy_all == JK_TRUE) {
2652 overrides->mountcopy = JK_TRUE;
2654 if (overrides->uri_to_context && overrides->mountcopy == JK_TRUE) {
2655 /* jk_map_copy() preserves existing entries in overrides map */
2656 if (jk_map_copy(base->uri_to_context, overrides->uri_to_context) == JK_FALSE) {
2657 jk_error_exit(APLOG_MARK, APLOG_EMERG, overrides->s, p, "Memory error");
2659 if (!overrides->mount_file)
2660 overrides->mount_file = base->mount_file;
2662 if (overrides->mountcopy == JK_TRUE) {
2663 if (!overrides->alias_dir)
2664 overrides->alias_dir = base->alias_dir;
2666 if (overrides->mount_file_reload == JK_UNSET)
2667 overrides->mount_file_reload = base->mount_file_reload;
2668 if (overrides->strip_session == JK_UNSET)
2669 overrides->strip_session = base->strip_session;
2674 static int JK_METHOD jk_log_to_file(jk_logger_t *l, int level,
2675 int used, char *what)
2678 (l->level <= level || level == JK_LOG_REQUEST_LEVEL) &&
2679 l->logger_private && what && used > 0) {
2680 jk_file_logger_t *flp = l->logger_private;
2681 int log_fd = flp->log_fd;
2684 what[used++] = '\r';
2686 what[used++] = '\n';
2687 if (write(log_fd, what, used) < 0 ) {
2688 ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, NULL,
2689 "mod_jk: jk_log_to_file %s failed",
2700 static int log_fd_get(char *key)
2702 const char *buf=ap_table_get(jk_log_fds, key);
2708 static void log_fd_set(pool *p, char *key, int v)
2710 char *buf=(char *)ap_pcalloc(p, 8*sizeof(char));
2711 ap_snprintf(buf, 8, "%d", v);
2712 ap_table_setn(jk_log_fds, key, buf);
2715 static void open_jk_log(server_rec *s, pool *p)
2721 jk_file_logger_t *flp;
2722 jk_server_conf_t *conf =
2723 (jk_server_conf_t *) ap_get_module_config(s->module_config,
2726 if (!s->is_virtual && !conf->log_file) {
2727 conf->log_file = ap_server_root_relative(p, JK_LOG_DEF_FILE);
2729 ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_NOERRNO, s,
2730 "No JkLogFile defined in httpd.conf. "
2731 "Using default %s", conf->log_file);
2734 if (s->is_virtual && conf->log_file == NULL) {
2735 ap_log_error(APLOG_MARK, APLOG_ERR, s,
2736 "mod_jk: Invalid JkLogFile NULL");
2737 conf->log = main_log;
2740 if (s->is_virtual && *(conf->log_file) == '\0') {
2741 ap_log_error(APLOG_MARK, APLOG_ERR, s,
2742 "mod_jk: Invalid JkLogFile EMPTY");
2743 conf->log = main_log;
2747 #ifdef CHROOTED_APACHE
2748 ap_server_strip_chroot(conf->log_file, 0);
2751 jklogfd = log_fd_get(conf->log_file);
2753 if (*conf->log_file == '|') {
2754 if ((pl = ap_open_piped_log(p, conf->log_file + 1)) == NULL) {
2755 ap_log_error(APLOG_MARK, APLOG_ERR, s,
2756 "mod_jk: could not open reliable pipe "
2757 "to jk log %s", conf->log_file + 1);
2760 jklogfd = ap_piped_log_write_fd(pl);
2763 fname = ap_server_root_relative(p, conf->log_file);
2765 ap_log_error(APLOG_MARK, APLOG_ERR, s,
2766 "mod_jk: Invalid JkLog " "path %s", conf->log_file);
2769 #if AP_MODULE_MAGIC_AT_LEAST(19990320,14)
2770 if ((jklogfd = ap_popenf_ex(p, fname, xfer_flags, xfer_mode, 1))
2773 if ((jklogfd = ap_popenf(p, fname, xfer_flags, xfer_mode))
2776 ap_log_error(APLOG_MARK, APLOG_ERR, s,
2777 "mod_jk: could not open JkLog " "file %s", fname);
2781 log_fd_set(p, conf->log_file, jklogfd);
2783 conf->log_fd = jklogfd;
2784 jkl = (jk_logger_t *)ap_palloc(p, sizeof(jk_logger_t));
2785 flp = (jk_file_logger_t *)ap_palloc(p, sizeof(jk_file_logger_t));
2787 jkl->log = jk_log_to_file;
2788 jkl->level = conf->log_level;
2789 jkl->logger_private = flp;
2790 flp->log_fd = conf->log_fd;
2792 jk_set_time_fmt(conf->log, conf->stamp_format_string);
2793 if (main_log == NULL)
2794 main_log = conf->log;
2801 static void jk_init(server_rec * s, ap_pool * p)
2804 server_rec *srv = s;
2805 const char *err_string = NULL;
2806 jk_server_conf_t *conf =
2807 (jk_server_conf_t *) ap_get_module_config(s->module_config,
2809 if (!jk_worker_properties)
2810 jk_map_alloc(&jk_worker_properties);
2811 jk_map_put(jk_worker_properties, "ServerRoot", ap_server_root, NULL);
2814 jk_log_fds = ap_make_table(p, 0);
2816 /* step through the servers and open each jk logfile
2817 * and do additional post config initialization.
2819 for (; srv; srv = srv->next) {
2820 jk_server_conf_t *sconf = (jk_server_conf_t *)ap_get_module_config(srv->module_config,
2824 * If a virtual server contains no JK directive, httpd shares
2825 * the config structure. But we don't want to share some settings
2826 * by default, especially the JkMount rules.
2827 * Therefore we check, if this config structure really belongs to this
2828 * vhost, otherwise we create a new one and merge.
2830 if (sconf && sconf->s != srv) {
2831 jk_server_conf_t *srvconf = (jk_server_conf_t *)create_jk_config(p, srv);
2832 sconf = (jk_server_conf_t *)merge_jk_config(p, sconf, srvconf);
2833 ap_set_module_config(srv->module_config, &jk_module, sconf);
2837 if (sconf && sconf->was_initialized == JK_FALSE) {
2838 sconf->was_initialized = JK_TRUE;
2839 open_jk_log(srv, p);
2840 sconf->options &= ~sconf->exclude_options;
2841 if (sconf->uri_to_context) {
2842 if (!uri_worker_map_alloc(&(sconf->uw_map),
2843 sconf->uri_to_context, sconf->log))
2844 jk_error_exit(APLOG_MARK, APLOG_EMERG, srv,
2846 if (sconf->options & JK_OPT_REJECTUNSAFE)
2847 sconf->uw_map->reject_unsafe = 1;
2849 sconf->uw_map->reject_unsafe = 0;
2850 if (sconf->mount_file) {
2851 sconf->uw_map->fname = sconf->mount_file;
2852 sconf->uw_map->reload = sconf->mount_file_reload;
2853 uri_worker_map_switch(sconf->uw_map, sconf->log);
2854 uri_worker_map_load(sconf->uw_map, sconf->log);
2858 if (sconf->mountcopy == JK_TRUE) {
2859 sconf->uw_map = conf->uw_map;
2862 if (sconf->format_string) {
2864 parse_request_log_string(p, sconf->format_string, &err_string);
2865 if (sconf->format == NULL)
2866 ap_log_error(APLOG_MARK, APLOG_ERR, srv,
2867 "JkRequestLogFormat format array NULL");
2869 if (sconf->envvars && sconf->envvars_has_own) {
2871 const array_header *arr;
2872 const table_entry *elts;
2874 const char *envvar_def;
2876 arr = ap_table_elts(sconf->envvars);
2878 elts = (const table_entry *)arr->elts;
2879 for (i = 0; i < arr->nelts; ++i) {
2880 item = (envvar_item *)ap_push_array(sconf->envvar_items);
2882 jk_error_exit(APLOG_MARK, APLOG_EMERG, srv,
2884 item->name = elts[i].key;
2885 envvar_def = ap_table_get(sconf->envvars_def, elts[i].key);
2886 if (envvar_def && !strcmp("1", envvar_def) ) {
2887 item->value = elts[i].val;
2888 item->has_default = 1;
2892 item->has_default = 0;
2900 if ((jk_worker_file != NULL) &&
2901 !jk_map_read_properties(jk_worker_properties, NULL, jk_worker_file, NULL,
2902 JK_MAP_HANDLE_DUPLICATES, conf->log)) {
2903 jk_error_exit(APLOG_MARK, APLOG_EMERG | APLOG_NOERRNO, s, p,
2904 "Error in reading worker properties from '%s'",
2908 if (jk_map_resolve_references(jk_worker_properties, "worker.",
2909 1, 1, conf->log) == JK_FALSE) {
2910 jk_error_exit(APLOG_MARK, APLOG_EMERG | APLOG_NOERRNO, s, p,
2911 "Error in resolving configuration references");
2914 #if !defined(WIN32) && !defined(NETWARE)
2916 jk_shm_file = ap_server_root_relative(p, JK_SHM_DEF_FILE);
2918 #ifdef CHROOTED_APACHE
2919 ap_server_strip_chroot(jk_shm_file, 0);
2923 ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_NOERRNO, s,
2924 "No JkShmFile defined in httpd.conf. "
2925 "Using default %s", jk_shm_file);
2929 if (jk_shm_size == 0)
2930 jk_shm_size = jk_shm_calculate_size(jk_worker_properties, conf->log);
2932 jk_log(conf->log, JK_LOG_WARNING,
2933 "The optimal shared memory size can now be determined automatically.");
2934 jk_log(conf->log, JK_LOG_WARNING,
2935 "You can remove the JkShmSize directive if you want to use the optimal size.");
2937 if ((rc = jk_shm_open(jk_shm_file, jk_shm_size, conf->log)) != 0)
2938 jk_log(conf->log, JK_LOG_ERROR,
2939 "Initializing shm:%s errno=%d. Load balancing workers will not function properly.",
2942 /* SREVILAK -- register cleanup handler to clear resources on restart,
2943 * to make sure log file gets closed in the parent process */
2944 ap_register_cleanup(p, s, jk_server_cleanup, ap_null_cleanup);
2946 /* we add the URI->WORKER MAP since workers using AJP14 will feed it */
2947 worker_env.uri_to_worker = conf->uw_map;
2948 worker_env.virtual = "*"; /* for now */
2949 worker_env.server_name = (char *)ap_get_server_version();
2950 worker_env.pool = NULL;
2952 if (wc_open(jk_worker_properties, &worker_env, conf->log)) {
2953 #if MODULE_MAGIC_NUMBER >= 19980527
2954 /* Tell apache we're here */
2955 ap_add_version_component(JK_EXPOSED_VERSION);
2957 jk_log(conf->log, JK_LOG_INFO,
2959 JK_FULL_EXPOSED_VERSION);
2962 jk_error_exit(APLOG_MARK, APLOG_EMERG | APLOG_NOERRNO, s, p,
2963 "Error in creating the workers."
2964 " Please consult your mod_jk log file '%s'.", conf->log_file);
2967 uri_worker_map_ext(conf->uw_map, conf->log);
2968 uri_worker_map_switch(conf->uw_map, conf->log);
2970 for (srv = s; srv; srv = srv->next) {
2971 jk_server_conf_t *sconf = (jk_server_conf_t *)ap_get_module_config(srv->module_config,
2973 if (conf->uw_map != sconf->uw_map && sconf->uw_map) {
2974 uri_worker_map_ext(sconf->uw_map, sconf->log);
2975 uri_worker_map_switch(sconf->uw_map, sconf->log);
2982 * Perform uri to worker mapping, and store the name of the relevant worker
2983 * in the notes fields of the request_rec object passed in. This will then
2984 * get picked up in jk_handler().
2986 static int jk_translate(request_rec * r)
2988 ap_set_module_config(r->request_config, &jk_module, NULL);
2991 jk_server_conf_t *conf =
2992 (jk_server_conf_t *) ap_get_module_config(r->server->
2997 char *clean_uri = ap_pstrdup(r->pool, r->uri);
3000 if (ap_table_get(r->subprocess_env, "no-jk")) {
3001 if (JK_IS_DEBUG_LEVEL(conf->log))
3002 jk_log(conf->log, JK_LOG_DEBUG,
3003 "Into translate no-jk env var detected for uri=%s, declined",
3008 ap_no2slash(clean_uri);
3009 if (!conf->uw_map) {
3010 if (JK_IS_DEBUG_LEVEL(conf->log))
3011 jk_log(conf->log, JK_LOG_DEBUG,
3012 "missing uri map for %s:%s",
3013 conf->s->server_hostname ? conf->s->server_hostname : "_default_",
3018 rule_extension_t *e;
3019 worker = map_uri_to_worker_ext(conf->uw_map, clean_uri,
3020 NULL, &e, NULL, conf->log);
3021 ap_set_module_config(r->request_config, &jk_module, e);
3024 /* Don't know the worker, ForwardDirectories is set, there is a
3025 * previous request for which the handler is JK_HANDLER (as set by
3026 * jk_fixups) and the request is for a directory:
3027 * --> forward to Tomcat, via default worker */
3028 if (!worker && (conf->options & JK_OPT_FWDDIRS) &&
3029 r->prev && r->prev->handler &&
3030 !strcmp(r->prev->handler, JK_HANDLER) && clean_uri &&
3031 strlen(clean_uri) && clean_uri[strlen(clean_uri) - 1] == '/') {
3033 if (worker_env.num_of_workers) {
3034 /* Nothing here to do but assign the first worker since we
3035 * already tried mapping and it didn't work out */
3036 worker = worker_env.worker_list[0];
3038 if (JK_IS_DEBUG_LEVEL(conf->log))
3039 jk_log(conf->log, JK_LOG_DEBUG, "Manual configuration for %s %s",
3040 clean_uri, worker_env.worker_list[0]);
3045 r->handler = ap_pstrdup(r->pool, JK_HANDLER);
3046 ap_table_setn(r->notes, JK_NOTE_WORKER_NAME, worker);
3048 else if (conf->alias_dir != NULL) {
3049 /* Automatically map uri to a context static file */
3050 if (JK_IS_DEBUG_LEVEL(conf->log))
3051 jk_log(conf->log, JK_LOG_DEBUG,
3052 "check alias_dir: %s",
3054 if (strlen(clean_uri) > 1) {
3055 /* Get the context directory name */
3056 char *context_dir = NULL;
3057 char *context_path = NULL;
3058 char *child_dir = NULL;
3059 char *index = clean_uri;
3060 char *suffix = strchr(index + 1, '/');
3061 if (suffix != NULL) {
3062 int size = suffix - index;
3063 context_dir = ap_pstrndup(r->pool, index, size);
3064 /* Get the context child directory name */
3065 index = index + size + 1;
3066 suffix = strchr(index, '/');
3067 if (suffix != NULL) {
3068 size = suffix - index;
3069 child_dir = ap_pstrndup(r->pool, index, size);
3074 /* Deny access to WEB-INF and META-INF directories */
3075 if (child_dir != NULL) {
3076 if (JK_IS_DEBUG_LEVEL(conf->log))
3077 jk_log(conf->log, JK_LOG_DEBUG,
3078 "AutoAlias child_dir: %s",
3080 if (!strcasecmp(child_dir, "WEB-INF") ||
3081 !strcasecmp(child_dir, "META-INF")) {
3082 if (JK_IS_DEBUG_LEVEL(conf->log))
3083 jk_log(conf->log, JK_LOG_DEBUG,
3084 "AutoAlias HTTP_NOT_FOUND for URI: %s",
3086 return HTTP_NOT_FOUND;
3091 context_dir = ap_pstrdup(r->pool, index);
3094 context_path = ap_pstrcat(r->pool, conf->alias_dir,
3095 ap_os_escape_path(r->pool,
3098 if (context_path != NULL) {
3099 DIR *dir = ap_popendir(r->pool, context_path);
3102 ap_os_escape_path(r->pool, clean_uri, 1);
3104 ap_pstrcat(r->pool, conf->alias_dir, escurl,
3106 ap_pclosedir(r->pool, dir);
3107 /* Add code to verify real path ap_os_canonical_name */
3109 if (JK_IS_DEBUG_LEVEL(conf->log))
3110 jk_log(conf->log, JK_LOG_DEBUG,
3111 "AutoAlias OK for file: %s",
3118 /* Deny access to war files in web app directory */
3119 int size = strlen(context_dir);
3121 && !strcasecmp(context_dir + (size - 4),
3123 if (JK_IS_DEBUG_LEVEL(conf->log))
3124 jk_log(conf->log, JK_LOG_DEBUG,
3125 "AutoAlias FORBIDDEN for URI: %s",
3134 if (JK_IS_DEBUG_LEVEL(conf->log))
3135 jk_log(conf->log, JK_LOG_DEBUG,
3136 "no match for %s found",
3138 if (conf->strip_session == JK_TRUE) {
3141 jsessionid = strstr(r->uri, JK_PATH_SESSION_IDENTIFIER);
3143 if (JK_IS_DEBUG_LEVEL(conf->log))
3144 jk_log(conf->log, JK_LOG_DEBUG,
3145 "removing session identifier [%s] for non servlet url [%s]",
3146 jsessionid, r->uri);
3151 jsessionid = strstr(r->filename, JK_PATH_SESSION_IDENTIFIER);
3163 /* In case ForwardDirectories option is set, we need to know if all files
3164 * mentioned in DirectoryIndex have been exhausted without success. If yes, we
3165 * need to let mod_dir know that we want Tomcat to handle the directory
3167 static int jk_fixups(request_rec * r)
3169 /* This is a sub-request, probably from mod_dir */
3171 jk_server_conf_t *conf = (jk_server_conf_t *)
3172 ap_get_module_config(r->server->module_config, &jk_module);
3173 char *worker = (char *)ap_table_get(r->notes, JK_NOTE_WORKER_NAME);
3175 if (ap_table_get(r->subprocess_env, "no-jk")) {
3176 if (JK_IS_DEBUG_LEVEL(conf->log))
3177 jk_log(conf->log, JK_LOG_DEBUG,
3178 "Into fixup no-jk env var detected for uri=%s, declined",
3183 /* Only if we have no worker and ForwardDirectories is set */
3184 if (!worker && (conf->options & JK_OPT_FWDDIRS)) {
3185 char *dummy_ptr[1], **names_ptr, *idx;
3187 dir_config_rec *d = (dir_config_rec *)
3188 ap_get_module_config(r->per_dir_config, &dir_module);
3190 /* Direct lift from mod_dir */
3191 if (d->index_names) {
3192 names_ptr = (char **)d->index_names->elts;
3193 num_names = d->index_names->nelts;
3196 dummy_ptr[0] = DEFAULT_INDEX;
3197 names_ptr = dummy_ptr;
3201 /* Where the index file would start within the filename */
3202 idx = r->filename + strlen(r->filename) -
3203 strlen(names_ptr[num_names - 1]);
3205 /* The requested filename has the last index file at the end */
3206 if (idx >= r->filename && !strcmp(idx, names_ptr[num_names - 1])) {
3207 r->uri = r->main->uri; /* Trick mod_dir with URI */
3208 r->finfo.st_mode = S_IFREG; /* Trick mod_dir with file stat */
3210 /* We'll be checking for handler in r->prev later on */
3211 r->main->handler = ap_pstrdup(r->pool, JK_HANDLER);
3213 if (JK_IS_DEBUG_LEVEL(conf->log))
3214 jk_log(conf->log, JK_LOG_DEBUG, "ForwardDirectories on: %s",
3223 static void child_exit_handler(server_rec * s, ap_pool * p)
3225 /* srevilak - refactor cleanup body to jk_generic_cleanup() */
3226 jk_generic_cleanup(s);
3230 static void child_init_handler(server_rec * s, ap_pool * p)
3233 jk_server_conf_t *conf =
3234 (jk_server_conf_t *) ap_get_module_config(s->module_config,
3237 JK_TRACE_ENTER(conf->log);
3239 if ((rc = jk_shm_attach(jk_shm_file, jk_shm_size, conf->log)) != 0)
3240 jk_log(conf->log, JK_LOG_ERROR, "Attaching shm:%s errno=%d",
3243 JK_TRACE_EXIT(conf->log);
3248 /** srevilak -- registered as a cleanup handler in jk_init */
3249 static void jk_server_cleanup(void *data)
3251 jk_generic_cleanup((server_rec *) data);
3257 * body taken from exit_handler()
3259 static void jk_generic_cleanup(server_rec *s)
3262 if (jk_worker_properties) {
3263 jk_map_free(&jk_worker_properties);
3264 jk_worker_properties = NULL;
3265 jk_worker_file = NULL;
3266 jk_mount_copy_all = JK_FALSE;
3269 /* loop through all available servers to clean up all configuration
3270 * records we've created
3273 jk_server_conf_t *conf =
3274 (jk_server_conf_t *) ap_get_module_config(s->module_config,
3277 if (conf && conf->was_initialized == JK_TRUE) {
3278 /* On pool cleanup pass NULL for the jk_logger to
3279 prevent segmentation faults on Windows because
3280 we can't guarantee what order pools get cleaned
3281 up between APR implementations. */
3283 if (conf->uri_to_context) {
3284 jk_map_free(&conf->uri_to_context);
3285 /* We cannot have allocated uw_map
3286 * unless we've allocated uri_to_context
3289 uri_worker_map_free(&conf->uw_map, NULL);
3291 conf->was_initialized = JK_FALSE;
3297 /** END SREVILAK **/
3300 static const handler_rec jk_handlers[] = {
3301 {JK_MAGIC_TYPE, jk_handler},
3302 {JK_HANDLER, jk_handler},
3306 module MODULE_VAR_EXPORT jk_module = {
3307 STANDARD_MODULE_STUFF,
3308 jk_init, /* module initializer */
3309 NULL, /* per-directory config creator */
3310 NULL, /* dir config merger */
3311 create_jk_config, /* server config creator */
3312 merge_jk_config, /* server config merger */
3313 jk_cmds, /* command table */
3314 jk_handlers, /* [7] list of handlers */
3315 jk_translate, /* [2] filename-to-URI translation */
3316 NULL, /* [5] check/validate user_id */
3317 NULL, /* [6] check user_id is valid *here* */
3318 NULL, /* [4] check access by host address */
3319 NULL, /* XXX [7] MIME type checker/setter */
3320 jk_fixups, /* [8] fixups */
3321 NULL, /* [10] logger */
3322 NULL, /* [3] header parser */
3323 child_init_handler, /* apache child process initializer */
3324 child_exit_handler, /* apache child process exit/cleanup */
3325 NULL /* [1] post read_request handling */
3328 * Extended module APIs, needed when using SSL.
3329 * STDC say that we do not have to have them as NULL but
3332 , NULL, /* add_module */
3333 NULL, /* remove_module */
3334 NULL, /* rewrite_command */
3335 NULL, /* new_connection */
3336 NULL /* close_connection */