1 /*
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
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
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.
16 */
17
18 /***************************************************************************
19 * Description: Apache 2 plugin for Tomcat *
20 * Author: Gal Shachor <shachor@il.ibm.com> *
21 * Henri Gomez <hgomez@apache.org> *
22 ***************************************************************************/
23
24 /*
25 * mod_jk: keeps all servlet related ramblings together.
26 */
27
28 #include "ap_config.h"
29 #include "apr_lib.h"
30 #include "apr_date.h"
31 #include "apr_file_info.h"
32 #include "apr_file_io.h"
33 #include "httpd.h"
34 #include "http_config.h"
35 #include "http_request.h"
36 #include "http_core.h"
37 #include "http_protocol.h"
38 #include "http_main.h"
39 #include "http_log.h"
40 #include "util_script.h"
41 #include "ap_mpm.h"
42
43 #if defined(AS400) && !defined(AS400_UTF8)
44 #include "ap_charset.h"
45 #include "util_charset.h" /* ap_hdrs_from_ascii */
46 #endif
47
48 /* deprecated with apr 0.9.3 */
49
50 #include "apr_version.h"
51 #if (APR_MAJOR_VERSION == 0) && \
52 (APR_MINOR_VERSION <= 9) && \
53 (APR_PATCH_VERSION < 3)
54 #define apr_filepath_name_get apr_filename_of_pathname
55 #endif
56
57 #include "apr_strings.h"
58
59 /* Yes; sorta sucks - with luck we will clean this up before httpd-2.2
60 * ships, leaving AP_NEED_SET_MUTEX_PERMS def'd as 1 or 0 on all platforms.
61 */
62 #ifdef AP_NEED_SET_MUTEX_PERMS
63 # define JK_NEED_SET_MUTEX_PERMS AP_NEED_SET_MUTEX_PERMS
64 #else
65 /* A special case for httpd-2.0 */
66 # if !defined(OS2) && !defined(WIN32) && !defined(BEOS) && !defined(AS400)
67 # define JK_NEED_SET_MUTEX_PERMS 1
68 # else
69 # define JK_NEED_SET_MUTEX_PERMS 0
70 # endif
71 #endif
72
73 #if JK_NEED_SET_MUTEX_PERMS
74 #include "unixd.h" /* for unixd_set_global_mutex_perms */
75 #endif
76 /*
77 * jk_ include files
78 */
79 #include "jk_global.h"
80 #include "jk_ajp13.h"
81 #include "jk_logger.h"
82 #include "jk_map.h"
83 #include "jk_pool.h"
84 #include "jk_service.h"
85 #include "jk_uri_worker_map.h"
86 #include "jk_util.h"
87 #include "jk_worker.h"
88 #include "jk_shm.h"
89 #include "jk_url.h"
90
91 #define JK_LOG_DEF_FILE ("logs/mod_jk.log")
92 #define JK_SHM_DEF_FILE ("logs/jk-runtime-status")
93 #define JK_ENV_REMOTE_ADDR ("JK_REMOTE_ADDR")
94 #define JK_ENV_REMOTE_PORT ("JK_REMOTE_PORT")
95 #define JK_ENV_REMOTE_HOST ("JK_REMOTE_HOST")
96 #define JK_ENV_REMOTE_USER ("JK_REMOTE_USER")
97 #define JK_ENV_AUTH_TYPE ("JK_AUTH_TYPE")
98 #define JK_ENV_LOCAL_NAME ("JK_LOCAL_NAME")
99 #define JK_ENV_LOCAL_ADDR ("JK_LOCAL_ADDR")
100 #define JK_ENV_LOCAL_PORT ("JK_LOCAL_PORT")
101 #define JK_ENV_IGNORE_CL ("JK_IGNORE_CL")
102 #define JK_ENV_HTTPS ("HTTPS")
103 #define JK_ENV_SSL_PROTOCOL ("SSL_PROTOCOL")
104 #define JK_ENV_CERTS ("SSL_CLIENT_CERT")
105 #define JK_ENV_CIPHER ("SSL_CIPHER")
106 #define JK_ENV_SESSION ("SSL_SESSION_ID")
107 #define JK_ENV_KEY_SIZE ("SSL_CIPHER_USEKEYSIZE")
108 #define JK_ENV_CERTCHAIN_PREFIX ("SSL_CLIENT_CERT_CHAIN_")
109 #define JK_ENV_REPLY_TIMEOUT ("JK_REPLY_TIMEOUT")
110 #define JK_ENV_STICKY_IGNORE ("JK_STICKY_IGNORE")
111 #define JK_ENV_STATELESS ("JK_STATELESS")
112 #define JK_ENV_ROUTE ("JK_ROUTE")
113 #define JK_ENV_WORKER_NAME ("JK_WORKER_NAME")
114 #define JK_NOTE_WORKER_NAME ("JK_WORKER_NAME")
115 #define JK_NOTE_WORKER_TYPE ("JK_WORKER_TYPE")
116 #define JK_NOTE_REQUEST_DURATION ("JK_REQUEST_DURATION")
117 #define JK_NOTE_WORKER_ROUTE ("JK_WORKER_ROUTE")
118 #define JK_HANDLER ("jakarta-servlet")
119 #define JK_MAGIC_TYPE ("application/x-jakarta-servlet")
120 #define NULL_FOR_EMPTY(x) ((x && !strlen(x)) ? NULL : x)
121 #define STRNULL_FOR_NULL(x) ((x) ? (x) : "(null)")
122 #define JK_LOG_LOCK_KEY ("jk_log_lock_key")
123 #define JKLOG_MARK __FILE__,__LINE__
124
125 /*
126 * If you are not using SSL, comment out the following line. It will make
127 * apache run faster.
128 *
129 * Personally, I (DM), think this may be a lie.
130 */
131 #define ADD_SSL_INFO
132
133 /* Needed for Apache 2.3/2.4 per-module log config */
134 #ifdef APLOG_USE_MODULE
135 APLOG_USE_MODULE(jk);
136 #endif
137
138 /* module MODULE_VAR_EXPORT jk_module; */
139 AP_MODULE_DECLARE_DATA module jk_module;
140
141 /*
142 * Environment variable forward object
143 */
144 typedef struct
145 {
146 int has_default;
147 char *name;
148 char *value;
149 } envvar_item;
150
151 /*
152 * Configuration object for the mod_jk module.
153 */
154 typedef struct
155 {
156
157 /*
158 * Log stuff
159 */
160 char *log_file;
161 int log_level;
162 jk_logger_t *log;
163
164 /*
165 * Mount stuff
166 */
167 char *mount_file;
168 int mount_file_reload;
169 jk_map_t *uri_to_context;
170
171 int mountcopy;
172
173 jk_uri_worker_map_t *uw_map;
174
175 int was_initialized;
176
177 /*
178 * Automatic context path apache alias
179 */
180 char *alias_dir;
181
182 /*
183 * Request Logging
184 */
185
186 char *stamp_format_string;
187 char *format_string;
188 apr_array_header_t *format;
189
190 /*
191 * Setting target worker via environment
192 */
193 char *worker_indicator;
194
195 /*
196 * Configurable environment variables to overwrite
197 * request information using meta data send by a
198 * proxy in front of us.
199 */
200 char *remote_addr_indicator;
201 char *remote_port_indicator;
202 char *remote_host_indicator;
203 char *remote_user_indicator;
204 char *auth_type_indicator;
205 char *local_name_indicator;
206 char *local_addr_indicator;
207 char *local_port_indicator;
208
209 /*
210 * Configurable environment variable to force
211 * ignoring a request Content-Length header
212 * (useful to make mod_deflate request inflation
213 * compatible with mod_jk).
214 */
215 char *ignore_cl_indicator;
216
217 /*
218 * SSL Support
219 */
220 int ssl_enable;
221 char *https_indicator;
222 char *ssl_protocol_indicator;
223 char *certs_indicator;
224 char *cipher_indicator;
225 char *session_indicator; /* Servlet API 2.3 requirement */
226 char *key_size_indicator; /* Servlet API 2.3 requirement */
227 char *certchain_prefix; /* Client certificate chain prefix */
228
229 /*
230 * Jk Options
231 */
232 int options;
233 int exclude_options;
234
235 int strip_session;
236 char *strip_session_name;
237 /*
238 * Environment variables support
239 */
240 int envvars_has_own;
241 apr_table_t *envvars;
242 apr_table_t *envvars_def;
243 apr_array_header_t *envvar_items;
244
245 server_rec *s;
246 } jk_server_conf_t;
247
248 /*
249 * Request specific configuration
250 */
251 struct jk_request_conf
252 {
253 rule_extension_t *rule_extensions;
254 char *orig_uri;
255 int jk_handled;
256 };
257
258 typedef struct jk_request_conf jk_request_conf_t;
259
260 struct apache_private_data
261 {
262 jk_pool_t p;
263
264 int read_body_started;
265 request_rec *r;
266 };
267 typedef struct apache_private_data apache_private_data_t;
268
269 static server_rec *main_server = NULL;
270 static jk_logger_t *main_log = NULL;
271 static apr_hash_t *jk_log_fps = NULL;
272 static jk_worker_env_t worker_env;
273 static apr_global_mutex_t *jk_log_lock = NULL;
274 static char *jk_shm_file = NULL;
275 static int jk_shm_size = 0;
276 static int jk_shm_size_set = 0;
277 static volatile int jk_watchdog_interval = 0;
278 static volatile int jk_watchdog_running = 0;
279
280 /*
281 * Worker stuff
282 */
283 static jk_map_t *jk_worker_properties = NULL;
284 static char *jk_worker_file = NULL;
285 static int jk_mount_copy_all = JK_FALSE;
286
287 static int JK_METHOD ws_start_response(jk_ws_service_t *s,
288 int status,
289 const char *reason,
290 const char *const *header_names,
291 const char *const *header_values,
292 unsigned num_of_headers);
293
294 static int JK_METHOD ws_read(jk_ws_service_t *s,
295 void *b, unsigned len, unsigned *actually_read);
296
297 static int init_jk(apr_pool_t * pconf, jk_server_conf_t * conf,
298 server_rec * s);
299
300 static int JK_METHOD ws_write(jk_ws_service_t *s, const void *b, unsigned l);
301
302 static void JK_METHOD ws_add_log_items(jk_ws_service_t *s,
303 const char *const *log_names,
304 const char *const *log_values,
305 unsigned num_of_log_items);
306
307 static void * JK_METHOD ws_next_vhost(void *d);
308
309 static void JK_METHOD ws_vhost_to_text(void *d, char *buf, size_t len);
310
311 static jk_uri_worker_map_t * JK_METHOD ws_vhost_to_uw_map(void *d);
312
313 /* ========================================================================= */
314 /* JK Service step callbacks */
315 /* ========================================================================= */
316
ws_start_response(jk_ws_service_t * s,int status,const char * reason,const char * const * header_names,const char * const * header_values,unsigned num_of_headers)317 static int JK_METHOD ws_start_response(jk_ws_service_t *s,
318 int status,
319 const char *reason,
320 const char *const *header_names,
321 const char *const *header_values,
322 unsigned num_of_headers)
323 {
324 unsigned h;
325 apache_private_data_t *p = s->ws_private;
326 request_rec *r = p->r;
327
328 /* If we use proxy error pages, still pass
329 * through context headers needed for special status codes.
330 */
331 if (s->extension.use_server_error_pages &&
332 status >= s->extension.use_server_error_pages) {
333 if (status == HTTP_UNAUTHORIZED) {
334 int found = JK_FALSE;
335 for (h = 0; h < num_of_headers; h++) {
336 if (!strcasecmp(header_names[h], "WWW-Authenticate")) {
337 char *tmp = apr_pstrdup(r->pool, header_values[h]);
338 apr_table_set(r->err_headers_out,
339 "WWW-Authenticate", tmp);
340 found = JK_TRUE;
341 }
342 }
343 if (found == JK_FALSE) {
344 jk_server_conf_t *xconf = (jk_server_conf_t *)
345 ap_get_module_config(r->server->module_config,
346 &jk_module);
347 jk_log(xconf->log, JK_LOG_INFO,
348 "origin server sent 401 without"
349 " WWW-Authenticate header");
350 }
351 }
352 return JK_TRUE;
353 }
354
355 /* If there is no reason given (or an empty one),
356 * we'll try to guess a good one.
357 */
358 if (!reason || *reason == '\0') {
359 /* We ask Apache httpd about a good reason phrase. */
360 reason = ap_get_status_line(status);
361 /* Unfortunately it returns with a 500 reason phrase,
362 * whenever it does not know about the given status code,
363 * e.g. in the case of custom status codes.
364 */
365 if (status != 500 && !strncmp(reason, "500 ", 4)) {
366 reason = "Unknown Reason";
367 }
368 else {
369 /* Apache httpd returns a full status line,
370 * but we only want a reason phrase, so skip
371 * the prepended status code.
372 */
373 reason = reason + 4;
374 }
375 }
376 r->status = status;
377 r->status_line = apr_psprintf(r->pool, "%d %s", status, reason);
378
379 for (h = 0; h < num_of_headers; h++) {
380 if (!strcasecmp(header_names[h], "Content-type")) {
381 char *tmp = apr_pstrdup(r->pool, header_values[h]);
382 ap_content_type_tolower(tmp);
383 /* It should be done like this in Apache 2.0 */
384 /* This way, Apache 2.0 will be able to set the output filter */
385 /* and it make jk usable with deflate using */
386 /* AddOutputFilterByType DEFLATE text/html */
387 ap_set_content_type(r, tmp);
388 }
389 else if (!strcasecmp(header_names[h], "Location")) {
390 #if defined(AS400) && !defined(AS400_UTF8)
391 /* Fix escapes in Location Header URL */
392 ap_fixup_escapes((char *)header_values[h],
393 strlen(header_values[h]), ap_hdrs_from_ascii);
394 #endif
395 apr_table_set(r->headers_out, header_names[h], header_values[h]);
396 }
397 else if (!strcasecmp(header_names[h], "Content-Length")) {
398 ap_set_content_length(r, apr_atoi64(header_values[h]));
399 }
400 else if (!strcasecmp(header_names[h], "Transfer-Encoding")) {
401 apr_table_set(r->headers_out, header_names[h], header_values[h]);
402 }
403 else if (!strcasecmp(header_names[h], "Last-Modified")) {
404 /*
405 * If the script gave us a Last-Modified header, we can't just
406 * pass it on blindly because of restrictions on future values.
407 */
408 ap_update_mtime(r, apr_date_parse_http(header_values[h]));
409 ap_set_last_modified(r);
410 }
411 else {
412 apr_table_add(r->headers_out, header_names[h], header_values[h]);
413 }
414 }
415
416 /* this NOP function was removed in apache 2.0 alpha14 */
417 /* ap_send_http_header(r); */
418 s->response_started = JK_TRUE;
419
420 return JK_TRUE;
421 }
422
423 /*
424 * Read a chunk of the request body into a buffer. Attempt to read len
425 * bytes into the buffer. Write the number of bytes actually read into
426 * actually_read.
427 *
428 * Think of this function as a method of the apache1.3-specific subclass of
429 * the jk_ws_service class. Think of the *s param as a "this" or "self"
430 * pointer.
431 */
ws_read(jk_ws_service_t * s,void * b,unsigned len,unsigned * actually_read)432 static int JK_METHOD ws_read(jk_ws_service_t *s,
433 void *b, unsigned len, unsigned *actually_read)
434 {
435 if (s && s->ws_private && b && actually_read) {
436 apache_private_data_t *p = s->ws_private;
437 if (!p->read_body_started) {
438 if (ap_should_client_block(p->r)) {
439 p->read_body_started = JK_TRUE;
440 }
441 }
442
443 if (p->read_body_started) {
444 #if defined(AS400) && !defined(AS400_UTF8)
445 int long rv = OK;
446 if (rv = ap_change_request_body_xlate(p->r, 65535, 65535)) { /* turn off request body translation */
447 ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_CRIT, 0, NULL,
448 "mod_jk: Error on ap_change_request_body_xlate, rc=%d",
449 rv);
450 return JK_FALSE;
451 }
452 #else
453 long rv;
454 #endif
455
456 if ((rv = ap_get_client_block(p->r, b, len)) < 0) {
457 return JK_FALSE;
458 }
459 else {
460 *actually_read = (unsigned)rv;
461 }
462 return JK_TRUE;
463 }
464 }
465 return JK_FALSE;
466 }
467
ws_flush(jk_ws_service_t * s)468 static void JK_METHOD ws_flush(jk_ws_service_t *s)
469 {
470 #if ! (defined(AS400) && !defined(AS400_UTF8))
471 if (s && s->ws_private) {
472 apache_private_data_t *p = s->ws_private;
473 ap_rflush(p->r);
474 }
475 #endif
476 }
477
ws_done(jk_ws_service_t * s)478 static void JK_METHOD ws_done(jk_ws_service_t *s)
479 {
480 #if ! (defined(AS400) && !defined(AS400_UTF8))
481 if (s && s->ws_private) {
482 apache_private_data_t *p = s->ws_private;
483 ap_finalize_request_protocol(p->r);
484 }
485 #endif
486 }
487
488 /*
489 * Write a chunk of response data back to the browser. If the headers
490 * haven't yet been sent over, send over default header values (Status =
491 * 200, basically).
492 *
493 * Write len bytes from buffer b.
494 *
495 * Think of this function as a method of the apache1.3-specific subclass of
496 * the jk_ws_service class. Think of the *s param as a "this" or "self"
497 * pointer.
498 */
499
ws_write(jk_ws_service_t * s,const void * b,unsigned int l)500 static int JK_METHOD ws_write(jk_ws_service_t *s, const void *b, unsigned int l)
501 {
502 #if defined(AS400) && !defined(AS400_UTF8)
503 int rc;
504 #endif
505
506 if (s && s->ws_private && b) {
507 apache_private_data_t *p = s->ws_private;
508
509 if (l) {
510 /* BUFF *bf = p->r->connection->client; */
511 int r = 0;
512 int ll = l;
513 const char *bb = (const char *)b;
514
515 if (!s->response_started) {
516 if (main_log)
517 jk_log(main_log, JK_LOG_INFO,
518 "Write without start, starting with defaults");
519 if (!s->start_response(s, 200, NULL, NULL, NULL, 0)) {
520 return JK_FALSE;
521 }
522 }
523 if (p->r->header_only) {
524 #if ! (defined(AS400) && !defined(AS400_UTF8))
525 ap_rflush(p->r);
526 #endif
527 return JK_TRUE;
528 }
529 #if defined(AS400) && !defined(AS400_UTF8)
530 /* turn off response body translation */
531 rc = ap_change_response_body_xlate(p->r, 65535, 65535);
532 if (rc) {
533 ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_CRIT, 0, NULL,
534 "mod_jk: Error on ap_change_response_body_xlate, rc=%d",
535 rc);
536 return JK_FALSE;
537 }
538 #endif
539
540 while (ll > 0 && !p->r->connection->aborted) {
541 r = ap_rwrite(bb, ll, p->r);
542 if (JK_IS_DEBUG_LEVEL(main_log))
543 jk_log(main_log, JK_LOG_DEBUG,
544 "written %d out of %d", r, ll);
545
546 if (r < 0)
547 return JK_FALSE;
548 ll -= r;
549 bb += r;
550 }
551 if (ll && p->r->connection->aborted) {
552 /* Fail if there is something left to send and
553 * the connection was aborted by the client
554 */
555 return JK_FALSE;
556 }
557 }
558
559 return JK_TRUE;
560 }
561 return JK_FALSE;
562 }
563
ws_add_log_items(jk_ws_service_t * s,const char * const * log_names,const char * const * log_values,unsigned num_of_log_items)564 static void JK_METHOD ws_add_log_items(jk_ws_service_t *s,
565 const char *const *log_names,
566 const char *const *log_values,
567 unsigned num_of_log_items)
568 {
569 unsigned h;
570 apache_private_data_t *p = s->ws_private;
571 request_rec *r = p->r;
572
573 for (h = 0; h < num_of_log_items; h++) {
574 if (log_names[h] && log_values[h]) {
575 apr_table_set(r->notes, log_names[h], log_values[h]);
576 }
577 }
578 }
579
ws_next_vhost(void * d)580 static void * JK_METHOD ws_next_vhost(void *d)
581 {
582 server_rec *s = (server_rec *)d;
583 if (s == NULL)
584 return main_server;
585 return s->next;
586 }
587
ws_vhost_to_text(void * d,char * buf,size_t len)588 static void JK_METHOD ws_vhost_to_text(void *d, char *buf, size_t len)
589 {
590 server_rec *s = (server_rec *)d;
591 size_t used = 0;
592
593 if (s->server_hostname) {
594 used += strlen(s->server_hostname);
595 }
596 if (!s->is_virtual) {
597 if (s->port)
598 used += strlen(":XXXXX");
599 }
600 else if (s->addrs) {
601 used += strlen(" [");
602 if (s->addrs->virthost)
603 used += strlen(s->addrs->virthost);
604 if (s->addrs->host_port)
605 used += strlen(":XXXXX");
606 used += strlen("]");
607 }
608
609 if (len < used && len > strlen("XXX")) {
610 strcpy(buf, "XXX");
611 return;
612 }
613
614 used = 0;
615
616 if (s->server_hostname) {
617 strcpy(buf + used, s->server_hostname);
618 used += strlen(s->server_hostname);
619 }
620 if (!s->is_virtual) {
621 if (s->port) {
622 sprintf(buf + used, ":%hu", s->port);
623 used = strlen(buf);
624 }
625 }
626 else if (s->addrs) {
627 strcpy(buf + used, " [");
628 used += strlen(" [");
629 if (s->addrs->virthost) {
630 strcpy(buf + used, s->addrs->virthost);
631 used += strlen(s->addrs->virthost);
632 }
633 if (s->addrs->host_port) {
634 sprintf(buf + used, ":%hu", s->addrs->host_port);
635 used = strlen(buf);
636 }
637 strcpy(buf + used, "]");
638 used += strlen("]");
639 }
640 }
641
ws_vhost_to_uw_map(void * d)642 static jk_uri_worker_map_t * JK_METHOD ws_vhost_to_uw_map(void *d)
643 {
644 server_rec *s = (server_rec *)d;
645 jk_server_conf_t *conf = NULL;
646 if (s == NULL)
647 return NULL;
648 conf = (jk_server_conf_t *) ap_get_module_config(s->module_config,
649 &jk_module);
650 return conf->uw_map;
651 }
652
653 /* ========================================================================= */
654 /* Utility functions */
655 /* ========================================================================= */
656
dump_options(server_rec * srv,apr_pool_t * p)657 static void dump_options(server_rec *srv, apr_pool_t *p)
658 {
659 char server_name[80];
660 jk_server_conf_t *conf = (jk_server_conf_t *)ap_get_module_config(srv->module_config,
661 &jk_module);
662 int options = conf->options;
663 ws_vhost_to_text(srv, server_name, 80);
664 if (options & JK_OPT_FWDURICOMPAT)
665 jk_log(conf->log, JK_LOG_DEBUG, "JkOption '%s' set in server '%s'%s",
666 "ForwardURICompat", server_name,
667 JK_OPT_DEFAULT & JK_OPT_FWDURICOMPAT ? " (default)" : "");
668 if (options & JK_OPT_FWDURICOMPATUNPARSED)
669 jk_log(conf->log, JK_LOG_DEBUG, "JkOption '%s' set in server '%s'%s",
670 "ForwardURICompatUnparsed", server_name,
671 JK_OPT_DEFAULT & JK_OPT_FWDURICOMPATUNPARSED ? " (default)" : "");
672 if (options & JK_OPT_FWDURIESCAPED)
673 jk_log(conf->log, JK_LOG_DEBUG, "JkOption '%s' set in server '%s'%s",
674 "ForwardURIEscaped", server_name,
675 JK_OPT_DEFAULT & JK_OPT_FWDURIESCAPED ? " (default)" : "");
676 if (options & JK_OPT_FWDURIPROXY)
677 jk_log(conf->log, JK_LOG_DEBUG, "JkOption '%s' set in server '%s'%s",
678 "ForwardURIProxy", server_name,
679 JK_OPT_DEFAULT & JK_OPT_FWDURIPROXY ? " (default)" : "");
680 if (options & JK_OPT_FWDDIRS)
681 jk_log(conf->log, JK_LOG_DEBUG, "JkOption '%s' set in server '%s'%s",
682 "ForwardDirectories", server_name,
683 JK_OPT_DEFAULT & JK_OPT_FWDDIRS ? " (default)" : "");
684 if (options & JK_OPT_FWDLOCAL)
685 jk_log(conf->log, JK_LOG_DEBUG, "JkOption '%s' set in server '%s'%s",
686 "ForwardLocalAddress", server_name,
687 JK_OPT_DEFAULT & JK_OPT_FWDLOCAL ? " (default)" : "");
688 if (options & JK_OPT_FWDPHYSICAL)
689 jk_log(conf->log, JK_LOG_DEBUG, "JkOption '%s' set in server '%s'%s",
690 "ForwardPhysicalAddress", server_name,
691 JK_OPT_DEFAULT & JK_OPT_FWDPHYSICAL ? " (default)" : "");
692 if (options & JK_OPT_FWDCERTCHAIN)
693 jk_log(conf->log, JK_LOG_DEBUG, "JkOption '%s' set in server '%s'%s",
694 "ForwardSSLCertChain", server_name,
695 JK_OPT_DEFAULT & JK_OPT_FWDCERTCHAIN ? " (default)" : "");
696 if (options & JK_OPT_FWDKEYSIZE)
697 jk_log(conf->log, JK_LOG_DEBUG, "JkOption '%s' set in server '%s'%s",
698 "ForwardKeySize", server_name,
699 JK_OPT_DEFAULT & JK_OPT_FWDKEYSIZE ? " (default)" : "");
700 if (options & JK_OPT_FLUSHPACKETS)
701 jk_log(conf->log, JK_LOG_DEBUG, "JkOption '%s' set in server '%s'%s",
702 "FlushPackets", server_name,
703 JK_OPT_DEFAULT & JK_OPT_FLUSHPACKETS ? " (default)" : "");
704 if (options & JK_OPT_FLUSHEADER)
705 jk_log(conf->log, JK_LOG_DEBUG, "JkOption '%s' set in server '%s'%s",
706 "FlushHeader", server_name,
707 JK_OPT_DEFAULT & JK_OPT_FLUSHEADER ? " (default)" : "");
708 if (options & JK_OPT_DISABLEREUSE)
709 jk_log(conf->log, JK_LOG_DEBUG, "JkOption '%s' set in server '%s'%s",
710 "DisableReuse", server_name,
711 JK_OPT_DEFAULT & JK_OPT_DISABLEREUSE ? " (default)" : "");
712 if (options & JK_OPT_REJECTUNSAFE)
713 jk_log(conf->log, JK_LOG_DEBUG, "JkOption '%s' set in server '%s'%s",
714 "RejectUnsafeURI", server_name,
715 JK_OPT_DEFAULT & JK_OPT_REJECTUNSAFE ? " (default)" : "");
716 }
717
718 /* ========================================================================= */
719 /* Log something to Jk log file then exit */
jk_error_exit(const char * file,int line,int level,const server_rec * s,apr_pool_t * p,const char * fmt,...)720 static void jk_error_exit(const char *file,
721 int line,
722 int level,
723 const server_rec * s,
724 apr_pool_t * p, const char *fmt, ...)
725 {
726 va_list ap;
727 char *res;
728 char *ch;
729
730 va_start(ap, fmt);
731 res = apr_pvsprintf(s->process->pool, fmt, ap);
732 va_end(ap);
733 /* Replace all format characters in the resulting message */
734 /* because we feed the message to ap_log_error(). */
735 ch = res;
736 while (*ch) {
737 if (*ch == '%') {
738 *ch = '#';
739 }
740 ch++;
741 }
742
743 #if (MODULE_MAGIC_NUMBER_MAJOR >= 20100606)
744 ap_log_error(file, line, APLOG_MODULE_INDEX, level, 0, s, "%s", res);
745 #else
746 ap_log_error(file, line, level, 0, s, "%s", res);
747 #endif
748 if ( s ) {
749 #if (MODULE_MAGIC_NUMBER_MAJOR >= 20100606)
750 ap_log_error(file, line, APLOG_MODULE_INDEX, level, 0, NULL, "%s", res);
751 #else
752 ap_log_error(file, line, level, 0, NULL, "%s", res);
753 #endif
754 }
755
756 /* Exit process */
757 exit(1);
758 }
759
get_content_length(request_rec * r)760 static jk_uint64_t get_content_length(request_rec * r)
761 {
762 if (r->main == NULL || r->main == r) {
763 char *lenp = (char *)apr_table_get(r->headers_in, "Content-Length");
764
765 if (lenp) {
766 jk_uint64_t rc = 0;
767 if (sscanf(lenp, "%" JK_UINT64_T_FMT, &rc) > 0 && rc > 0) {
768 return rc;
769 }
770 }
771 }
772
773 return 0;
774 }
775
776 /* Retrieve string value from env var, use default if env var does not exist. */
get_env_string(request_rec * r,const char * def,char * env,int null_for_empty)777 static const char *get_env_string(request_rec *r, const char *def,
778 char *env, int null_for_empty)
779 {
780 char *value = (char *)apr_table_get(r->subprocess_env, env);
781 if (value)
782 return null_for_empty ? NULL_FOR_EMPTY(value) : value;
783 return null_for_empty ? NULL_FOR_EMPTY(def) : def;
784 }
785
786 /* Retrieve integer value from env var, use default if env var does not exist. */
get_env_int(request_rec * r,int def,char * env)787 static int get_env_int(request_rec *r, int def, char *env)
788 {
789 char *value = (char *)apr_table_get(r->subprocess_env, env);
790 if (value)
791 return atoi(value);
792 return def;
793 }
794
init_ws_service(apache_private_data_t * private_data,jk_ws_service_t * s,jk_server_conf_t * conf)795 static int init_ws_service(apache_private_data_t * private_data,
796 jk_ws_service_t *s, jk_server_conf_t * conf)
797 {
798 int size;
799 request_rec *r = private_data->r;
800 char *ssl_temp = NULL;
801 char *uri = NULL;
802 const char *reply_timeout = NULL;
803 const char *sticky_ignore = NULL;
804 const char *stateless = NULL;
805 const char *route = NULL;
806 rule_extension_t *e;
807 jk_request_conf_t *rconf;
808
809 /* Copy in function pointers (which are really methods) */
810 s->start_response = ws_start_response;
811 s->read = ws_read;
812 s->write = ws_write;
813 s->flush = ws_flush;
814 s->done = ws_done;
815 s->add_log_items = ws_add_log_items;
816 s->next_vhost = ws_next_vhost;
817 s->vhost_to_text = ws_vhost_to_text;
818 s->vhost_to_uw_map = ws_vhost_to_uw_map;
819
820 s->auth_type = get_env_string(r, r->ap_auth_type,
821 conf->auth_type_indicator, 1);
822 s->remote_user = get_env_string(r, r->user,
823 conf->remote_user_indicator, 1);
824
825 s->protocol = r->protocol;
826 s->remote_host = (char *)ap_get_remote_host(r->connection,
827 r->per_dir_config,
828 REMOTE_HOST, NULL);
829 s->remote_host = get_env_string(r, s->remote_host,
830 conf->remote_host_indicator, 1);
831 if (conf->options & JK_OPT_FWDLOCAL) {
832 s->remote_addr = r->connection->local_ip;
833 /* We don't know the client port of the backend connection. */
834 s->remote_port = "0";
835 }
836 else {
837 #if (MODULE_MAGIC_NUMBER_MAJOR >= 20111130)
838 if (conf->options & JK_OPT_FWDPHYSICAL) {
839 s->remote_addr = r->connection->client_ip;
840 s->remote_port = apr_itoa(r->pool, r->connection->client_addr->port);
841 } else {
842 s->remote_addr = r->useragent_ip;
843 s->remote_port = apr_itoa(r->pool, r->useragent_addr->port);
844 }
845 #else
846 s->remote_addr = r->connection->remote_ip;
847 s->remote_port = apr_itoa(r->pool, r->connection->remote_addr->port);
848 #endif
849 }
850 s->remote_addr = get_env_string(r, s->remote_addr,
851 conf->remote_addr_indicator, 1);
852 s->remote_port = get_env_string(r, s->remote_port,
853 conf->remote_port_indicator, 1);
854
855 if (conf->options & JK_OPT_FLUSHPACKETS)
856 s->flush_packets = 1;
857 if (conf->options & JK_OPT_FLUSHEADER)
858 s->flush_header = 1;
859
860 rconf = (jk_request_conf_t *)ap_get_module_config(r->request_config, &jk_module);
861
862 e = rconf->rule_extensions;
863 if (e) {
864 s->extension.reply_timeout = e->reply_timeout;
865 s->extension.sticky_ignore = e->sticky_ignore;
866 s->extension.stateless = e->stateless;
867 s->extension.use_server_error_pages = e->use_server_error_pages;
868 if (e->activation) {
869 s->extension.activation = apr_palloc(r->pool, e->activation_size * sizeof(int));
870 memcpy(s->extension.activation, e->activation, e->activation_size * sizeof(int));
871 }
872 if (e->fail_on_status_size > 0) {
873 s->extension.fail_on_status_size = e->fail_on_status_size;
874 s->extension.fail_on_status = apr_palloc(r->pool, e->fail_on_status_size * sizeof(int));
875 memcpy(s->extension.fail_on_status, e->fail_on_status, e->fail_on_status_size * sizeof(int));
876 }
877 if (e->session_cookie) {
878 s->extension.session_cookie = apr_pstrdup(r->pool, e->session_cookie);
879 }
880 if (e->session_path) {
881 s->extension.session_path = apr_pstrdup(r->pool, e->session_path);
882 }
883 if (e->set_session_cookie) {
884 s->extension.set_session_cookie = e->set_session_cookie;
885 }
886 if (e->session_cookie_path) {
887 s->extension.session_cookie_path = apr_pstrdup(r->pool, e->session_cookie_path);
888 }
889 }
890 reply_timeout = apr_table_get(r->subprocess_env, JK_ENV_REPLY_TIMEOUT);
891 if (reply_timeout) {
892 int r = atoi(reply_timeout);
893 if (r >= 0)
894 s->extension.reply_timeout = r;
895 }
896
897 sticky_ignore = apr_table_get(r->subprocess_env, JK_ENV_STICKY_IGNORE);
898 if (sticky_ignore) {
899 if (*sticky_ignore == '\0') {
900 s->extension.sticky_ignore = JK_TRUE;
901 }
902 else {
903 int r = atoi(sticky_ignore);
904 if (r) {
905 s->extension.sticky_ignore = JK_TRUE;
906 }
907 else {
908 s->extension.sticky_ignore = JK_FALSE;
909 }
910 }
911 }
912
913 stateless = apr_table_get(r->subprocess_env, JK_ENV_STATELESS);
914 if (stateless) {
915 if (*stateless == '\0') {
916 s->extension.stateless = JK_TRUE;
917 }
918 else {
919 int r = atoi(stateless);
920 if (r) {
921 s->extension.stateless = JK_TRUE;
922 }
923 else {
924 s->extension.stateless = JK_FALSE;
925 }
926 }
927 }
928
929 if (conf->options & JK_OPT_DISABLEREUSE)
930 s->disable_reuse = 1;
931
932 /* get route if known */
933 route = apr_table_get(r->subprocess_env, JK_ENV_ROUTE);
934 if (route && *route) {
935 s->route = route;
936 }
937
938 /* get server name */
939 s->server_name = get_env_string(r, (char *)ap_get_server_name(r),
940 conf->local_name_indicator, 0);
941
942 /* get the local IP address */
943 s->local_addr = get_env_string(r, r->connection->local_ip,
944 conf->local_addr_indicator, 0);
945
946 /* get the real port (otherwise redirect failed) */
947 /* XXX: use apache API for getting server port
948 *
949 * Pre 1.2.7 versions used:
950 * s->server_port = r->connection->local_addr->port;
951 */
952 s->server_port = get_env_int(r, ap_get_server_port(r),
953 conf->local_port_indicator);
954
955 #if ((AP_MODULE_MAGIC_AT_LEAST(20051115,4)) && !defined(API_COMPATIBILITY)) || (MODULE_MAGIC_NUMBER_MAJOR >= 20060905)
956 s->server_software = (char *)ap_get_server_description();
957 #else
958 s->server_software = (char *)ap_get_server_version();
959 #endif
960 s->method = (char *)r->method;
961 s->content_length = get_content_length(r);
962 s->is_chunked = r->read_chunked;
963 if (s->content_length > 0 &&
964 get_env_string(r, NULL, conf->ignore_cl_indicator, 0) != NULL) {
965 s->content_length = 0;
966 s->is_chunked = 1;
967 }
968 s->no_more_chunks = 0;
969 #if defined(AS400) && !defined(AS400_UTF8)
970 /* Get the query string that is not translated to EBCDIC */
971 s->query_string = ap_get_original_query_string(r);
972 #else
973 s->query_string = r->args;
974 #endif
975
976 /*
977 * The 2.2 servlet spec errata says the uri from
978 * HttpServletRequest.getRequestURI() should remain encoded.
979 * [http://java.sun.com/products/servlet/errata_042700.html]
980 *
981 * We use JkOptions to determine which method to be used
982 *
983 * ap_escape_uri is the latest recommended but require
984 * some java decoding (in TC 3.3 rc2)
985 *
986 * unparsed_uri is used for strict compliance with spec and
987 * old Tomcat (3.2.3 for example)
988 *
989 * uri is use for compatibility with mod_rewrite with old Tomcats
990 */
991
992 uri = rconf->orig_uri ? rconf->orig_uri : r->uri;
993
994 switch (conf->options & JK_OPT_FWDURIMASK) {
995
996 case JK_OPT_FWDURICOMPATUNPARSED:
997 s->req_uri = r->unparsed_uri;
998 if (s->req_uri != NULL) {
999 char *query_str = strchr(s->req_uri, '?');
1000 if (query_str != NULL) {
1001 *query_str = 0;
1002 }
1003 }
1004
1005 break;
1006
1007 case JK_OPT_FWDURICOMPAT:
1008 s->req_uri = uri;
1009 break;
1010
1011 case JK_OPT_FWDURIPROXY:
1012 size = 3 * (int)strlen(uri) + 1;
1013 s->req_uri = apr_palloc(r->pool, size);
1014 jk_canonenc(uri, s->req_uri, size);
1015 break;
1016
1017 case JK_OPT_FWDURIESCAPED:
1018 s->req_uri = ap_escape_uri(r->pool, uri);
1019 break;
1020
1021 default:
1022 return JK_FALSE;
1023 }
1024
1025 if (conf->ssl_enable || conf->envvars) {
1026 ap_add_common_vars(r);
1027
1028 if (conf->ssl_enable) {
1029 ssl_temp =
1030 (char *)apr_table_get(r->subprocess_env,
1031 conf->https_indicator);
1032 if (ssl_temp && !strcasecmp(ssl_temp, "on")) {
1033 s->is_ssl = JK_TRUE;
1034 s->ssl_cert =
1035 (char *)apr_table_get(r->subprocess_env,
1036 conf->certs_indicator);
1037
1038 if (conf->options & JK_OPT_FWDCERTCHAIN) {
1039 const apr_array_header_t *t = apr_table_elts(r->subprocess_env);
1040 if (t && t->nelts) {
1041 int i;
1042 const apr_table_entry_t *elts = (const apr_table_entry_t *) t->elts;
1043 apr_array_header_t *certs = apr_array_make(r->pool, 1, sizeof(char *));
1044 *(const char **)apr_array_push(certs) = s->ssl_cert;
1045 for (i = 0; i < t->nelts; i++) {
1046 if (!elts[i].key)
1047 continue;
1048 if (!strncasecmp(elts[i].key, conf->certchain_prefix,
1049 strlen(conf->certchain_prefix)))
1050 *(const char **)apr_array_push(certs) = elts[i].val;
1051 }
1052 s->ssl_cert = apr_array_pstrcat(r->pool, certs, '\0');
1053 }
1054 }
1055
1056 if (s->ssl_cert) {
1057 s->ssl_cert_len = (unsigned int)strlen(s->ssl_cert);
1058 if (JK_IS_DEBUG_LEVEL(conf->log)) {
1059 jk_log(conf->log, JK_LOG_DEBUG,
1060 "SSL client certificate (%d bytes): %s",
1061 s->ssl_cert_len, s->ssl_cert);
1062 }
1063 }
1064 s->ssl_protocol =
1065 (char *)apr_table_get(r->subprocess_env,
1066 conf->ssl_protocol_indicator);
1067 /* Servlet 2.3 API */
1068 s->ssl_cipher =
1069 (char *)apr_table_get(r->subprocess_env,
1070 conf->cipher_indicator);
1071 s->ssl_session =
1072 (char *)apr_table_get(r->subprocess_env,
1073 conf->session_indicator);
1074
1075 if (conf->options & JK_OPT_FWDKEYSIZE) {
1076 /* Servlet 2.3 API */
1077 ssl_temp = (char *)apr_table_get(r->subprocess_env,
1078 conf->
1079 key_size_indicator);
1080 if (ssl_temp)
1081 s->ssl_key_size = atoi(ssl_temp);
1082 }
1083
1084
1085 }
1086 }
1087
1088 if (conf->envvars) {
1089 const apr_array_header_t *t = conf->envvar_items;
1090 if (t && t->nelts) {
1091 int i;
1092 int j = 0;
1093 envvar_item *elts = (envvar_item *) t->elts;
1094 s->attributes_names = apr_palloc(r->pool,
1095 sizeof(char *) * t->nelts);
1096 s->attributes_values = apr_palloc(r->pool,
1097 sizeof(char *) * t->nelts);
1098
1099 for (i = 0; i < t->nelts; i++) {
1100 s->attributes_names[i - j] = elts[i].name;
1101 s->attributes_values[i - j] =
1102 (char *)apr_table_get(r->subprocess_env, elts[i].name);
1103 if (!s->attributes_values[i - j]) {
1104 if (elts[i].has_default) {
1105 s->attributes_values[i - j] = elts[i].value;
1106 }
1107 else {
1108 s->attributes_values[i - j] = "";
1109 s->attributes_names[i - j] = "";
1110 j++;
1111 }
1112 }
1113 }
1114
1115 s->num_attributes = t->nelts - j;
1116 }
1117 }
1118 }
1119
1120 if (r->headers_in && apr_table_elts(r->headers_in)) {
1121 int need_content_length_header = (!s->is_chunked
1122 && s->content_length ==
1123 0) ? JK_TRUE : JK_FALSE;
1124 const apr_array_header_t *t = apr_table_elts(r->headers_in);
1125 if (t && t->nelts) {
1126 int i;
1127 int off = 0;
1128 apr_table_entry_t *elts = (apr_table_entry_t *) t->elts;
1129 s->num_headers = t->nelts;
1130 /* allocate an extra header slot in case we need to add a content-length header */
1131 s->headers_names =
1132 apr_palloc(r->pool, sizeof(char *) * (t->nelts + 1));
1133 s->headers_values =
1134 apr_palloc(r->pool, sizeof(char *) * (t->nelts + 1));
1135 if (!s->headers_names || !s->headers_values)
1136 return JK_FALSE;
1137 for (i = 0; i < t->nelts; i++) {
1138 char *hname = apr_pstrdup(r->pool, elts[i].key);
1139 if (!strcasecmp(hname, "content-length")) {
1140 if (need_content_length_header) {
1141 need_content_length_header = JK_FALSE;
1142 } else if (s->is_chunked) {
1143 s->num_headers--;
1144 off++;
1145 continue;
1146 }
1147 }
1148 s->headers_values[i - off] = apr_pstrdup(r->pool, elts[i].val);
1149 s->headers_names[i - off] = hname;
1150 }
1151 /* Add a content-length = 0 header if needed.
1152 * Ajp13 assumes an absent content-length header means an unknown,
1153 * but non-zero length body.
1154 */
1155 if (need_content_length_header) {
1156 s->headers_names[s->num_headers] = "content-length";
1157 s->headers_values[s->num_headers] = "0";
1158 s->num_headers++;
1159 }
1160 }
1161 /* Add a content-length = 0 header if needed. */
1162 else if (need_content_length_header) {
1163 s->headers_names = apr_palloc(r->pool, sizeof(char *));
1164 s->headers_values = apr_palloc(r->pool, sizeof(char *));
1165 if (!s->headers_names || !s->headers_values)
1166 return JK_FALSE;
1167 s->headers_names[0] = "content-length";
1168 s->headers_values[0] = "0";
1169 s->num_headers++;
1170 }
1171 }
1172 s->uw_map = conf->uw_map;
1173
1174 /* Dump all connection param so we can trace what's going to
1175 * the remote tomcat
1176 */
1177 if (JK_IS_DEBUG_LEVEL(conf->log)) {
1178 jk_log(conf->log, JK_LOG_DEBUG,
1179 "Service protocol=%s method=%s ssl=%s host=%s addr=%s name=%s port=%d auth=%s user=%s laddr=%s raddr=%s uaddr=%s uri=%s",
1180 STRNULL_FOR_NULL(s->protocol),
1181 STRNULL_FOR_NULL(s->method),
1182 s->is_ssl ? "true" : "false",
1183 STRNULL_FOR_NULL(s->remote_host),
1184 STRNULL_FOR_NULL(s->remote_addr),
1185 STRNULL_FOR_NULL(s->server_name),
1186 s->server_port,
1187 STRNULL_FOR_NULL(s->auth_type),
1188 STRNULL_FOR_NULL(s->remote_user),
1189 STRNULL_FOR_NULL(r->connection->local_ip),
1190 #if (MODULE_MAGIC_NUMBER_MAJOR >= 20111130)
1191 STRNULL_FOR_NULL(r->connection->client_ip),
1192 STRNULL_FOR_NULL(r->useragent_ip),
1193 #else
1194 STRNULL_FOR_NULL(r->connection->remote_ip),
1195 STRNULL_FOR_NULL(r->connection->remote_ip),
1196 #endif
1197 STRNULL_FOR_NULL(s->req_uri));
1198 }
1199
1200 return JK_TRUE;
1201 }
1202
1203 /*
1204 * The JK module command processors
1205 *
1206 * The below are all installed so that Apache calls them while it is
1207 * processing its config files. This allows configuration info to be
1208 * copied into a jk_server_conf_t object, which is then used for request
1209 * filtering/processing.
1210 *
1211 * See jk_cmds definition below for explanations of these options.
1212 */
1213
1214 /*
1215 * JkMountCopy directive handling
1216 *
1217 * JkMountCopy On/Off/All
1218 */
1219
jk_set_mountcopy(cmd_parms * cmd,void * dummy,const char * mount_copy)1220 static const char *jk_set_mountcopy(cmd_parms * cmd,
1221 void *dummy, const char *mount_copy)
1222 {
1223 server_rec *s = cmd->server;
1224 jk_server_conf_t *conf =
1225 (jk_server_conf_t *) ap_get_module_config(s->module_config,
1226 &jk_module);
1227
1228 if (! strcasecmp(mount_copy, "all")) {
1229 const char *err_string = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1230 if (err_string != NULL) {
1231 return err_string;
1232 }
1233 jk_mount_copy_all = JK_TRUE;
1234 }
1235 else if (strcasecmp(mount_copy, "on") && strcasecmp(mount_copy, "off")) {
1236 return "JkMountCopy must be All, On or Off";
1237 }
1238 else {
1239 conf->mountcopy = strcasecmp(mount_copy, "off") ? JK_TRUE : JK_FALSE;
1240 }
1241
1242 return NULL;
1243 }
1244
1245 /*
1246 * JkMount directive handling
1247 *
1248 * JkMount URI(context) worker
1249 */
1250
jk_mount_context(cmd_parms * cmd,void * dummy,const char * context,const char * worker)1251 static const char *jk_mount_context(cmd_parms * cmd,
1252 void *dummy,
1253 const char *context,
1254 const char *worker)
1255 {
1256 server_rec *s = cmd->server;
1257 jk_server_conf_t *conf =
1258 (jk_server_conf_t *) ap_get_module_config(s->module_config,
1259 &jk_module);
1260 const char *c, *w;
1261
1262 if (worker != NULL && cmd->path == NULL ) {
1263 c = context;
1264 w = worker;
1265 }
1266 else if (worker == NULL && cmd->path != NULL) {
1267 c = cmd->path;
1268 w = context;
1269 }
1270 else {
1271 if (worker == NULL)
1272 return "JkMount needs a path when not defined in a location";
1273 else
1274 return "JkMount can not have a path when defined in a location";
1275 }
1276
1277 if (c[0] != '/')
1278 return "JkMount context should start with /";
1279
1280 if (!conf->uri_to_context) {
1281 if (!jk_map_alloc(&(conf->uri_to_context))) {
1282 return "JkMount Memory error";
1283 }
1284 }
1285 /*
1286 * Add the new worker to the alias map.
1287 */
1288 jk_map_put(conf->uri_to_context, c, w, NULL);
1289 return NULL;
1290 }
1291
1292 /*
1293 * JkUnMount directive handling
1294 *
1295 * JkUnMount URI(context) worker
1296 */
1297
jk_unmount_context(cmd_parms * cmd,void * dummy,const char * context,const char * worker)1298 static const char *jk_unmount_context(cmd_parms * cmd,
1299 void *dummy,
1300 const char *context,
1301 const char *worker)
1302 {
1303 server_rec *s = cmd->server;
1304 jk_server_conf_t *conf =
1305 (jk_server_conf_t *) ap_get_module_config(s->module_config,
1306 &jk_module);
1307 char *uri;
1308 const char *c, *w;
1309
1310 if (worker != NULL && cmd->path == NULL ) {
1311 c = context;
1312 w = worker;
1313 }
1314 else if (worker == NULL && cmd->path != NULL) {
1315 c = cmd->path;
1316 w = context;
1317 }
1318 else {
1319 if (worker == NULL)
1320 return "JkUnMount needs a path when not defined in a location";
1321 else
1322 return "JkUnMount can not have a path when defined in a location";
1323 }
1324
1325 if (c[0] != '/')
1326 return "JkUnMount context should start with /";
1327
1328 uri = apr_pstrcat(cmd->temp_pool, "!", c, NULL);
1329
1330 if (!conf->uri_to_context) {
1331 if (!jk_map_alloc(&(conf->uri_to_context))) {
1332 return "JkUnMount Memory error";
1333 }
1334 }
1335 /*
1336 * Add the new worker to the alias map.
1337 */
1338 jk_map_put(conf->uri_to_context, uri, w, NULL);
1339 return NULL;
1340 }
1341
1342
1343 /*
1344 * JkWorkersFile Directive Handling
1345 *
1346 * JkWorkersFile file
1347 */
1348
jk_set_worker_file(cmd_parms * cmd,void * dummy,const char * worker_file)1349 static const char *jk_set_worker_file(cmd_parms * cmd,
1350 void *dummy, const char *worker_file)
1351 {
1352 const char *err_string = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1353 if (err_string != NULL) {
1354 return err_string;
1355 }
1356
1357 if (jk_worker_file != NULL)
1358 return "JkWorkersFile only allowed once";
1359
1360 /* we need an absolute path (ap_server_root_relative does the ap_pstrdup) */
1361 jk_worker_file = ap_server_root_relative(cmd->pool, worker_file);
1362
1363 if (jk_worker_file == NULL)
1364 return "JkWorkersFile file name invalid";
1365
1366 if (jk_file_exists(jk_worker_file) != JK_TRUE)
1367 return "JkWorkersFile: Can't find the workers file specified";
1368
1369 return NULL;
1370 }
1371
1372 /*
1373 * JkMountFile Directive Handling
1374 *
1375 * JkMountFile file
1376 */
1377
jk_set_mount_file(cmd_parms * cmd,void * dummy,const char * mount_file)1378 static const char *jk_set_mount_file(cmd_parms * cmd,
1379 void *dummy, const char *mount_file)
1380 {
1381 server_rec *s = cmd->server;
1382
1383 jk_server_conf_t *conf =
1384 (jk_server_conf_t *) ap_get_module_config(s->module_config,
1385 &jk_module);
1386
1387 /* we need an absolute path (ap_server_root_relative does the ap_pstrdup) */
1388 conf->mount_file = ap_server_root_relative(cmd->pool, mount_file);
1389
1390 if (conf->mount_file == NULL)
1391 return "JkMountFile file name invalid";
1392
1393 if (jk_file_exists(conf->mount_file) != JK_TRUE)
1394 return "JkMountFile: Can't find the mount file specified";
1395
1396 if (!conf->uri_to_context) {
1397 if (!jk_map_alloc(&(conf->uri_to_context))) {
1398 return "JkMountFile Memory error";
1399 }
1400 }
1401
1402 return NULL;
1403 }
1404
1405 /*
1406 * JkMountFileReload Directive Handling
1407 *
1408 * JkMountFileReload seconds
1409 */
1410
jk_set_mount_file_reload(cmd_parms * cmd,void * dummy,const char * mount_file_reload)1411 static const char *jk_set_mount_file_reload(cmd_parms * cmd,
1412 void *dummy, const char *mount_file_reload)
1413 {
1414 server_rec *s = cmd->server;
1415 int interval;
1416
1417 jk_server_conf_t *conf =
1418 (jk_server_conf_t *) ap_get_module_config(s->module_config,
1419 &jk_module);
1420
1421 interval = atoi(mount_file_reload);
1422 if (interval < 0) {
1423 interval = 0;
1424 }
1425
1426 conf->mount_file_reload = interval;
1427
1428 return NULL;
1429 }
1430
1431 /*
1432 * JkWatchdogInterval Directive Handling
1433 *
1434 * JkWatchdogInterval seconds
1435 */
1436
jk_set_watchdog_interval(cmd_parms * cmd,void * dummy,const char * watchdog_interval)1437 static const char *jk_set_watchdog_interval(cmd_parms * cmd,
1438 void *dummy, const char *watchdog_interval)
1439 {
1440 const char *err_string = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1441 if (err_string != NULL) {
1442 return err_string;
1443 }
1444
1445 #if APR_HAS_THREADS
1446 jk_watchdog_interval = atoi(watchdog_interval);
1447 if (jk_watchdog_interval < 0) {
1448 jk_watchdog_interval = 0;
1449 }
1450 return NULL;
1451 #else
1452 return "JkWatchdogInterval: APR was compiled without threading support. Cannot create watchdog thread";
1453 #endif
1454 }
1455
1456 /*
1457 * JkLogFile Directive Handling
1458 *
1459 * JkLogFile file
1460 */
1461
jk_set_log_file(cmd_parms * cmd,void * dummy,const char * log_file)1462 static const char *jk_set_log_file(cmd_parms * cmd,
1463 void *dummy, const char *log_file)
1464 {
1465 server_rec *s = cmd->server;
1466 jk_server_conf_t *conf =
1467 (jk_server_conf_t *) ap_get_module_config(s->module_config,
1468 &jk_module);
1469
1470 /* we need an absolute path */
1471 if (*log_file != '|')
1472 conf->log_file = ap_server_root_relative(cmd->pool, log_file);
1473 else
1474 conf->log_file = apr_pstrdup(cmd->pool, log_file);
1475
1476 if (conf->log_file == NULL)
1477 return "JkLogFile file name invalid";
1478
1479 return NULL;
1480 }
1481
1482 /*
1483 * JkShmFile Directive Handling
1484 *
1485 * JkShmFile file
1486 */
1487
jk_set_shm_file(cmd_parms * cmd,void * dummy,const char * shm_file)1488 static const char *jk_set_shm_file(cmd_parms * cmd,
1489 void *dummy, const char *shm_file)
1490 {
1491 const char *err_string = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1492 if (err_string != NULL) {
1493 return err_string;
1494 }
1495
1496 /* we need an absolute path */
1497 jk_shm_file = ap_server_root_relative(cmd->pool, shm_file);
1498 if (jk_shm_file == NULL)
1499 return "JkShmFile file name invalid";
1500
1501 return NULL;
1502 }
1503
1504 /*
1505 * JkShmSize Directive Handling
1506 *
1507 * JkShmSize size in kilobytes
1508 */
1509
jk_set_shm_size(cmd_parms * cmd,void * dummy,const char * shm_size)1510 static const char *jk_set_shm_size(cmd_parms * cmd,
1511 void *dummy, const char *shm_size)
1512 {
1513 int sz = 0;
1514 const char *err_string = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1515 if (err_string != NULL) {
1516 return err_string;
1517 }
1518
1519 sz = atoi(shm_size) * 1024;
1520 if (sz < JK_SHM_MIN_SIZE)
1521 sz = JK_SHM_MIN_SIZE;
1522 else
1523 sz = JK_SHM_ALIGN(sz);
1524 jk_shm_size = sz;
1525 if (jk_shm_size)
1526 jk_shm_size_set = 1;
1527 return NULL;
1528 }
1529
1530 /*
1531 * JkLogLevel Directive Handling
1532 *
1533 * JkLogLevel debug/info/error/emerg
1534 */
1535
jk_set_log_level(cmd_parms * cmd,void * dummy,const char * log_level)1536 static const char *jk_set_log_level(cmd_parms * cmd,
1537 void *dummy, const char *log_level)
1538 {
1539 server_rec *s = cmd->server;
1540 jk_server_conf_t *conf =
1541 (jk_server_conf_t *) ap_get_module_config(s->module_config,
1542 &jk_module);
1543
1544 conf->log_level = jk_parse_log_level(log_level);
1545
1546 return NULL;
1547 }
1548
1549 /*
1550 * JkLogStampFormat Directive Handling
1551 *
1552 * JkLogStampFormat "[%a %b %d %H:%M:%S %Y] "
1553 */
1554
jk_set_log_fmt(cmd_parms * cmd,void * dummy,const char * log_format)1555 static const char *jk_set_log_fmt(cmd_parms * cmd,
1556 void *dummy, const char *log_format)
1557 {
1558 server_rec *s = cmd->server;
1559 jk_server_conf_t *conf =
1560 (jk_server_conf_t *) ap_get_module_config(s->module_config,
1561 &jk_module);
1562
1563 conf->stamp_format_string = apr_pstrdup(cmd->pool, log_format);
1564
1565 return NULL;
1566 }
1567
1568
1569 /*
1570 * JkAutoAlias Directive Handling
1571 *
1572 * JkAutoAlias application directory
1573 */
1574
jk_set_auto_alias(cmd_parms * cmd,void * dummy,const char * directory)1575 static const char *jk_set_auto_alias(cmd_parms * cmd,
1576 void *dummy, const char *directory)
1577 {
1578 server_rec *s = cmd->server;
1579 jk_server_conf_t *conf =
1580 (jk_server_conf_t *) ap_get_module_config(s->module_config,
1581 &jk_module);
1582
1583 conf->alias_dir = apr_pstrdup(cmd->pool, directory);
1584
1585 if (conf->alias_dir == NULL)
1586 return "JkAutoAlias directory invalid";
1587
1588 return NULL;
1589 }
1590
1591 /*
1592 * JkStripSession directive handling
1593 *
1594 * JkStripSession On/Off [session path identifier]
1595 */
1596
jk_set_strip_session(cmd_parms * cmd,void * dummy,const char * flag,const char * name)1597 static const char *jk_set_strip_session(cmd_parms * cmd, void *dummy,
1598 const char *flag, const char *name)
1599 {
1600 server_rec *s = cmd->server;
1601 jk_server_conf_t *conf =
1602 (jk_server_conf_t *) ap_get_module_config(s->module_config,
1603 &jk_module);
1604
1605 if (strcasecmp(flag, "on") && strcasecmp(flag, "off")) {
1606 return "JkStripSession must be On or Off";
1607 }
1608 else {
1609 conf->strip_session = strcasecmp(flag, "off") ? JK_TRUE : JK_FALSE;
1610 }
1611
1612 /* Check for optional path value */
1613 if (name)
1614 conf->strip_session_name = apr_pstrdup(cmd->pool, name);
1615 else
1616 conf->strip_session_name = apr_pstrdup(cmd->pool, JK_PATH_SESSION_IDENTIFIER);
1617
1618 return NULL;
1619 }
1620
1621 /*****************************************************************
1622 *
1623 * Actually logging.
1624 */
1625
1626 typedef const char *(*item_key_func) (request_rec *, char *);
1627
1628 typedef struct
1629 {
1630 item_key_func func;
1631 char *arg;
1632 } request_log_format_item;
1633
process_item(request_rec * r,request_log_format_item * item)1634 static const char *process_item(request_rec * r,
1635 request_log_format_item * item)
1636 {
1637 const char *cp;
1638
1639 cp = (*item->func) (r, item->arg);
1640 return cp ? cp : "-";
1641 }
1642
request_log_transaction(request_rec * r)1643 static int request_log_transaction(request_rec * r)
1644 {
1645 request_log_format_item *items;
1646 char *str, *s;
1647 int i;
1648 int len = 0;
1649 const char **strs;
1650 int *strl;
1651 jk_server_conf_t *conf;
1652 jk_request_conf_t *rconf;
1653 apr_array_header_t *format;
1654
1655 conf = (jk_server_conf_t *) ap_get_module_config(r->server->module_config,
1656 &jk_module);
1657 format = conf->format;
1658 if (format == NULL) {
1659 return DECLINED;
1660 }
1661 rconf = (jk_request_conf_t *)ap_get_module_config(r->request_config,
1662 &jk_module);
1663 if (rconf == NULL || rconf->jk_handled == JK_FALSE) {
1664 return DECLINED;
1665 }
1666
1667 strs = apr_palloc(r->pool, sizeof(char *) * (format->nelts));
1668 strl = apr_palloc(r->pool, sizeof(int) * (format->nelts));
1669 items = (request_log_format_item *) format->elts;
1670 for (i = 0; i < format->nelts; ++i) {
1671 strs[i] = process_item(r, &items[i]);
1672 }
1673 for (i = 0; i < format->nelts; ++i) {
1674 len += strl[i] = (int)strlen(strs[i]);
1675 }
1676 str = apr_palloc(r->pool, len + 1);
1677 for (i = 0, s = str; i < format->nelts; ++i) {
1678 memcpy(s, strs[i], strl[i]);
1679 s += strl[i];
1680 }
1681 *s = 0;
1682
1683 jk_log(conf->log, JK_LOG_REQUEST, "%s", str);
1684 return OK;
1685
1686 }
1687
1688 /*****************************************************************
1689 *
1690 * Parsing the log format string
1691 */
1692
format_integer(apr_pool_t * p,int i)1693 static char *format_integer(apr_pool_t * p, int i)
1694 {
1695 return apr_psprintf(p, "%d", i);
1696 }
1697
pfmt(apr_pool_t * p,int i)1698 static char *pfmt(apr_pool_t * p, int i)
1699 {
1700 if (i <= 0) {
1701 return "-";
1702 }
1703 else {
1704 return format_integer(p, i);
1705 }
1706 }
1707
constant_item(request_rec * dummy,char * stuff)1708 static const char *constant_item(request_rec * dummy, char *stuff)
1709 {
1710 return stuff;
1711 }
1712
log_worker_name(request_rec * r,char * a)1713 static const char *log_worker_name(request_rec * r, char *a)
1714 {
1715 return apr_table_get(r->notes, JK_NOTE_WORKER_NAME);
1716 }
1717
log_worker_route(request_rec * r,char * a)1718 static const char *log_worker_route(request_rec * r, char *a)
1719 {
1720 return apr_table_get(r->notes, JK_NOTE_WORKER_ROUTE);
1721 }
1722
1723
log_request_duration(request_rec * r,char * a)1724 static const char *log_request_duration(request_rec * r, char *a)
1725 {
1726 return apr_table_get(r->notes, JK_NOTE_REQUEST_DURATION);
1727 }
1728
log_request_line(request_rec * r,char * a)1729 static const char *log_request_line(request_rec * r, char *a)
1730 {
1731 /* NOTE: If the original request contained a password, we
1732 * re-write the request line here to contain XXXXXX instead:
1733 * (note the truncation before the protocol string for HTTP/0.9 requests)
1734 * (note also that r->the_request contains the unmodified request)
1735 */
1736 return (r->parsed_uri.password) ? apr_pstrcat(r->pool, r->method, " ",
1737 apr_uri_unparse(r->pool,
1738 &r->
1739 parsed_uri,
1740 0),
1741 r->
1742 assbackwards ? NULL : " ",
1743 r->protocol, NULL)
1744 : r->the_request;
1745 }
1746
1747 /* These next two routines use the canonical name:port so that log
1748 * parsers don't need to duplicate all the vhost parsing crud.
1749 */
log_virtual_host(request_rec * r,char * a)1750 static const char *log_virtual_host(request_rec * r, char *a)
1751 {
1752 return r->server->server_hostname;
1753 }
1754
log_server_port(request_rec * r,char * a)1755 static const char *log_server_port(request_rec * r, char *a)
1756 {
1757 return apr_psprintf(r->pool, "%u",
1758 r->server->port ? r->server->
1759 port : ap_default_port(r));
1760 }
1761
1762 /* This respects the setting of UseCanonicalName so that
1763 * the dynamic mass virtual hosting trick works better.
1764 */
log_server_name(request_rec * r,char * a)1765 static const char *log_server_name(request_rec * r, char *a)
1766 {
1767 return ap_get_server_name(r);
1768 }
1769
log_request_uri(request_rec * r,char * a)1770 static const char *log_request_uri(request_rec * r, char *a)
1771 {
1772 return r->uri;
1773 }
log_request_method(request_rec * r,char * a)1774 static const char *log_request_method(request_rec * r, char *a)
1775 {
1776 return r->method;
1777 }
1778
log_request_protocol(request_rec * r,char * a)1779 static const char *log_request_protocol(request_rec * r, char *a)
1780 {
1781 return r->protocol;
1782 }
log_request_query(request_rec * r,char * a)1783 static const char *log_request_query(request_rec * r, char *a)
1784 {
1785 return (r->args != NULL) ? apr_pstrcat(r->pool, "?", r->args, NULL)
1786 : "";
1787 }
log_status(request_rec * r,char * a)1788 static const char *log_status(request_rec * r, char *a)
1789 {
1790 return pfmt(r->pool, r->status);
1791 }
1792
clf_log_bytes_sent(request_rec * r,char * a)1793 static const char *clf_log_bytes_sent(request_rec * r, char *a)
1794 {
1795 if (!r->sent_bodyct) {
1796 return "-";
1797 }
1798 else {
1799 return apr_off_t_toa(r->pool, r->bytes_sent);
1800 }
1801 }
1802
log_bytes_sent(request_rec * r,char * a)1803 static const char *log_bytes_sent(request_rec * r, char *a)
1804 {
1805 if (!r->sent_bodyct) {
1806 return "0";
1807 }
1808 else {
1809 return apr_psprintf(r->pool, "%" APR_OFF_T_FMT, r->bytes_sent);
1810 }
1811 }
1812
1813 static struct log_item_list
1814 {
1815 char ch;
1816 item_key_func func;
1817 } log_item_keys[] = {
1818 { 'T', log_request_duration },
1819 { 'r', log_request_line },
1820 { 'U', log_request_uri },
1821 { 's', log_status },
1822 { 'b', clf_log_bytes_sent },
1823 { 'B', log_bytes_sent },
1824 { 'V', log_server_name },
1825 { 'v', log_virtual_host },
1826 { 'p', log_server_port },
1827 { 'H', log_request_protocol },
1828 { 'm', log_request_method },
1829 { 'q', log_request_query },
1830 { 'w', log_worker_name },
1831 { 'R', log_worker_route},
1832 { '\0', NULL }
1833 };
1834
find_log_func(char k)1835 static struct log_item_list *find_log_func(char k)
1836 {
1837 int i;
1838
1839 for (i = 0; log_item_keys[i].ch; ++i)
1840 if (k == log_item_keys[i].ch) {
1841 return &log_item_keys[i];
1842 }
1843
1844 return NULL;
1845 }
1846
parse_request_log_misc_string(apr_pool_t * p,request_log_format_item * it,const char ** sa)1847 static char *parse_request_log_misc_string(apr_pool_t * p,
1848 request_log_format_item * it,
1849 const char **sa)
1850 {
1851 const char *s;
1852 char *d;
1853
1854 it->func = constant_item;
1855
1856 s = *sa;
1857 while (*s && *s != '%') {
1858 s++;
1859 }
1860 /*
1861 * This might allocate a few chars extra if there's a backslash
1862 * escape in the format string.
1863 */
1864 it->arg = apr_palloc(p, s - *sa + 1);
1865
1866 d = it->arg;
1867 s = *sa;
1868 while (*s && *s != '%') {
1869 if (*s != '\\') {
1870 *d++ = *s++;
1871 }
1872 else {
1873 s++;
1874 switch (*s) {
1875 case '\\':
1876 *d++ = '\\';
1877 s++;
1878 break;
1879 case 'n':
1880 *d++ = '\n';
1881 s++;
1882 break;
1883 case 't':
1884 *d++ = '\t';
1885 s++;
1886 break;
1887 default:
1888 /* copy verbatim */
1889 *d++ = '\\';
1890 /*
1891 * Allow the loop to deal with this *s in the normal
1892 * fashion so that it handles end of string etc.
1893 * properly.
1894 */
1895 break;
1896 }
1897 }
1898 }
1899 *d = '\0';
1900
1901 *sa = s;
1902 return NULL;
1903 }
1904
parse_request_log_item(apr_pool_t * p,request_log_format_item * it,const char ** sa)1905 static char *parse_request_log_item(apr_pool_t * p,
1906 request_log_format_item * it,
1907 const char **sa)
1908 {
1909 const char *s = *sa;
1910 struct log_item_list *l;
1911
1912 if (*s != '%') {
1913 return parse_request_log_misc_string(p, it, sa);
1914 }
1915
1916 ++s;
1917 it->arg = ""; /* For safety's sake... */
1918
1919 l = find_log_func(*s++);
1920 if (!l) {
1921 char dummy[2];
1922
1923 dummy[0] = s[-1];
1924 dummy[1] = '\0';
1925 return apr_pstrcat(p, "Unrecognized JkRequestLogFormat directive %",
1926 dummy, NULL);
1927 }
1928 it->func = l->func;
1929 *sa = s;
1930 return NULL;
1931 }
1932
parse_request_log_string(apr_pool_t * p,const char * s,const char ** err)1933 static apr_array_header_t *parse_request_log_string(apr_pool_t * p,
1934 const char *s,
1935 const char **err)
1936 {
1937 apr_array_header_t *a =
1938 apr_array_make(p, 0, sizeof(request_log_format_item));
1939 char *res;
1940
1941 while (*s) {
1942 if ((res =
1943 parse_request_log_item(p,
1944 (request_log_format_item *)
1945 apr_array_push(a), &s))) {
1946 *err = res;
1947 return NULL;
1948 }
1949 }
1950
1951 return a;
1952 }
1953
1954 /*
1955 * JkRequestLogFormat Directive Handling
1956 *
1957 * JkRequestLogFormat format string
1958 *
1959 * %b - Bytes sent, excluding HTTP headers. In CLF format
1960 * %B - Bytes sent, excluding HTTP headers.
1961 * %H - The request protocol
1962 * %m - The request method
1963 * %p - The canonical Port of the server serving the request
1964 * %q - The query string (prepended with a ? if a query string exists,
1965 * otherwise an empty string)
1966 * %r - First line of request
1967 * %s - request HTTP status code
1968 * %T - Request duration, elapsed time to handle request in seconds '.' micro seconds
1969 * %U - The URL path requested, not including any query string.
1970 * %v - The canonical ServerName of the server serving the request.
1971 * %V - The server name according to the UseCanonicalName setting.
1972 * %w - Tomcat worker name
1973 */
1974
jk_set_request_log_format(cmd_parms * cmd,void * dummy,const char * format)1975 static const char *jk_set_request_log_format(cmd_parms * cmd,
1976 void *dummy, const char *format)
1977 {
1978 server_rec *s = cmd->server;
1979 jk_server_conf_t *conf =
1980 (jk_server_conf_t *) ap_get_module_config(s->module_config,
1981 &jk_module);
1982
1983 conf->format_string = apr_pstrdup(cmd->pool, format);
1984
1985 return NULL;
1986 }
1987
1988
1989 /*
1990 * JkWorkerIndicator Directive Handling
1991 *
1992 * JkWorkerIndicator JkWorker
1993 */
1994
jk_set_worker_indicator(cmd_parms * cmd,void * dummy,const char * indicator)1995 static const char *jk_set_worker_indicator(cmd_parms * cmd,
1996 void *dummy, const char *indicator)
1997 {
1998 server_rec *s = cmd->server;
1999 jk_server_conf_t *conf =
2000 (jk_server_conf_t *) ap_get_module_config(s->module_config,
2001 &jk_module);
2002
2003 conf->worker_indicator = apr_pstrdup(cmd->pool, indicator);
2004
2005 return NULL;
2006 }
2007
2008 /*
2009 * Directives Handling for setting various environment names
2010 * used to overwrite the following request information:
2011 * - remote_addr
2012 * - remote_port
2013 * - remote_host
2014 * - remote_user
2015 * - auth_type
2016 * - server_name
2017 * - server_port
2018 */
jk_set_remote_addr_indicator(cmd_parms * cmd,void * dummy,const char * indicator)2019 static const char *jk_set_remote_addr_indicator(cmd_parms * cmd,
2020 void *dummy, const char *indicator)
2021 {
2022 server_rec *s = cmd->server;
2023 jk_server_conf_t *conf =
2024 (jk_server_conf_t *) ap_get_module_config(s->module_config, &jk_module);
2025 conf->remote_addr_indicator = apr_pstrdup(cmd->pool, indicator);
2026 return NULL;
2027 }
2028
jk_set_remote_port_indicator(cmd_parms * cmd,void * dummy,const char * indicator)2029 static const char *jk_set_remote_port_indicator(cmd_parms * cmd,
2030 void *dummy, const char *indicator)
2031 {
2032 server_rec *s = cmd->server;
2033 jk_server_conf_t *conf =
2034 (jk_server_conf_t *) ap_get_module_config(s->module_config, &jk_module);
2035 conf->remote_port_indicator = apr_pstrdup(cmd->pool, indicator);
2036 return NULL;
2037 }
2038
jk_set_remote_host_indicator(cmd_parms * cmd,void * dummy,const char * indicator)2039 static const char *jk_set_remote_host_indicator(cmd_parms * cmd,
2040 void *dummy, const char *indicator)
2041 {
2042 server_rec *s = cmd->server;
2043 jk_server_conf_t *conf =
2044 (jk_server_conf_t *) ap_get_module_config(s->module_config, &jk_module);
2045 conf->remote_host_indicator = apr_pstrdup(cmd->pool, indicator);
2046 return NULL;
2047 }
2048
jk_set_remote_user_indicator(cmd_parms * cmd,void * dummy,const char * indicator)2049 static const char *jk_set_remote_user_indicator(cmd_parms * cmd,
2050 void *dummy, const char *indicator)
2051 {
2052 server_rec *s = cmd->server;
2053 jk_server_conf_t *conf =
2054 (jk_server_conf_t *) ap_get_module_config(s->module_config, &jk_module);
2055 conf->remote_user_indicator = apr_pstrdup(cmd->pool, indicator);
2056 return NULL;
2057 }
2058
jk_set_auth_type_indicator(cmd_parms * cmd,void * dummy,const char * indicator)2059 static const char *jk_set_auth_type_indicator(cmd_parms * cmd,
2060 void *dummy, const char *indicator)
2061 {
2062 server_rec *s = cmd->server;
2063 jk_server_conf_t *conf =
2064 (jk_server_conf_t *) ap_get_module_config(s->module_config, &jk_module);
2065 conf->auth_type_indicator = apr_pstrdup(cmd->pool, indicator);
2066 return NULL;
2067 }
2068
jk_set_local_name_indicator(cmd_parms * cmd,void * dummy,const char * indicator)2069 static const char *jk_set_local_name_indicator(cmd_parms * cmd,
2070 void *dummy, const char *indicator)
2071 {
2072 server_rec *s = cmd->server;
2073 jk_server_conf_t *conf =
2074 (jk_server_conf_t *) ap_get_module_config(s->module_config, &jk_module);
2075 conf->local_name_indicator = apr_pstrdup(cmd->pool, indicator);
2076 return NULL;
2077 }
2078
jk_set_local_addr_indicator(cmd_parms * cmd,void * dummy,const char * indicator)2079 static const char *jk_set_local_addr_indicator(cmd_parms * cmd,
2080 void *dummy, const char *indicator)
2081 {
2082 server_rec *s = cmd->server;
2083 jk_server_conf_t *conf =
2084 (jk_server_conf_t *) ap_get_module_config(s->module_config, &jk_module);
2085 conf->local_addr_indicator = apr_pstrdup(cmd->pool, indicator);
2086 return NULL;
2087 }
2088
jk_set_local_port_indicator(cmd_parms * cmd,void * dummy,const char * indicator)2089 static const char *jk_set_local_port_indicator(cmd_parms * cmd,
2090 void *dummy, const char *indicator)
2091 {
2092 server_rec *s = cmd->server;
2093 jk_server_conf_t *conf =
2094 (jk_server_conf_t *) ap_get_module_config(s->module_config, &jk_module);
2095 conf->local_port_indicator = apr_pstrdup(cmd->pool, indicator);
2096 return NULL;
2097 }
2098
jk_set_ignore_cl_indicator(cmd_parms * cmd,void * dummy,const char * indicator)2099 static const char *jk_set_ignore_cl_indicator(cmd_parms * cmd,
2100 void *dummy, const char *indicator)
2101 {
2102 server_rec *s = cmd->server;
2103 jk_server_conf_t *conf =
2104 (jk_server_conf_t *) ap_get_module_config(s->module_config, &jk_module);
2105 conf->ignore_cl_indicator = apr_pstrdup(cmd->pool, indicator);
2106 return NULL;
2107 }
2108
2109 /*
2110 * JkExtractSSL Directive Handling
2111 *
2112 * JkExtractSSL On/Off
2113 */
2114
jk_set_enable_ssl(cmd_parms * cmd,void * dummy,int flag)2115 static const char *jk_set_enable_ssl(cmd_parms * cmd, void *dummy, int flag)
2116 {
2117 server_rec *s = cmd->server;
2118 jk_server_conf_t *conf =
2119 (jk_server_conf_t *) ap_get_module_config(s->module_config,
2120 &jk_module);
2121
2122 /* Set up our value */
2123 conf->ssl_enable = flag ? JK_TRUE : JK_FALSE;
2124
2125 return NULL;
2126 }
2127
2128 /*
2129 * JkHTTPSIndicator Directive Handling
2130 *
2131 * JkHTTPSIndicator HTTPS
2132 */
2133
jk_set_https_indicator(cmd_parms * cmd,void * dummy,const char * indicator)2134 static const char *jk_set_https_indicator(cmd_parms * cmd,
2135 void *dummy, const char *indicator)
2136 {
2137 server_rec *s = cmd->server;
2138 jk_server_conf_t *conf =
2139 (jk_server_conf_t *) ap_get_module_config(s->module_config,
2140 &jk_module);
2141
2142 conf->https_indicator = apr_pstrdup(cmd->pool, indicator);
2143
2144 return NULL;
2145 }
2146
2147 /*
2148 * JkSSLPROTOCOLIndicator Directive Handling
2149 *
2150 * JkSSLPROTOCOLIndicator SSL_PROTOCOL
2151 */
2152
jk_set_ssl_protocol_indicator(cmd_parms * cmd,void * dummy,const char * indicator)2153 static const char *jk_set_ssl_protocol_indicator(cmd_parms * cmd,
2154 void *dummy, const char *indicator)
2155 {
2156 server_rec *s = cmd->server;
2157 jk_server_conf_t *conf =
2158 (jk_server_conf_t *) ap_get_module_config(s->module_config,
2159 &jk_module);
2160
2161 conf->ssl_protocol_indicator = apr_pstrdup(cmd->pool, indicator);
2162
2163 return NULL;
2164 }
2165
2166 /*
2167 * JkCERTSIndicator Directive Handling
2168 *
2169 * JkCERTSIndicator SSL_CLIENT_CERT
2170 */
2171
jk_set_certs_indicator(cmd_parms * cmd,void * dummy,const char * indicator)2172 static const char *jk_set_certs_indicator(cmd_parms * cmd,
2173 void *dummy, const char *indicator)
2174 {
2175 server_rec *s = cmd->server;
2176 jk_server_conf_t *conf =
2177 (jk_server_conf_t *) ap_get_module_config(s->module_config,
2178 &jk_module);
2179
2180 conf->certs_indicator = apr_pstrdup(cmd->pool, indicator);
2181
2182 return NULL;
2183 }
2184
2185 /*
2186 * JkCIPHERIndicator Directive Handling
2187 *
2188 * JkCIPHERIndicator SSL_CIPHER
2189 */
2190
jk_set_cipher_indicator(cmd_parms * cmd,void * dummy,const char * indicator)2191 static const char *jk_set_cipher_indicator(cmd_parms * cmd,
2192 void *dummy, const char *indicator)
2193 {
2194 server_rec *s = cmd->server;
2195 jk_server_conf_t *conf =
2196 (jk_server_conf_t *) ap_get_module_config(s->module_config,
2197 &jk_module);
2198
2199 conf->cipher_indicator = apr_pstrdup(cmd->pool, indicator);
2200
2201 return NULL;
2202 }
2203
2204 /*
2205 * JkCERTCHAINPrefix Directive Handling
2206 *
2207 * JkCERTCHAINPrefix SSL_CLIENT_CERT_CHAIN_
2208 */
2209
jk_set_certchain_prefix(cmd_parms * cmd,void * dummy,const char * prefix)2210 static const char *jk_set_certchain_prefix(cmd_parms * cmd,
2211 void *dummy, const char *prefix)
2212 {
2213 server_rec *s = cmd->server;
2214 jk_server_conf_t *conf =
2215 (jk_server_conf_t *) ap_get_module_config(s->module_config,
2216 &jk_module);
2217
2218 conf->certchain_prefix = apr_pstrdup(cmd->pool, prefix);
2219
2220 return NULL;
2221 }
2222
2223 /*
2224 * JkSESSIONIndicator Directive Handling
2225 *
2226 * JkSESSIONIndicator SSL_SESSION_ID
2227 */
2228
jk_set_session_indicator(cmd_parms * cmd,void * dummy,const char * indicator)2229 static const char *jk_set_session_indicator(cmd_parms * cmd,
2230 void *dummy,
2231 const char *indicator)
2232 {
2233 server_rec *s = cmd->server;
2234 jk_server_conf_t *conf =
2235 (jk_server_conf_t *) ap_get_module_config(s->module_config,
2236 &jk_module);
2237
2238 conf->session_indicator = apr_pstrdup(cmd->pool, indicator);
2239
2240 return NULL;
2241 }
2242
2243 /*
2244 * JkKEYSIZEIndicator Directive Handling
2245 *
2246 * JkKEYSIZEIndicator SSL_CIPHER_USEKEYSIZE
2247 */
2248
jk_set_key_size_indicator(cmd_parms * cmd,void * dummy,const char * indicator)2249 static const char *jk_set_key_size_indicator(cmd_parms * cmd,
2250 void *dummy,
2251 const char *indicator)
2252 {
2253 server_rec *s = cmd->server;
2254 jk_server_conf_t *conf =
2255 (jk_server_conf_t *) ap_get_module_config(s->module_config,
2256 &jk_module);
2257
2258 conf->key_size_indicator = apr_pstrdup(cmd->pool, indicator);
2259
2260 return NULL;
2261 }
2262
2263 /*
2264 * JkOptions Directive Handling
2265 *
2266 *
2267 * +ForwardSSLKeySize => Forward SSL Key Size, to follow 2.3 specs but may broke old TC 3.2
2268 * -ForwardSSLKeySize => Don't Forward SSL Key Size, will make mod_jk works with all TC release
2269 * ForwardURICompat => Forward URI normally, less spec compliant but mod_rewrite compatible (old TC)
2270 * ForwardURICompatUnparsed => Forward URI as unparsed, spec compliant but broke mod_rewrite (old TC)
2271 * ForwardURIEscaped => Forward URI escaped and Tomcat (3.3 rc2) stuff will do the decoding part
2272 * ForwardDirectories => Forward all directory requests with no index files to Tomcat
2273 * +ForwardSSLCertChain => Forward SSL Cert Chain
2274 * -ForwardSSLCertChain => Don't Forward SSL Cert Chain (default)
2275 */
2276
jk_set_options(cmd_parms * cmd,void * dummy,const char * line)2277 static const char *jk_set_options(cmd_parms * cmd, void *dummy,
2278 const char *line)
2279 {
2280 int opt = 0;
2281 int mask = 0;
2282 char action;
2283 char *w;
2284
2285 server_rec *s = cmd->server;
2286 jk_server_conf_t *conf =
2287 (jk_server_conf_t *) ap_get_module_config(s->module_config,
2288 &jk_module);
2289
2290 while (line[0] != 0) {
2291 w = ap_getword_conf(cmd->pool, &line);
2292 action = 0;
2293
2294 if (*w == '+' || *w == '-') {
2295 action = *(w++);
2296 }
2297
2298 mask = 0;
2299
2300 if (action == '-' &&
2301 (!strncasecmp(w, "ForwardURI", strlen("ForwardURI")))) {
2302 return apr_pstrcat(cmd->pool, "JkOptions: Illegal option '-", w,
2303 "': option can not be disabled", NULL);
2304 }
2305 if (!strcasecmp(w, "ForwardURICompat")) {
2306 opt = JK_OPT_FWDURICOMPAT;
2307 mask = JK_OPT_FWDURIMASK;
2308 }
2309 else if (!strcasecmp(w, "ForwardURICompatUnparsed")) {
2310 opt = JK_OPT_FWDURICOMPATUNPARSED;
2311 mask = JK_OPT_FWDURIMASK;
2312 }
2313 else if (!strcasecmp(w, "ForwardURIEscaped")) {
2314 opt = JK_OPT_FWDURIESCAPED;
2315 mask = JK_OPT_FWDURIMASK;
2316 }
2317 else if (!strcasecmp(w, "ForwardURIProxy")) {
2318 opt = JK_OPT_FWDURIPROXY;
2319 mask = JK_OPT_FWDURIMASK;
2320 }
2321 else if (!strcasecmp(w, "CollapseSlashesAll")) {
2322 opt = JK_OPT_COLLAPSEALL;
2323 mask = JK_OPT_COLLAPSEMASK;
2324 }
2325 else if (!strcasecmp(w, "CollapseSlashesNone")) {
2326 opt = JK_OPT_COLLAPSENONE;
2327 mask = JK_OPT_COLLAPSEMASK;
2328 }
2329 else if (!strcasecmp(w, "CollapseSlashesUnmount")) {
2330 opt = JK_OPT_COLLAPSEUNMOUNT;
2331 mask = JK_OPT_COLLAPSEMASK;
2332 }
2333 else if (!strcasecmp(w, "ForwardDirectories")) {
2334 opt = JK_OPT_FWDDIRS;
2335 }
2336 else if (!strcasecmp(w, "ForwardLocalAddress")) {
2337 opt = JK_OPT_FWDLOCAL;
2338 mask = JK_OPT_FWDADDRMASK;
2339 }
2340 else if (!strcasecmp(w, "ForwardPhysicalAddress")) {
2341 opt = JK_OPT_FWDPHYSICAL;
2342 mask = JK_OPT_FWDADDRMASK;
2343 }
2344 else if (!strcasecmp(w, "FlushPackets")) {
2345 opt = JK_OPT_FLUSHPACKETS;
2346 }
2347 else if (!strcasecmp(w, "FlushHeader")) {
2348 opt = JK_OPT_FLUSHEADER;
2349 }
2350 else if (!strcasecmp(w, "DisableReuse")) {
2351 opt = JK_OPT_DISABLEREUSE;
2352 }
2353 else if (!strcasecmp(w, "ForwardSSLCertChain")) {
2354 opt = JK_OPT_FWDCERTCHAIN;
2355 }
2356 else if (!strcasecmp(w, "ForwardKeySize")) {
2357 opt = JK_OPT_FWDKEYSIZE;
2358 }
2359 else if (!strcasecmp(w, "RejectUnsafeURI")) {
2360 opt = JK_OPT_REJECTUNSAFE;
2361 }
2362 else
2363 return apr_pstrcat(cmd->pool, "JkOptions: Illegal option '", w,
2364 "'", NULL);
2365
2366 conf->options &= ~mask;
2367
2368 if (action == '-') {
2369 conf->exclude_options |= opt;
2370 }
2371 else if (action == '+') {
2372 conf->options |= opt;
2373 }
2374 else { /* for now +Opt == Opt */
2375 conf->options |= opt;
2376 }
2377 }
2378 return NULL;
2379 }
2380
2381 /*
2382 * JkEnvVar Directive Handling
2383 *
2384 * JkEnvVar MYOWNDIR
2385 */
2386
jk_add_env_var(cmd_parms * cmd,void * dummy,const char * env_name,const char * default_value)2387 static const char *jk_add_env_var(cmd_parms * cmd,
2388 void *dummy,
2389 const char *env_name,
2390 const char *default_value)
2391 {
2392 server_rec *s = cmd->server;
2393 jk_server_conf_t *conf =
2394 (jk_server_conf_t *) ap_get_module_config(s->module_config,
2395 &jk_module);
2396
2397 conf->envvars_has_own = JK_TRUE;
2398 if (!conf->envvars) {
2399 conf->envvars = apr_table_make(cmd->pool, 0);
2400 conf->envvars_def = apr_table_make(cmd->pool, 0);
2401 conf->envvar_items = apr_array_make(cmd->pool, 0,
2402 sizeof(envvar_item));
2403 }
2404
2405 /* env_name is mandatory, default_value is optional.
2406 * No value means send the attribute only, if the env var is set during runtime.
2407 */
2408 apr_table_setn(conf->envvars, env_name, default_value ? default_value : "");
2409 apr_table_setn(conf->envvars_def, env_name, default_value ? "1" : "0");
2410
2411 return NULL;
2412 }
2413
2414 /*
2415 * JkWorkerProperty Directive Handling
2416 *
2417 * JkWorkerProperty name=value
2418 */
2419
jk_set_worker_property(cmd_parms * cmd,void * dummy,const char * line)2420 static const char *jk_set_worker_property(cmd_parms * cmd,
2421 void *dummy,
2422 const char *line)
2423 {
2424 server_rec *s = cmd->server;
2425 jk_server_conf_t *conf =
2426 (jk_server_conf_t *) ap_get_module_config(s->module_config,
2427 &jk_module);
2428
2429 const char *err_string = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2430 if (err_string != NULL) {
2431 return err_string;
2432 }
2433
2434 if (!jk_worker_properties)
2435 jk_map_alloc(&jk_worker_properties);
2436 if (jk_map_read_property(jk_worker_properties, NULL, line,
2437 JK_MAP_HANDLE_DUPLICATES, conf->log) == JK_FALSE)
2438 return apr_pstrcat(cmd->temp_pool, "Invalid JkWorkerProperty ", line, NULL);
2439
2440 return NULL;
2441 }
2442
2443 static const command_rec jk_cmds[] = {
2444 /*
2445 * JkWorkersFile specifies a full path to the location of the worker
2446 * properties file.
2447 *
2448 * This file defines the different workers used by apache to redirect
2449 * servlet requests.
2450 */
2451 AP_INIT_TAKE1("JkWorkersFile", jk_set_worker_file, NULL, RSRC_CONF,
2452 "The name of a worker file for the Tomcat servlet containers"),
2453
2454 /*
2455 * JkMountFile specifies a full path to the location of the
2456 * uriworker properties file.
2457 *
2458 * This file defines the different mapping for workers used by apache
2459 * to redirect servlet requests.
2460 */
2461 AP_INIT_TAKE1("JkMountFile", jk_set_mount_file, NULL, RSRC_CONF,
2462 "The name of a mount file for the Tomcat servlet uri mapping"),
2463
2464 /*
2465 * JkMountFileReload specifies the reload check interval for the
2466 * uriworker properties file.
2467 *
2468 * Default value is: JK_URIMAP_DEF_RELOAD
2469 */
2470 AP_INIT_TAKE1("JkMountFileReload", jk_set_mount_file_reload, NULL, RSRC_CONF,
2471 "The reload check interval of the mount file"),
2472
2473 /*
2474 * JkWatchdogInterval specifies the maintain interval for the
2475 * watchdog thread.
2476 *
2477 * Default value is: 0 meaning watchdog thread will not be created
2478 */
2479 AP_INIT_TAKE1("JkWatchdogInterval", jk_set_watchdog_interval, NULL, RSRC_CONF,
2480 "The maintain interval of the watchdog thread"),
2481
2482 /*
2483 * JkMount mounts a url prefix to a worker (the worker need to be
2484 * defined in the worker properties file.
2485 */
2486 AP_INIT_TAKE12("JkMount", jk_mount_context, NULL, RSRC_CONF|ACCESS_CONF,
2487 "A mount point from a context to a Tomcat worker"),
2488
2489 /*
2490 * JkUnMount unmounts a url prefix to a worker (the worker need to be
2491 * defined in the worker properties file.
2492 */
2493 AP_INIT_TAKE12("JkUnMount", jk_unmount_context, NULL, RSRC_CONF|ACCESS_CONF,
2494 "A no mount point from a context to a Tomcat worker"),
2495
2496 /*
2497 * JkMountCopy specifies if mod_jk should copy the mount points
2498 * from the main server to the virtual servers.
2499 */
2500 AP_INIT_TAKE1("JkMountCopy", jk_set_mountcopy, NULL, RSRC_CONF,
2501 "Should the base server mounts be copied to the virtual server"),
2502
2503 /*
2504 * JkStripSession specifies if mod_jk should strip the ;jsessionid
2505 * from the unmapped urls
2506 */
2507 AP_INIT_TAKE12("JkStripSession", jk_set_strip_session, NULL, RSRC_CONF,
2508 "Should the server strip the jsessionid from unmapped URLs"),
2509
2510 /*
2511 * JkLogFile & JkLogLevel specifies to where should the plugin log
2512 * its information and how much.
2513 * JkLogStampFormat specify the time-stamp to be used on log
2514 */
2515 AP_INIT_TAKE1("JkLogFile", jk_set_log_file, NULL, RSRC_CONF,
2516 "Full path to the Tomcat module log file"),
2517
2518 AP_INIT_TAKE1("JkShmFile", jk_set_shm_file, NULL, RSRC_CONF,
2519 "Full path to the Tomcat module shared memory file"),
2520
2521 AP_INIT_TAKE1("JkShmSize", jk_set_shm_size, NULL, RSRC_CONF,
2522 "Size of the shared memory file in KBytes"),
2523
2524 AP_INIT_TAKE1("JkLogLevel", jk_set_log_level, NULL, RSRC_CONF,
2525 "The Tomcat module log level, can be debug, "
2526 "info, error or emerg"),
2527 AP_INIT_TAKE1("JkLogStampFormat", jk_set_log_fmt, NULL, RSRC_CONF,
2528 "The Tomcat module log format, follow strftime syntax"),
2529 AP_INIT_TAKE1("JkRequestLogFormat", jk_set_request_log_format, NULL,
2530 RSRC_CONF,
2531 "The mod_jk module request log format string"),
2532
2533 /*
2534 * Automatically Alias webapp context directories into the Apache
2535 * document space.
2536 */
2537 AP_INIT_TAKE1("JkAutoAlias", jk_set_auto_alias, NULL, RSRC_CONF,
2538 "The mod_jk module automatic context apache alias directory"),
2539
2540 /*
2541 * Enable worker name to be set in an environment variable.
2542 * This way one can use LocationMatch together with mod_env,
2543 * mod_setenvif and mod_rewrite to set the target worker.
2544 * Use this in combination with SetHandler jakarta-servlet to
2545 * make mod_jk the handler for the request.
2546 *
2547 */
2548 AP_INIT_TAKE1("JkWorkerIndicator", jk_set_worker_indicator, NULL, RSRC_CONF,
2549 "Name of the Apache environment that contains the worker name"),
2550
2551 /*
2552 * Environment variables used to overwrite the following
2553 * request information which gets forwarded:
2554 * - remote_addr
2555 * - remote_port
2556 * - remote_host
2557 * - remote_user
2558 * - auth_type
2559 * - server_name
2560 * - server_port
2561 */
2562 AP_INIT_TAKE1("JkRemoteAddrIndicator", jk_set_remote_addr_indicator, NULL, RSRC_CONF,
2563 "Name of the Apache environment that contains the remote address"),
2564 AP_INIT_TAKE1("JkRemotePortIndicator", jk_set_remote_port_indicator, NULL, RSRC_CONF,
2565 "Name of the Apache environment that contains the remote port"),
2566 AP_INIT_TAKE1("JkRemoteHostIndicator", jk_set_remote_host_indicator, NULL, RSRC_CONF,
2567 "Name of the Apache environment that contains the remote host name"),
2568 AP_INIT_TAKE1("JkRemoteUserIndicator", jk_set_remote_user_indicator, NULL, RSRC_CONF,
2569 "Name of the Apache environment that contains the remote user name"),
2570 AP_INIT_TAKE1("JkAuthTypeIndicator", jk_set_auth_type_indicator, NULL, RSRC_CONF,
2571 "Name of the Apache environment that contains the type of authentication"),
2572 AP_INIT_TAKE1("JkLocalNameIndicator", jk_set_local_name_indicator, NULL, RSRC_CONF,
2573 "Name of the Apache environment that contains the local name"),
2574 AP_INIT_TAKE1("JkLocalAddrIndicator", jk_set_local_addr_indicator, NULL, RSRC_CONF,
2575 "Name of the Apache environment that contains the local IP address"),
2576 AP_INIT_TAKE1("JkLocalPortIndicator", jk_set_local_port_indicator, NULL, RSRC_CONF,
2577 "Name of the Apache environment that contains the local port"),
2578 AP_INIT_TAKE1("JkIgnoreCLIndicator", jk_set_ignore_cl_indicator, NULL, RSRC_CONF,
2579 "Name of the Apache environment that forces to ignore a request "
2580 "Content-Length header"),
2581
2582 /*
2583 * Apache has multiple SSL modules (for example apache_ssl, stronghold
2584 * IHS ...). Each of these can have a different SSL environment names
2585 * The following properties let the administrator specify the envoiroment
2586 * variables names.
2587 *
2588 * HTTPS - indication for SSL
2589 * CERTS - Base64-Der-encoded client certificates.
2590 * CIPHER - A string specifing the ciphers suite in use.
2591 * KEYSIZE - Size of Key used in dialogue (#bits are secure)
2592 * SESSION - A string specifing the current SSL session.
2593 */
2594 AP_INIT_TAKE1("JkHTTPSIndicator", jk_set_https_indicator, NULL, RSRC_CONF,
2595 "Name of the Apache environment that contains SSL indication"),
2596 AP_INIT_TAKE1("JkSSLPROTOCOLIndicator", jk_set_ssl_protocol_indicator, NULL, RSRC_CONF,
2597 "Name of the Apache environment that contains the SSL protocol name"),
2598 AP_INIT_TAKE1("JkCERTSIndicator", jk_set_certs_indicator, NULL, RSRC_CONF,
2599 "Name of the Apache environment that contains SSL client certificates"),
2600 AP_INIT_TAKE1("JkCIPHERIndicator", jk_set_cipher_indicator, NULL,
2601 RSRC_CONF,
2602 "Name of the Apache environment that contains SSL client cipher"),
2603 AP_INIT_TAKE1("JkSESSIONIndicator", jk_set_session_indicator, NULL,
2604 RSRC_CONF,
2605 "Name of the Apache environment that contains SSL session"),
2606 AP_INIT_TAKE1("JkKEYSIZEIndicator", jk_set_key_size_indicator, NULL,
2607 RSRC_CONF,
2608 "Name of the Apache environment that contains SSL key size in use"),
2609 AP_INIT_TAKE1("JkCERTCHAINPrefix", jk_set_certchain_prefix, NULL, RSRC_CONF,
2610 "Name of the Apache environment (prefix) that contains SSL client chain certificates"),
2611 AP_INIT_FLAG("JkExtractSSL", jk_set_enable_ssl, NULL, RSRC_CONF,
2612 "Turns on SSL processing and information gathering by mod_jk"),
2613
2614 /*
2615 * Options to tune mod_jk configuration
2616 * for now we understand :
2617 * +ForwardSSLKeySize => Forward SSL Key Size, to follow 2.3 specs but may broke old TC 3.2
2618 * -ForwardSSLKeySize => Don't Forward SSL Key Size, will make mod_jk works with all TC release
2619 * ForwardURICompat => Forward URI normally, less spec compliant but mod_rewrite compatible (old TC)
2620 * ForwardURICompatUnparsed => Forward URI as unparsed, spec compliant but broke mod_rewrite (old TC)
2621 * ForwardURIEscaped => Forward URI escaped and Tomcat (3.3 rc2) stuff will do the decoding part
2622 * +ForwardSSLCertChain => Forward SSL certificate chain
2623 * -ForwardSSLCertChain => Don't forward SSL certificate chain
2624 */
2625 AP_INIT_RAW_ARGS("JkOptions", jk_set_options, NULL, RSRC_CONF,
2626 "Set one of more options to configure the mod_jk module"),
2627
2628 /*
2629 * JkEnvVar let user defines envs var passed from WebServer to
2630 * Servlet Engine
2631 */
2632 AP_INIT_TAKE12("JkEnvVar", jk_add_env_var, NULL, RSRC_CONF,
2633 "Adds a name of environment variable and an optional value "
2634 "that should be sent to servlet-engine"),
2635
2636 AP_INIT_RAW_ARGS("JkWorkerProperty", jk_set_worker_property,
2637 NULL, RSRC_CONF,
2638 "Set workers.properties formated directive"),
2639
2640 {NULL}
2641 };
2642
2643 /* ========================================================================= */
2644 /* The JK module handlers */
2645 /* ========================================================================= */
2646
2647 /** Util - cleanup for all processes.
2648 */
jk_cleanup_proc(void * data)2649 static apr_status_t jk_cleanup_proc(void *data)
2650 {
2651 /* If the main log is piped, we need to make sure
2652 * it is no longer used. The external log process
2653 * (e.g. rotatelogs) will be gone now and the pipe will
2654 * block, once the buffer gets full. NULLing
2655 * jklogfp makes logging switch to error log.
2656 */
2657 jk_logger_t *l = (jk_logger_t *)data;
2658 if (l && l->logger_private) {
2659 jk_file_logger_t *p = l->logger_private;
2660 if (p && p->is_piped == JK_TRUE) {
2661 p->jklogfp = NULL;
2662 p->is_piped = JK_FALSE;
2663 }
2664 }
2665 jk_shm_close(l);
2666 return APR_SUCCESS;
2667 }
2668
2669 /** Util - cleanup for child processes.
2670 */
jk_cleanup_child(void * data)2671 static apr_status_t jk_cleanup_child(void *data)
2672 {
2673 /* If the main log is piped, we need to make sure
2674 * it is no longer used. The external log process
2675 * (e.g. rotatelogs) will be gone now and the pipe will
2676 * block, once the buffer gets full. NULLing
2677 * jklogfp makes logging switch to error log.
2678 */
2679 jk_logger_t *l = (jk_logger_t *)data;
2680 if (l && l->logger_private) {
2681 jk_file_logger_t *p = l->logger_private;
2682 if (p && p->is_piped == JK_TRUE) {
2683 p->jklogfp = NULL;
2684 p->is_piped = JK_FALSE;
2685 }
2686 }
2687 /* Force the watchdog thread exit */
2688 if (jk_watchdog_interval > 0) {
2689 jk_watchdog_interval = 0;
2690 while (jk_watchdog_running)
2691 apr_sleep(apr_time_from_sec(1));
2692 }
2693 wc_shutdown(l);
2694 return jk_cleanup_proc(data);
2695 }
2696
2697 /** Main service method, called to forward a request to tomcat
2698 */
jk_handler(request_rec * r)2699 static int jk_handler(request_rec * r)
2700 {
2701 const char *worker_name;
2702 jk_server_conf_t *xconf;
2703 jk_request_conf_t *rconf;
2704 int rc, dmt = 1;
2705 int worker_name_extension = JK_FALSE;
2706
2707 /* We do DIR_MAGIC_TYPE here to make sure TC gets all requests, even
2708 * if they are directory requests, in case there are no static files
2709 * visible to Apache and/or DirectoryIndex was not used. This is only
2710 * used when JkOptions has ForwardDirectories set. */
2711 /* Not for me, try next handler */
2712 if (strcmp(r->handler, JK_HANDLER)
2713 && (dmt = strcmp(r->handler, DIR_MAGIC_TYPE)))
2714 return DECLINED;
2715
2716 xconf = (jk_server_conf_t *) ap_get_module_config(r->server->module_config,
2717 &jk_module);
2718 JK_TRACE_ENTER(xconf->log);
2719 if (apr_table_get(r->subprocess_env, "no-jk")) {
2720 if (JK_IS_DEBUG_LEVEL(xconf->log))
2721 jk_log(xconf->log, JK_LOG_DEBUG,
2722 "Into handler no-jk env var detected for uri=%s, declined",
2723 r->uri);
2724
2725 JK_TRACE_EXIT(xconf->log);
2726 return DECLINED;
2727 }
2728
2729 /* Was the option to forward directories to Tomcat set? */
2730 if (!dmt && !(xconf->options & JK_OPT_FWDDIRS)) {
2731 JK_TRACE_EXIT(xconf->log);
2732 return DECLINED;
2733 }
2734
2735 rconf = (jk_request_conf_t *)ap_get_module_config(r->request_config, &jk_module);
2736 if (rconf == NULL) {
2737 rconf = apr_palloc(r->pool, sizeof(jk_request_conf_t));
2738 rconf->jk_handled = JK_FALSE;
2739 rconf->rule_extensions = NULL;
2740 rconf->orig_uri = NULL;
2741 ap_set_module_config(r->request_config, &jk_module, rconf);
2742 }
2743
2744 worker_name = apr_table_get(r->notes, JK_NOTE_WORKER_NAME);
2745
2746 if (worker_name == NULL) {
2747 /* we may be here because of a manual directive ( that overrides
2748 translate and
2749 sets the handler directly ). We still need to know the worker.
2750 */
2751 worker_name = apr_table_get(r->subprocess_env, xconf->worker_indicator);
2752 if (worker_name) {
2753 /* The JkWorkerIndicator environment variable has
2754 * been used to explicitly set the worker without JkMount.
2755 * This is useful in combination with LocationMatch or mod_rewrite.
2756 */
2757 if (JK_IS_DEBUG_LEVEL(xconf->log))
2758 jk_log(xconf->log, JK_LOG_DEBUG,
2759 "Retrieved worker (%s) from env %s for %s",
2760 worker_name, xconf->worker_indicator, r->uri);
2761 if (ap_strchr_c(worker_name, ';')) {
2762 rule_extension_t *e = apr_palloc(r->pool, sizeof(rule_extension_t));
2763 char *w = apr_pstrdup(r->pool, worker_name);
2764 worker_name_extension = JK_TRUE;
2765 parse_rule_extensions(w, e, xconf->log);
2766 worker_name = w;
2767 rconf->rule_extensions = e;
2768 }
2769 }
2770 else if (worker_env.num_of_workers == 1) {
2771 /** We have a single worker ( the common case ).
2772 ( lb is a bit special, it should count as a single worker but
2773 I'm not sure how ). We also have a manual config directive that
2774 explicitly give control to us. */
2775 worker_name = worker_env.worker_list[0];
2776 if (JK_IS_DEBUG_LEVEL(xconf->log))
2777 jk_log(xconf->log, JK_LOG_DEBUG,
2778 "Single worker (%s) configuration for %s",
2779 worker_name, r->uri);
2780 }
2781 else {
2782 if (!xconf->uw_map) {
2783 if (JK_IS_DEBUG_LEVEL(xconf->log))
2784 jk_log(xconf->log, JK_LOG_DEBUG,
2785 "missing uri map for %s:%s",
2786 xconf->s->server_hostname ? xconf->s->server_hostname : "_default_",
2787 r->uri);
2788 }
2789 else {
2790 rule_extension_t *e;
2791 char *clean_uri;
2792 clean_uri = apr_pstrdup(r->pool, r->uri);
2793 rc = jk_servlet_normalize(clean_uri, xconf->log);
2794 if (rc != 0) {
2795 JK_TRACE_EXIT(xconf->log);
2796 return HTTP_BAD_REQUEST;
2797 }
2798
2799 worker_name = map_uri_to_worker_ext(xconf->uw_map, clean_uri,
2800 NULL, &e, NULL, xconf->log);
2801 if (worker_name) {
2802 rconf->rule_extensions = e;
2803 rconf->orig_uri = r->uri;
2804 r->uri = clean_uri;
2805 }
2806 }
2807
2808 if (worker_name == NULL && worker_env.num_of_workers) {
2809 worker_name = worker_env.worker_list[0];
2810 if (JK_IS_DEBUG_LEVEL(xconf->log))
2811 jk_log(xconf->log, JK_LOG_DEBUG,
2812 "Using first worker (%s) from %d workers for %s",
2813 worker_name, worker_env.num_of_workers, r->uri);
2814 }
2815 }
2816 if (worker_name)
2817 apr_table_setn(r->notes, JK_NOTE_WORKER_NAME, worker_name);
2818 }
2819
2820 if (JK_IS_DEBUG_LEVEL(xconf->log))
2821 jk_log(xconf->log, JK_LOG_DEBUG, "Into handler %s worker=%s"
2822 " r->proxyreq=%d",
2823 r->handler, STRNULL_FOR_NULL(worker_name), r->proxyreq);
2824
2825 rconf->jk_handled = JK_TRUE;
2826
2827 /* If this is a proxy request, we'll notify an error */
2828 if (r->proxyreq) {
2829 jk_log(xconf->log, JK_LOG_INFO, "Proxy request for worker=%s"
2830 " is not allowed",
2831 STRNULL_FOR_NULL(worker_name));
2832 JK_TRACE_EXIT(xconf->log);
2833 return HTTP_INTERNAL_SERVER_ERROR;
2834 }
2835
2836 /* Set up r->read_chunked flags for chunked encoding, if present */
2837 if ((rc = ap_setup_client_block(r, REQUEST_CHUNKED_DECHUNK)) != APR_SUCCESS) {
2838 JK_TRACE_EXIT(xconf->log);
2839 return rc;
2840 }
2841
2842 if (worker_name) {
2843 jk_worker_t *worker = wc_get_worker_for_name(worker_name, xconf->log);
2844
2845 /* If the remote client has aborted, just ignore the request */
2846 if (r->connection->aborted) {
2847 jk_log(xconf->log, JK_LOG_INFO, "Client connection aborted for"
2848 " worker=%s",
2849 worker_name);
2850 JK_TRACE_EXIT(xconf->log);
2851 return OK;
2852 }
2853
2854 if (worker) {
2855 long micro, seconds;
2856 char *duration = NULL;
2857 apr_time_t rd;
2858 apr_time_t request_begin = 0;
2859 int is_error = HTTP_INTERNAL_SERVER_ERROR;
2860 int rc = JK_FALSE;
2861 apache_private_data_t private_data;
2862 jk_ws_service_t s;
2863 jk_pool_atom_t buf[SMALL_POOL_SIZE];
2864 jk_open_pool(&private_data.p, buf, sizeof(buf));
2865
2866 private_data.read_body_started = JK_FALSE;
2867 private_data.r = r;
2868
2869 if (worker_name_extension == JK_TRUE) {
2870 extension_fix(&private_data.p, worker_name,
2871 rconf->rule_extensions, xconf->log);
2872 }
2873
2874 /* Maintain will be done by watchdog thread */
2875 if (!jk_watchdog_interval)
2876 wc_maintain(xconf->log);
2877 jk_init_ws_service(&s);
2878 s.ws_private = &private_data;
2879 s.pool = &private_data.p;
2880 apr_table_setn(r->notes, JK_NOTE_WORKER_TYPE,
2881 wc_get_name_for_type(worker->type, xconf->log));
2882
2883 request_begin = apr_time_now();
2884
2885 if (init_ws_service(&private_data, &s, xconf)) {
2886 jk_endpoint_t *end = NULL;
2887
2888 /* Use per/thread pool ( or "context" ) to reuse the
2889 endpoint. It's a bit faster, but I don't know
2890 how to deal with load balancing - but it's usefull for JNI
2891 */
2892
2893 /* worker->get_endpoint might fail if we are out of memory so check */
2894 /* and handle it */
2895 if (worker->get_endpoint(worker, &end, xconf->log)) {
2896 rc = end->service(end, &s, xconf->log,
2897 &is_error);
2898 end->done(&end, xconf->log);
2899 if ((s.content_read < s.content_length ||
2900 (s.is_chunked && !s.no_more_chunks)) &&
2901 /* This case aborts the connection below and typically
2902 * means the request body reading already timed out,
2903 * so lets not try to read again here. */
2904 !(rc == JK_CLIENT_ERROR && is_error == HTTP_BAD_REQUEST)) {
2905 /*
2906 * If the servlet engine didn't consume all of the
2907 * request data, consume and discard all further
2908 * characters left to read from client
2909 */
2910 char *buff = apr_palloc(r->pool, 2048);
2911 int consumed = 0;
2912 if (buff != NULL) {
2913 int rd;
2914 while ((rd =
2915 ap_get_client_block(r, buff, 2048)) > 0) {
2916 s.content_read += rd;
2917 consumed += rd;
2918 }
2919 }
2920 if (JK_IS_DEBUG_LEVEL(xconf->log)) {
2921 jk_log(xconf->log, JK_LOG_DEBUG,
2922 "Consumed %d bytes of remaining request data for worker=%s",
2923 consumed, STRNULL_FOR_NULL(worker_name));
2924 }
2925 }
2926 }
2927 else { /* this means we couldn't get an endpoint */
2928 jk_log(xconf->log, JK_LOG_ERROR, "Could not get endpoint"
2929 " for worker=%s",
2930 worker_name);
2931 rc = 0; /* just to make sure that we know we've failed */
2932 is_error = HTTP_SERVICE_UNAVAILABLE;
2933 }
2934 }
2935 else {
2936 jk_log(xconf->log, JK_LOG_ERROR, "Could not init service"
2937 " for worker=%s",
2938 worker_name);
2939 jk_close_pool(&private_data.p);
2940 JK_TRACE_EXIT(xconf->log);
2941 return HTTP_INTERNAL_SERVER_ERROR;
2942 }
2943 rd = apr_time_now() - request_begin;
2944 seconds = (long)apr_time_sec(rd);
2945 micro = (long)(rd - apr_time_from_sec(seconds));
2946
2947 duration = apr_psprintf(r->pool, "%.1ld.%.6ld", seconds, micro);
2948 apr_table_setn(r->notes, JK_NOTE_REQUEST_DURATION, duration);
2949 if (s.route && *s.route)
2950 apr_table_set(r->notes, JK_NOTE_WORKER_ROUTE, s.route);
2951
2952 jk_close_pool(&private_data.p);
2953
2954 if (rc > 0) {
2955 if (s.extension.use_server_error_pages &&
2956 s.http_response_status >= s.extension.use_server_error_pages) {
2957 if (JK_IS_DEBUG_LEVEL(xconf->log))
2958 jk_log(xconf->log, JK_LOG_DEBUG, "Forwarding status=%d"
2959 " for worker=%s",
2960 s.http_response_status, worker_name);
2961 JK_TRACE_EXIT(xconf->log);
2962 return s.http_response_status;
2963 }
2964 /* If tomcat returned no body and the status is not OK,
2965 let apache handle the error code */
2966
2967 if (!r->sent_bodyct && r->status >= HTTP_BAD_REQUEST) {
2968 jk_log(xconf->log, JK_LOG_INFO, "No body with status=%d"
2969 " for worker=%s",
2970 r->status, worker_name);
2971 JK_TRACE_EXIT(xconf->log);
2972 return r->status;
2973 }
2974 if (JK_IS_DEBUG_LEVEL(xconf->log))
2975 jk_log(xconf->log, JK_LOG_DEBUG, "Service finished"
2976 " with status=%d for worker=%s",
2977 r->status, worker_name);
2978 JK_TRACE_EXIT(xconf->log);
2979 return OK; /* NOT r->status, even if it has changed. */
2980 }
2981 else if (rc == JK_CLIENT_ERROR) {
2982 if (is_error != HTTP_REQUEST_ENTITY_TOO_LARGE)
2983 r->connection->aborted = 1;
2984 jk_log(xconf->log, JK_LOG_INFO, "Aborting connection"
2985 " for worker=%s",
2986 worker_name);
2987 JK_TRACE_EXIT(xconf->log);
2988 return is_error;
2989 }
2990 else {
2991 jk_log(xconf->log, JK_LOG_INFO, "Service error=%d"
2992 " for worker=%s",
2993 rc, worker_name);
2994 JK_TRACE_EXIT(xconf->log);
2995 return is_error;
2996 }
2997 }
2998 else {
2999 jk_log(xconf->log, JK_LOG_INFO, "Could not find a worker"
3000 " for worker name=%s",
3001 worker_name);
3002 JK_TRACE_EXIT(xconf->log);
3003 return HTTP_INTERNAL_SERVER_ERROR;
3004 }
3005 }
3006
3007 rconf->jk_handled = JK_FALSE;
3008 JK_TRACE_EXIT(xconf->log);
3009 return DECLINED;
3010 }
3011
3012 /** Standard apache hook, cleanup jk
3013 */
jk_apr_pool_cleanup(void * data)3014 static apr_status_t jk_apr_pool_cleanup(void *data)
3015 {
3016 server_rec *s = data;
3017
3018 if (jk_worker_properties) {
3019 jk_map_free(&jk_worker_properties);
3020 jk_worker_properties = NULL;
3021 jk_worker_file = NULL;
3022 jk_mount_copy_all = JK_FALSE;
3023 }
3024
3025 while (NULL != s) {
3026 jk_server_conf_t *conf =
3027 (jk_server_conf_t *) ap_get_module_config(s->module_config,
3028 &jk_module);
3029
3030 if (conf && conf->was_initialized == JK_TRUE) {
3031 /* On pool cleanup pass NULL for the jk_logger to
3032 prevent segmentation faults on Windows because
3033 we can't guarantee what order pools get cleaned
3034 up between APR implementations. */
3035 wc_close(NULL);
3036 if (conf->uri_to_context) {
3037 jk_map_free(&conf->uri_to_context);
3038 /* We cannot have allocated uw_map
3039 * unless we've allocated uri_to_context
3040 */
3041 if (conf->uw_map)
3042 uri_worker_map_free(&conf->uw_map, NULL);
3043 }
3044 conf->was_initialized = JK_FALSE;
3045 }
3046 s = s->next;
3047 }
3048 return APR_SUCCESS;
3049 }
3050
3051 /** Create default jk_config. XXX This is mostly server-independent,
3052 all servers are using something similar - should go to common.
3053 */
create_jk_config(apr_pool_t * p,server_rec * s)3054 static void *create_jk_config(apr_pool_t * p, server_rec * s)
3055 {
3056 jk_server_conf_t *c =
3057 (jk_server_conf_t *) apr_pcalloc(p, sizeof(jk_server_conf_t));
3058
3059 c->was_initialized = JK_FALSE;
3060
3061 if (s->is_virtual) {
3062 c->mountcopy = JK_UNSET;
3063 c->mount_file_reload = JK_UNSET;
3064 c->log_level = JK_UNSET;
3065 c->ssl_enable = JK_UNSET;
3066 c->strip_session = JK_UNSET;
3067 }
3068 else {
3069 if (!jk_map_alloc(&(c->uri_to_context))) {
3070 ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "Memory error");
3071 }
3072 c->mountcopy = JK_FALSE;
3073 c->mount_file_reload = JK_URIMAP_DEF_RELOAD;
3074 c->log_level = JK_LOG_DEF_LEVEL;
3075 c->options = JK_OPT_DEFAULT;
3076 c->worker_indicator = JK_ENV_WORKER_NAME;
3077
3078 /*
3079 * Configurable environment variables to overwrite
3080 * request information using meta data send by a
3081 * proxy in front of us.
3082 */
3083 c->remote_addr_indicator = JK_ENV_REMOTE_ADDR;
3084 c->remote_port_indicator = JK_ENV_REMOTE_PORT;
3085 c->remote_host_indicator = JK_ENV_REMOTE_HOST;
3086 c->remote_user_indicator = JK_ENV_REMOTE_USER;
3087 c->auth_type_indicator = JK_ENV_AUTH_TYPE;
3088 c->local_name_indicator = JK_ENV_LOCAL_NAME;
3089 c->local_addr_indicator = JK_ENV_LOCAL_ADDR;
3090 c->local_port_indicator = JK_ENV_LOCAL_PORT;
3091
3092 c->ignore_cl_indicator = JK_ENV_IGNORE_CL;
3093
3094 /*
3095 * By default we will try to gather SSL info.
3096 * Disable this functionality through JkExtractSSL
3097 */
3098 c->ssl_enable = JK_TRUE;
3099 /*
3100 * The defaults ssl indicators match those in mod_ssl (seems
3101 * to be in more use).
3102 */
3103 c->https_indicator = JK_ENV_HTTPS;
3104 c->ssl_protocol_indicator = JK_ENV_SSL_PROTOCOL;
3105 c->certs_indicator = JK_ENV_CERTS;
3106 c->cipher_indicator = JK_ENV_CIPHER;
3107 c->certchain_prefix = JK_ENV_CERTCHAIN_PREFIX;
3108 c->session_indicator = JK_ENV_SESSION;
3109 c->key_size_indicator = JK_ENV_KEY_SIZE;
3110 c->strip_session = JK_FALSE;
3111 }
3112 c->envvars_has_own = JK_FALSE;
3113
3114 c->s = s;
3115 apr_pool_cleanup_register(p, s, jk_apr_pool_cleanup, apr_pool_cleanup_null);
3116 return c;
3117 }
3118
3119
3120 /*
3121 * Utility - copy items from apr table src to dst,
3122 * for keys that exist in src but not in dst.
3123 */
merge_apr_table(apr_table_t * src,apr_table_t * dst)3124 static void merge_apr_table(apr_table_t *src, apr_table_t *dst)
3125 {
3126 int i;
3127 const apr_array_header_t *arr;
3128 const apr_table_entry_t *elts;
3129
3130 arr = apr_table_elts(src);
3131 elts = (const apr_table_entry_t *)arr->elts;
3132 for (i = 0; i < arr->nelts; ++i) {
3133 if (!apr_table_get(dst, elts[i].key)) {
3134 apr_table_setn(dst, elts[i].key, elts[i].val);
3135 }
3136 }
3137 }
3138
3139
3140 /** Standard apache callback, merge jk options specified in <Directory>
3141 context or <Host>.
3142 */
merge_jk_config(apr_pool_t * p,void * basev,void * overridesv)3143 static void *merge_jk_config(apr_pool_t * p, void *basev, void *overridesv)
3144 {
3145 jk_server_conf_t *base = (jk_server_conf_t *) basev;
3146 jk_server_conf_t *overrides = (jk_server_conf_t *) overridesv;
3147 int mask = 0;
3148
3149 if (!overrides->log_file)
3150 overrides->log_file = base->log_file;
3151 if (overrides->log_level == JK_UNSET)
3152 overrides->log_level = base->log_level;
3153
3154 if (!overrides->stamp_format_string)
3155 overrides->stamp_format_string = base->stamp_format_string;
3156 if (!overrides->format_string)
3157 overrides->format_string = base->format_string;
3158
3159 if (!overrides->worker_indicator)
3160 overrides->worker_indicator = base->worker_indicator;
3161
3162 if (!overrides->remote_addr_indicator)
3163 overrides->remote_addr_indicator = base->remote_addr_indicator;
3164 if (!overrides->remote_port_indicator)
3165 overrides->remote_port_indicator = base->remote_port_indicator;
3166 if (!overrides->remote_host_indicator)
3167 overrides->remote_host_indicator = base->remote_host_indicator;
3168 if (!overrides->remote_user_indicator)
3169 overrides->remote_user_indicator = base->remote_user_indicator;
3170 if (!overrides->auth_type_indicator)
3171 overrides->auth_type_indicator = base->auth_type_indicator;
3172 if (!overrides->local_name_indicator)
3173 overrides->local_name_indicator = base->local_name_indicator;
3174 if (!overrides->local_port_indicator)
3175 overrides->local_port_indicator = base->local_port_indicator;
3176
3177 if (!overrides->ignore_cl_indicator)
3178 overrides->ignore_cl_indicator = base->ignore_cl_indicator;
3179
3180 if (overrides->ssl_enable == JK_UNSET)
3181 overrides->ssl_enable = base->ssl_enable;
3182 if (!overrides->https_indicator)
3183 overrides->https_indicator = base->https_indicator;
3184 if (!overrides->ssl_protocol_indicator)
3185 overrides->ssl_protocol_indicator = base->ssl_protocol_indicator;
3186 if (!overrides->certs_indicator)
3187 overrides->certs_indicator = base->certs_indicator;
3188 if (!overrides->cipher_indicator)
3189 overrides->cipher_indicator = base->cipher_indicator;
3190 if (!overrides->certchain_prefix)
3191 overrides->certchain_prefix = base->certchain_prefix;
3192 if (!overrides->session_indicator)
3193 overrides->session_indicator = base->session_indicator;
3194 if (!overrides->key_size_indicator)
3195 overrides->key_size_indicator = base->key_size_indicator;
3196
3197 /* Don't simply accumulate bits in the JK_OPT_FWDURIMASK or
3198 * JK_OPT_COLLAPSEMASK region, because those are multi-bit values. */
3199 if (overrides->options & JK_OPT_FWDURIMASK)
3200 mask |= JK_OPT_FWDURIMASK;
3201 if (overrides->options & JK_OPT_COLLAPSEMASK)
3202 mask |= JK_OPT_COLLAPSEMASK;
3203 overrides->options |= (base->options & ~base->exclude_options) & ~mask;
3204
3205 if (base->envvars) {
3206 if (overrides->envvars && overrides->envvars_has_own) {
3207 /* merge_apr_table() preserves existing entries in overrides table */
3208 merge_apr_table(base->envvars, overrides->envvars);
3209 merge_apr_table(base->envvars_def, overrides->envvars_def);
3210 }
3211 else {
3212 overrides->envvars = base->envvars;
3213 overrides->envvars_def = base->envvars_def;
3214 overrides->envvar_items = base->envvar_items;
3215 }
3216 }
3217
3218 if (overrides->mountcopy == JK_UNSET && jk_mount_copy_all == JK_TRUE) {
3219 overrides->mountcopy = JK_TRUE;
3220 }
3221 if (overrides->uri_to_context && overrides->mountcopy == JK_TRUE) {
3222 /* jk_map_copy() preserves existing entries in overrides map */
3223 if (jk_map_copy(base->uri_to_context, overrides->uri_to_context) == JK_FALSE) {
3224 jk_error_exit(JKLOG_MARK, APLOG_EMERG, overrides->s, p, "Memory error");
3225 }
3226 if (!overrides->mount_file)
3227 overrides->mount_file = base->mount_file;
3228 }
3229 if (overrides->mountcopy == JK_TRUE) {
3230 if (!overrides->alias_dir)
3231 overrides->alias_dir = base->alias_dir;
3232 }
3233 if (overrides->mount_file_reload == JK_UNSET)
3234 overrides->mount_file_reload = base->mount_file_reload;
3235 if (overrides->strip_session == JK_UNSET) {
3236 overrides->strip_session = base->strip_session;
3237 overrides->strip_session_name = base->strip_session_name;
3238 }
3239 return overrides;
3240 }
3241
jk_log_to_file(jk_logger_t * l,int level,int used,char * what)3242 static int JK_METHOD jk_log_to_file(jk_logger_t *l, int level,
3243 int used, char *what)
3244 {
3245 if (l &&
3246 (l->level <= level || level == JK_LOG_REQUEST_LEVEL) &&
3247 l->logger_private && what && used > 0) {
3248 jk_file_logger_t *p = l->logger_private;
3249 if (p->jklogfp) {
3250 apr_status_t rv;
3251 apr_size_t wrote;
3252 #if defined(WIN32)
3253 what[used++] = '\r';
3254 #endif
3255 what[used++] = '\n';
3256 wrote = used;
3257 rv = apr_global_mutex_lock(jk_log_lock);
3258 if (rv != APR_SUCCESS) {
3259 ap_log_error(APLOG_MARK, APLOG_ERR, rv, NULL,
3260 "apr_global_mutex_lock(jk_log_lock) failed");
3261 /* XXX: Maybe this should be fatal? */
3262 }
3263 rv = apr_file_write(p->jklogfp, what, &wrote);
3264 if (rv != APR_SUCCESS) {
3265 char error[256];
3266 apr_strerror(rv, error, 254);
3267 ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
3268 "mod_jk: jk_log_to_file %.*s failed: %s",
3269 used, what, error);
3270 }
3271 rv = apr_global_mutex_unlock(jk_log_lock);
3272 if (rv != APR_SUCCESS) {
3273 ap_log_error(APLOG_MARK, APLOG_ERR, rv, NULL,
3274 "apr_global_mutex_unlock(jk_log_lock) failed");
3275 /* XXX: Maybe this should be fatal? */
3276 }
3277 }
3278 else {
3279 /* Can't use mod_jk log any more, log to error log instead.
3280 * Choose APLOG_ERR, since we already checked above, that if
3281 * the mod_jk log file would still be open, we would have
3282 * actually logged the message there
3283 */
3284 ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
3285 "%.*s", used, what);
3286 }
3287
3288 return JK_TRUE;
3289 }
3290
3291 return JK_FALSE;
3292 }
3293
3294 /*
3295 ** +-------------------------------------------------------+
3296 ** | |
3297 ** | jk logfile support |
3298 ** | |
3299 ** +-------------------------------------------------------+
3300 */
3301
jklog_cleanup(void * d)3302 static apr_status_t jklog_cleanup(void *d)
3303 {
3304 /* hgomez@20070425 */
3305 /* Clean up pointer content */
3306 if (d != NULL)
3307 *(jk_logger_t **)d = NULL;
3308
3309 return APR_SUCCESS;
3310 }
3311
open_jklog(server_rec * s,apr_pool_t * p)3312 static int open_jklog(server_rec * s, apr_pool_t * p)
3313 {
3314 jk_server_conf_t *conf;
3315 const char *fname;
3316 apr_status_t rc;
3317 apr_file_t *jklogfp;
3318 piped_log *pl;
3319 jk_logger_t *jkl;
3320 jk_file_logger_t *flp;
3321 int jklog_flags = (APR_WRITE | APR_APPEND | APR_CREATE);
3322 apr_fileperms_t jklog_mode =
3323 (APR_UREAD | APR_UWRITE | APR_GREAD | APR_WREAD);
3324
3325 conf = ap_get_module_config(s->module_config, &jk_module);
3326
3327 if (conf->log_file == NULL) {
3328 conf->log_file = ap_server_root_relative(p, JK_LOG_DEF_FILE);
3329 if (conf->log_file)
3330 ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s,
3331 "No JkLogFile defined in httpd.conf. "
3332 "Using default %s", conf->log_file);
3333 }
3334 if (*(conf->log_file) == '\0') {
3335 ap_log_error(APLOG_MARK, APLOG_ERR, APR_EBADPATH, s,
3336 "mod_jk: Invalid JkLogFile EMPTY");
3337 conf->log = main_log;
3338 return 0;
3339 }
3340
3341 jklogfp = apr_hash_get(jk_log_fps, conf->log_file, APR_HASH_KEY_STRING);
3342 if (!jklogfp) {
3343 if (*conf->log_file == '|') {
3344 if ((pl = ap_open_piped_log(p, conf->log_file + 1)) == NULL) {
3345 ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
3346 "mod_jk: could not open reliable pipe "
3347 "to jk log %s", conf->log_file + 1);
3348 return -1;
3349 }
3350 jklogfp = (void *)ap_piped_log_write_fd(pl);
3351 }
3352 else {
3353 fname = ap_server_root_relative(p, conf->log_file);
3354 if (!fname) {
3355 ap_log_error(APLOG_MARK, APLOG_ERR, APR_EBADPATH, s,
3356 "mod_jk: Invalid JkLog " "path %s", conf->log_file);
3357 return -1;
3358 }
3359 if ((rc = apr_file_open(&jklogfp, fname,
3360 jklog_flags, jklog_mode, p))
3361 != APR_SUCCESS) {
3362 ap_log_error(APLOG_MARK, APLOG_ERR, rc, s,
3363 "mod_jk: could not open JkLog " "file %s", fname);
3364 return -1;
3365 }
3366 }
3367 apr_file_inherit_set(jklogfp);
3368 apr_hash_set(jk_log_fps, conf->log_file, APR_HASH_KEY_STRING, jklogfp);
3369 }
3370 jkl = (jk_logger_t *)apr_palloc(p, sizeof(jk_logger_t));
3371 flp = (jk_file_logger_t *) apr_palloc(p, sizeof(jk_file_logger_t));
3372 if (jkl && flp) {
3373 jkl->log = jk_log_to_file;
3374 jkl->level = conf->log_level;
3375 jkl->logger_private = flp;
3376 flp->jklogfp = jklogfp;
3377 if (*conf->log_file == '|')
3378 flp->is_piped = JK_TRUE;
3379 else
3380 flp->is_piped = JK_FALSE;
3381 conf->log = jkl;
3382 jk_set_time_fmt(conf->log, conf->stamp_format_string);
3383 if (main_log == NULL) {
3384 main_log = conf->log;
3385
3386 /* hgomez@20070425 */
3387 /* Shouldn't we clean both conf->log and main_log ? */
3388 /* Also should we pass pointer (ie: main_log) or handle (*main_log) ? */
3389 apr_pool_cleanup_register(p, &main_log,
3390 jklog_cleanup,
3391 apr_pool_cleanup_null);
3392 }
3393
3394 return 0;
3395 }
3396
3397 return -1;
3398 }
3399
3400 #if APR_HAS_THREADS
3401
jk_watchdog_func(apr_thread_t * thd,void * data)3402 static void * APR_THREAD_FUNC jk_watchdog_func(apr_thread_t *thd, void *data)
3403 {
3404 int i;
3405 jk_server_conf_t *conf = (jk_server_conf_t *)data;
3406
3407 if (JK_IS_DEBUG_LEVEL(conf->log))
3408 jk_log(conf->log, JK_LOG_DEBUG,
3409 "Watchdog thread initialized with %d second interval",
3410 jk_watchdog_interval);
3411 for (;;) {
3412 for (i = 0; i < (jk_watchdog_interval * 10); i++) {
3413 /* apr_sleep() uses microseconds */
3414 apr_sleep((apr_time_t)(100000));
3415 if (!jk_watchdog_interval)
3416 break;
3417 }
3418 if (!jk_watchdog_interval)
3419 break;
3420 if (JK_IS_DEBUG_LEVEL(conf->log))
3421 jk_log(conf->log, JK_LOG_DEBUG,
3422 "Watchdog thread running");
3423 jk_watchdog_running = 1;
3424 wc_maintain(conf->log);
3425 if (!jk_watchdog_interval)
3426 break;
3427 }
3428 jk_watchdog_running = 0;
3429 return NULL;
3430 }
3431
3432 #endif
3433
3434 /** Standard apache callback, initialize jk.
3435 */
jk_child_init(apr_pool_t * pconf,server_rec * s)3436 static void jk_child_init(apr_pool_t * pconf, server_rec * s)
3437 {
3438 jk_server_conf_t *conf;
3439 apr_status_t rv;
3440 int rc;
3441 apr_thread_t *wdt;
3442
3443 conf = ap_get_module_config(s->module_config, &jk_module);
3444
3445 rv = apr_global_mutex_child_init(&jk_log_lock, NULL, pconf);
3446 if (rv != APR_SUCCESS) {
3447 ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
3448 "mod_jk: could not init JK log lock in child");
3449 }
3450
3451 JK_TRACE_ENTER(conf->log);
3452
3453 if (jk_watchdog_interval) {
3454 #if APR_HAS_THREADS
3455 rv = apr_thread_create(&wdt, NULL, jk_watchdog_func, conf, pconf);
3456 if (rv != APR_SUCCESS) {
3457 jk_log(conf->log, JK_LOG_ERROR,
3458 "Could not init watchdog thread, error=%d", rv);
3459 jk_watchdog_interval = 0;
3460 }
3461 apr_thread_detach(wdt);
3462 #endif
3463 }
3464
3465 if ((rc = jk_shm_attach(jk_shm_file, jk_shm_size, conf->log)) == 0) {
3466 apr_pool_cleanup_register(pconf, conf->log, jk_cleanup_child,
3467 apr_pool_cleanup_null);
3468 }
3469 else {
3470 jk_log(conf->log, JK_LOG_ERROR, "Attaching shm:%s errno=%d",
3471 jk_shm_name(), rc);
3472 }
3473 if (JK_IS_DEBUG_LEVEL(conf->log))
3474 jk_log(conf->log, JK_LOG_DEBUG, "Initialized %s", JK_FULL_EXPOSED_VERSION);
3475 JK_TRACE_EXIT(conf->log);
3476 }
3477
3478 /** Initialize jk, using worker.properties.
3479 We also use apache commands ( JkWorker, etc), but this use is
3480 deprecated, as we'll try to concentrate all config in
3481 workers.properties, urimap.properties, and ajp14 autoconf.
3482
3483 Apache config will only be used for manual override, using
3484 SetHandler and normal apache directives ( but minimal jk-specific
3485 stuff )
3486 */
init_jk(apr_pool_t * pconf,jk_server_conf_t * conf,server_rec * s)3487 static int init_jk(apr_pool_t * pconf, jk_server_conf_t * conf,
3488 server_rec * s)
3489 {
3490 int rc;
3491 int is_threaded;
3492 int mpm_threads = 1;
3493
3494 if (!jk_worker_properties)
3495 jk_map_alloc(&jk_worker_properties);
3496 jk_map_put(jk_worker_properties, "ServerRoot", ap_server_root, NULL);
3497
3498 /* Set default connection cache size for multi-threaded MPMs */
3499 if (ap_mpm_query(AP_MPMQ_IS_THREADED, &is_threaded) == APR_SUCCESS &&
3500 is_threaded != AP_MPMQ_NOT_SUPPORTED) {
3501 if (ap_mpm_query(AP_MPMQ_MAX_THREADS, &mpm_threads) != APR_SUCCESS)
3502 mpm_threads = 1;
3503 }
3504 if (mpm_threads > 1) {
3505 #if _MT_CODE
3506 /* _MT_CODE */
3507 if (JK_IS_DEBUG_LEVEL(conf->log)) {
3508 #if !defined(WIN32)
3509 #if USE_FLOCK_LK
3510 jk_log(conf->log, JK_LOG_DEBUG,
3511 "Using flock() for locking.");
3512 #else
3513 jk_log(conf->log, JK_LOG_DEBUG,
3514 "Using fcntl() for locking.");
3515 #endif /* USE_FLOCK_LK */
3516 #else /* WIN32 */
3517 jk_log(conf->log, JK_LOG_DEBUG,
3518 "Not using locking.");
3519 #endif
3520 }
3521 #else
3522 /* !_MT_CODE */
3523 ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s,
3524 "Cannot run prefork mod_jk on threaded server.");
3525 return JK_FALSE;
3526 #endif
3527 }
3528 if (JK_IS_DEBUG_LEVEL(conf->log))
3529 jk_log(conf->log, JK_LOG_DEBUG,
3530 "Setting default connection pool max size to %d",
3531 mpm_threads);
3532 jk_set_worker_def_cache_size(mpm_threads);
3533
3534 if ((jk_worker_file != NULL) &&
3535 !jk_map_read_properties(jk_worker_properties, NULL, jk_worker_file, NULL,
3536 JK_MAP_HANDLE_DUPLICATES, conf->log)) {
3537 ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s,
3538 "Error in reading worker properties from '%s'",
3539 jk_worker_file);
3540 return JK_FALSE;
3541 }
3542
3543 if (jk_map_resolve_references(jk_worker_properties, "worker.",
3544 1, 1, conf->log) == JK_FALSE) {
3545 ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s,
3546 "Error in resolving configuration references");
3547 return JK_FALSE;
3548 }
3549
3550 #if !defined(WIN32)
3551 if (!jk_shm_file) {
3552 jk_shm_file = ap_server_root_relative(pconf, JK_SHM_DEF_FILE);
3553 if (jk_shm_file)
3554 ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s,
3555 "No JkShmFile defined in httpd.conf. "
3556 "Using default %s", jk_shm_file);
3557 }
3558 #endif
3559 if (jk_shm_size == 0) {
3560 jk_shm_size = jk_shm_calculate_size(jk_worker_properties, conf->log);
3561 }
3562 else if (jk_shm_size_set) {
3563 jk_log(conf->log, JK_LOG_WARNING,
3564 "The optimal shared memory size can now be determined automatically.");
3565 jk_log(conf->log, JK_LOG_WARNING,
3566 "You can remove the JkShmSize directive if you want to use the optimal size.");
3567 }
3568 if ((rc = jk_shm_open(jk_shm_file, jk_shm_size, conf->log)) == 0) {
3569 apr_pool_cleanup_register(pconf, conf->log,
3570 jk_cleanup_proc,
3571 apr_pool_cleanup_null);
3572 }
3573 else {
3574 jk_error_exit(JKLOG_MARK, APLOG_EMERG, s, s->process->pool,
3575 "Initializing shm:%s errno=%d. Unable to start due to shared memory failure.",
3576 jk_shm_name(), rc);
3577 }
3578 /* we add the URI->WORKER MAP since workers using AJP14
3579 will feed it */
3580 worker_env.uri_to_worker = conf->uw_map;
3581 worker_env.virtual = "*"; /* for now */
3582 #if ((AP_MODULE_MAGIC_AT_LEAST(20051115,4)) && !defined(API_COMPATIBILITY)) || (MODULE_MAGIC_NUMBER_MAJOR >= 20060905)
3583 worker_env.server_name = (char *)ap_get_server_description();
3584 #else
3585 worker_env.server_name = (char *)ap_get_server_version();
3586 #endif
3587 worker_env.pool = pconf;
3588
3589 if (wc_open(jk_worker_properties, &worker_env, conf->log)) {
3590 ap_add_version_component(pconf, JK_EXPOSED_VERSION);
3591 jk_log(conf->log, JK_LOG_INFO,
3592 "%s initialized",
3593 JK_FULL_EXPOSED_VERSION);
3594 }
3595 else {
3596 ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s,
3597 "Error in creating the workers."
3598 " Please consult your mod_jk log file '%s'.", conf->log_file);
3599 return JK_FALSE;
3600 }
3601 return JK_TRUE;
3602 }
3603
jk_post_config(apr_pool_t * pconf,apr_pool_t * plog,apr_pool_t * ptemp,server_rec * s)3604 static int jk_post_config(apr_pool_t * pconf,
3605 apr_pool_t * plog,
3606 apr_pool_t * ptemp, server_rec * s)
3607 {
3608 apr_status_t rv;
3609 jk_server_conf_t *conf;
3610 server_rec *srv = s;
3611 const char *err_string = NULL;
3612 int remain;
3613 void *data = NULL;
3614
3615 remain = jk_check_buffer_size();
3616 if (remain < 0) {
3617 ap_log_error(APLOG_MARK, APLOG_CRIT, 0, s,
3618 "mod_jk: JK_MAX_ATTRIBUTE_NAME_LEN in jk_util.c is too small, "
3619 "increase by %d", -1 * remain);
3620 return HTTP_INTERNAL_SERVER_ERROR;
3621 }
3622 apr_pool_userdata_get(&data, JK_LOG_LOCK_KEY, s->process->pool);
3623 if (data == NULL) {
3624 /* create the jk log lockfiles in the parent */
3625 if ((rv = apr_global_mutex_create(&jk_log_lock, NULL,
3626 APR_LOCK_DEFAULT,
3627 s->process->pool)) != APR_SUCCESS) {
3628 ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
3629 "mod_jk: could not create jk_log_lock");
3630 return HTTP_INTERNAL_SERVER_ERROR;
3631 }
3632
3633 #if JK_NEED_SET_MUTEX_PERMS
3634 #if (MODULE_MAGIC_NUMBER_MAJOR >= 20090208)
3635 rv = ap_unixd_set_global_mutex_perms(jk_log_lock);
3636 #else
3637 rv = unixd_set_global_mutex_perms(jk_log_lock);
3638 #endif
3639 if (rv != APR_SUCCESS) {
3640 ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
3641 "mod_jk: Could not set permissions on "
3642 "jk_log_lock; check User and Group directives");
3643 return HTTP_INTERNAL_SERVER_ERROR;
3644 }
3645 #endif
3646 apr_pool_userdata_set((const void *)jk_log_lock, JK_LOG_LOCK_KEY,
3647 apr_pool_cleanup_null, s->process->pool);
3648 }
3649 else {
3650 jk_log_lock = (apr_global_mutex_t *)data;
3651 }
3652
3653 main_server = s;
3654 jk_log_fps = apr_hash_make(pconf);
3655
3656 if (!s->is_virtual) {
3657 conf = (jk_server_conf_t *)ap_get_module_config(s->module_config,
3658 &jk_module);
3659 if (conf->was_initialized == JK_FALSE) {
3660 /* step through the servers and open each jk logfile
3661 * and do additional post config initialization.
3662 */
3663 for (; srv; srv = srv->next) {
3664 jk_server_conf_t *sconf = (jk_server_conf_t *)ap_get_module_config(srv->module_config,
3665 &jk_module);
3666
3667 /*
3668 * If a virtual server contains no JK directive, httpd shares
3669 * the config structure. But we don't want to share some settings
3670 * by default, especially the JkMount rules.
3671 * Therefore we check, if this config structure really belongs to this
3672 * vhost, otherwise we create a new one and merge.
3673 */
3674 if (sconf && sconf->s != srv) {
3675 jk_server_conf_t *srvconf = (jk_server_conf_t *)create_jk_config(pconf, srv);
3676 sconf = (jk_server_conf_t *)merge_jk_config(pconf, sconf, srvconf);
3677 ap_set_module_config(srv->module_config, &jk_module, sconf);
3678 }
3679
3680 if (sconf && sconf->was_initialized == JK_FALSE) {
3681 sconf->was_initialized = JK_TRUE;
3682 if (open_jklog(srv, pconf))
3683 return HTTP_INTERNAL_SERVER_ERROR;
3684 sconf->options &= ~sconf->exclude_options;
3685 dump_options(srv, pconf);
3686 if (sconf->uri_to_context) {
3687 if (!uri_worker_map_alloc(&(sconf->uw_map),
3688 sconf->uri_to_context, sconf->log))
3689 jk_error_exit(JKLOG_MARK, APLOG_EMERG, srv,
3690 srv->process->pool, "Memory error");
3691 if (sconf->options & JK_OPT_REJECTUNSAFE)
3692 sconf->uw_map->reject_unsafe = 1;
3693 else
3694 sconf->uw_map->reject_unsafe = 0;
3695 if (sconf->mount_file) {
3696 sconf->uw_map->fname = sconf->mount_file;
3697 sconf->uw_map->reload = sconf->mount_file_reload;
3698 uri_worker_map_switch(sconf->uw_map, sconf->log);
3699 uri_worker_map_load(sconf->uw_map, sconf->log);
3700 }
3701 if (sconf->options & JK_OPT_COLLAPSEMASK) {
3702 ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s,
3703 "Deprecated CollapseSlashes setting ignored");
3704 }
3705 }
3706 else {
3707 if (sconf->mountcopy == JK_TRUE) {
3708 sconf->uw_map = conf->uw_map;
3709 }
3710 }
3711 if (sconf->format_string) {
3712 sconf->format =
3713 parse_request_log_string(pconf, sconf->format_string, &err_string);
3714 if (sconf->format == NULL)
3715 ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
3716 "JkRequestLogFormat format array NULL");
3717 }
3718 if (sconf->envvars && sconf->envvars_has_own) {
3719 int i;
3720 const apr_array_header_t *arr;
3721 const apr_table_entry_t *elts;
3722 envvar_item *item;
3723 const char *envvar_def;
3724
3725 arr = apr_table_elts(sconf->envvars);
3726 if (arr) {
3727 elts = (const apr_table_entry_t *)arr->elts;
3728 for (i = 0; i < arr->nelts; ++i) {
3729 item = (envvar_item *)apr_array_push(sconf->envvar_items);
3730 if (!item)
3731 return HTTP_INTERNAL_SERVER_ERROR;
3732 item->name = elts[i].key;
3733 envvar_def = apr_table_get(sconf->envvars_def, elts[i].key);
3734 if (envvar_def && !strcmp("1", envvar_def) ) {
3735 item->value = elts[i].val;
3736 item->has_default = 1;
3737 }
3738 else {
3739 item->value = "";
3740 item->has_default = 0;
3741 }
3742 }
3743 }
3744 }
3745 }
3746 }
3747 conf->was_initialized = JK_TRUE;
3748 if (init_jk(pconf, conf, s) == JK_FALSE)
3749 return HTTP_INTERNAL_SERVER_ERROR;
3750 if (conf->uw_map) {
3751 uri_worker_map_ext(conf->uw_map, conf->log);
3752 uri_worker_map_switch(conf->uw_map, conf->log);
3753 }
3754 for (srv = s; srv; srv = srv->next) {
3755 jk_server_conf_t *sconf = (jk_server_conf_t *)ap_get_module_config(srv->module_config,
3756 &jk_module);
3757 if (conf->uw_map != sconf->uw_map && sconf->uw_map) {
3758 uri_worker_map_ext(sconf->uw_map, sconf->log);
3759 uri_worker_map_switch(sconf->uw_map, sconf->log);
3760 }
3761 }
3762
3763 }
3764 }
3765
3766 return OK;
3767 }
3768
3769 /** Use the internal mod_jk mappings to find if this is a request for
3770 * tomcat and what worker to use.
3771 */
jk_translate(request_rec * r)3772 static int jk_translate(request_rec * r)
3773 {
3774 jk_request_conf_t *rconf = apr_palloc(r->pool, sizeof(jk_request_conf_t));
3775 rconf->jk_handled = JK_FALSE;
3776 rconf->rule_extensions = NULL;
3777 rconf->orig_uri = NULL;
3778 ap_set_module_config(r->request_config, &jk_module, rconf);
3779
3780 if (!r->proxyreq) {
3781 jk_server_conf_t *conf =
3782 (jk_server_conf_t *) ap_get_module_config(r->server->
3783 module_config,
3784 &jk_module);
3785
3786 if (conf) {
3787 char *clean_uri;
3788 int rc;
3789 const char *worker;
3790
3791 JK_TRACE_ENTER(conf->log);
3792
3793 if ((r->handler != NULL) && (!strcmp(r->handler, JK_HANDLER))) {
3794 /* Somebody already set the handler, probably manual config
3795 * or "native" configuration, no need for extra overhead
3796 */
3797 if (JK_IS_DEBUG_LEVEL(conf->log))
3798 jk_log(conf->log, JK_LOG_DEBUG,
3799 "Manually mapped, no need to call uri_to_worker");
3800 JK_TRACE_EXIT(conf->log);
3801 return DECLINED;
3802 }
3803
3804 if (apr_table_get(r->subprocess_env, "no-jk")) {
3805 if (JK_IS_DEBUG_LEVEL(conf->log))
3806 jk_log(conf->log, JK_LOG_DEBUG,
3807 "Into translate no-jk env var detected for uri=%s, declined",
3808 r->uri);
3809
3810 JK_TRACE_EXIT(conf->log);
3811 return DECLINED;
3812 }
3813
3814 clean_uri = apr_pstrdup(r->pool, r->uri);
3815 rc = jk_servlet_normalize(clean_uri, conf->log);
3816 if (rc != 0) {
3817 JK_TRACE_EXIT(conf->log);
3818 return HTTP_BAD_REQUEST;
3819 }
3820
3821 /* Special case to make sure that apache can serve a directory
3822 listing if there are no matches for the DirectoryIndex and
3823 Tomcat webapps are mapped into apache using JkAutoAlias. */
3824 if (r->main != NULL && r->main->handler != NULL &&
3825 (conf->alias_dir != NULL) &&
3826 !strcmp(r->main->handler, DIR_MAGIC_TYPE)) {
3827
3828 /* Append the request uri to the JkAutoAlias directory and
3829 determine if the file exists. */
3830 apr_finfo_t finfo;
3831 finfo.filetype = APR_NOFILE;
3832 /* Map uri to a context static file */
3833 if (strlen(clean_uri) > 1) {
3834 char *context_path = NULL;
3835
3836 context_path = apr_pstrcat(r->pool, conf->alias_dir, clean_uri, NULL);
3837 if (context_path != NULL) {
3838 apr_stat(&finfo, context_path, APR_FINFO_TYPE,
3839 r->pool);
3840 }
3841 }
3842 if (finfo.filetype != APR_REG) {
3843 if (JK_IS_DEBUG_LEVEL(conf->log))
3844 jk_log(conf->log, JK_LOG_DEBUG,
3845 "JkAutoAlias, no DirectoryIndex file for URI %s",
3846 r->uri);
3847 JK_TRACE_EXIT(conf->log);
3848 return DECLINED;
3849 }
3850 }
3851 if (!conf->uw_map) {
3852 if (JK_IS_DEBUG_LEVEL(conf->log))
3853 jk_log(conf->log, JK_LOG_DEBUG,
3854 "missing uri map for %s:%s",
3855 conf->s->server_hostname ? conf->s->server_hostname : "_default_",
3856 r->uri);
3857 JK_TRACE_EXIT(conf->log);
3858 return DECLINED;
3859 }
3860 else {
3861 rule_extension_t *e;
3862 worker = map_uri_to_worker_ext(conf->uw_map, clean_uri,
3863 NULL, &e, NULL, conf->log);
3864 if (worker) {
3865 rconf->rule_extensions = e;
3866 rconf->orig_uri = r->uri;
3867 r->uri = clean_uri;
3868 }
3869 }
3870
3871 if (worker) {
3872 r->handler = apr_pstrdup(r->pool, JK_HANDLER);
3873 apr_table_setn(r->notes, JK_NOTE_WORKER_NAME, worker);
3874
3875 /* This could be a sub-request, possibly from mod_dir */
3876 /* Also add the the HANDLER to the main request */
3877 if (r->main) {
3878 r->main->handler = apr_pstrdup(r->main->pool, JK_HANDLER);
3879 apr_table_setn(r->main->notes, JK_NOTE_WORKER_NAME, worker);
3880 }
3881
3882 JK_TRACE_EXIT(conf->log);
3883 return OK;
3884 }
3885 else if (conf->alias_dir != NULL) {
3886 /* Automatically map uri to a context static file */
3887 if (JK_IS_DEBUG_LEVEL(conf->log))
3888 jk_log(conf->log, JK_LOG_DEBUG,
3889 "check alias_dir: %s",
3890 conf->alias_dir);
3891 if (strlen(clean_uri) > 1) {
3892 /* Get the context directory name */
3893 char *context_dir = NULL;
3894 char *context_path = NULL;
3895 char *child_dir = NULL;
3896 char *index = clean_uri;
3897 char *suffix = strchr(index + 1, '/');
3898 if (suffix != NULL) {
3899 int size = (int)(suffix - index);
3900 context_dir = apr_pstrndup(r->pool, index, size);
3901 /* Get the context child directory name */
3902 index = index + size + 1;
3903 suffix = strchr(index, '/');
3904 if (suffix != NULL) {
3905 size = (int)(suffix - index);
3906 child_dir = apr_pstrndup(r->pool, index, size);
3907 }
3908 else {
3909 child_dir = index;
3910 }
3911 /* Deny access to WEB-INF and META-INF directories */
3912 if (child_dir != NULL) {
3913 if (JK_IS_DEBUG_LEVEL(conf->log))
3914 jk_log(conf->log, JK_LOG_DEBUG,
3915 "AutoAlias child_dir: %s",
3916 child_dir);
3917 if (!strcasecmp(child_dir, "WEB-INF")
3918 || !strcasecmp(child_dir, "META-INF")) {
3919 if (JK_IS_DEBUG_LEVEL(conf->log))
3920 jk_log(conf->log, JK_LOG_DEBUG,
3921 "AutoAlias HTTP_NOT_FOUND for URI: %s",
3922 r->uri);
3923 JK_TRACE_EXIT(conf->log);
3924 return HTTP_NOT_FOUND;
3925 }
3926 }
3927 }
3928 else {
3929 context_dir = apr_pstrdup(r->pool, index);
3930 }
3931
3932 context_path = apr_pstrcat(r->pool, conf->alias_dir, context_dir, NULL);
3933 if (context_path != NULL) {
3934 apr_finfo_t finfo;
3935 finfo.filetype = APR_NOFILE;
3936 apr_stat(&finfo, context_path, APR_FINFO_TYPE,
3937 r->pool);
3938 if (finfo.filetype == APR_DIR) {
3939 char *ret = apr_pstrcat(r->pool, conf->alias_dir, clean_uri, NULL);
3940 /* Add code to verify real path ap_os_canonical_name */
3941 if (ret != NULL) {
3942 if (JK_IS_DEBUG_LEVEL(conf->log))
3943 jk_log(conf->log, JK_LOG_DEBUG,
3944 "AutoAlias OK for file: %s",
3945 ret);
3946 r->filename = ret;
3947 JK_TRACE_EXIT(conf->log);
3948 return OK;
3949 }
3950 }
3951 else {
3952 /* Deny access to war files in web app directory */
3953 int size = (int)strlen(context_dir);
3954 if (size > 4
3955 && !strcasecmp(context_dir + (size - 4),
3956 ".war")) {
3957 if (JK_IS_DEBUG_LEVEL(conf->log))
3958 jk_log(conf->log, JK_LOG_DEBUG,
3959 "AutoAlias HTTP_FORBIDDEN for URI: %s",
3960 r->uri);
3961 JK_TRACE_EXIT(conf->log);
3962 return HTTP_FORBIDDEN;
3963 }
3964 }
3965 }
3966 }
3967 }
3968 else {
3969 if (JK_IS_DEBUG_LEVEL(conf->log))
3970 jk_log(conf->log, JK_LOG_DEBUG,
3971 "no match for %s found",
3972 r->uri);
3973 }
3974 }
3975 }
3976
3977 return DECLINED;
3978 }
3979
3980 /* bypass the directory_walk and file_walk for non-file requests */
jk_map_to_storage(request_rec * r)3981 static int jk_map_to_storage(request_rec * r)
3982 {
3983
3984 jk_request_conf_t *rconf = ap_get_module_config(r->request_config, &jk_module);
3985 if (rconf == NULL) {
3986 rconf = apr_palloc(r->pool, sizeof(jk_request_conf_t));
3987 rconf->jk_handled = JK_FALSE;
3988 rconf->rule_extensions = NULL;
3989 rconf->orig_uri = NULL;
3990 ap_set_module_config(r->request_config, &jk_module, rconf);
3991 }
3992
3993 if (!r->proxyreq && !apr_table_get(r->notes, JK_NOTE_WORKER_NAME)) {
3994 jk_server_conf_t *conf =
3995 (jk_server_conf_t *) ap_get_module_config(r->server->
3996 module_config,
3997 &jk_module);
3998
3999 if (conf) {
4000 char *clean_uri;
4001 int rc;
4002 const char *worker;
4003
4004 JK_TRACE_ENTER(conf->log);
4005
4006 if ((r->handler != NULL) && (!strcmp(r->handler, JK_HANDLER))) {
4007 /* Somebody already set the handler, probably manual config
4008 * or "native" configuration, no need for extra overhead
4009 */
4010 if (JK_IS_DEBUG_LEVEL(conf->log))
4011 jk_log(conf->log, JK_LOG_DEBUG,
4012 "Manually mapped, no need to call uri_to_worker");
4013 JK_TRACE_EXIT(conf->log);
4014 return DECLINED;
4015 }
4016
4017 if (apr_table_get(r->subprocess_env, "no-jk")) {
4018 if (JK_IS_DEBUG_LEVEL(conf->log))
4019 jk_log(conf->log, JK_LOG_DEBUG,
4020 "Into map_to_storage no-jk env var detected for uri=%s, declined",
4021 r->uri);
4022
4023 JK_TRACE_EXIT(conf->log);
4024 return DECLINED;
4025 }
4026
4027 // Not a URI based request - e.g. file based SSI include
4028 if (strlen(r->uri) == 0) {
4029 jk_log(conf->log, JK_LOG_DEBUG,
4030 "File based (sub-)request for file=%s. No URI to match.",
4031 r->filename);
4032 JK_TRACE_EXIT(conf->log);
4033 return DECLINED;
4034 }
4035
4036 clean_uri = apr_pstrdup(r->pool, r->uri);
4037 rc = jk_servlet_normalize(clean_uri, conf->log);
4038 if (rc != 0) {
4039 JK_TRACE_EXIT(conf->log);
4040 return HTTP_BAD_REQUEST;
4041 }
4042
4043 if (!conf->uw_map) {
4044 if (JK_IS_DEBUG_LEVEL(conf->log))
4045 jk_log(conf->log, JK_LOG_DEBUG,
4046 "missing uri map for %s:%s",
4047 conf->s->server_hostname ? conf->s->server_hostname : "_default_",
4048 r->uri);
4049 JK_TRACE_EXIT(conf->log);
4050 return DECLINED;
4051 }
4052 else {
4053 rule_extension_t *e;
4054 worker = map_uri_to_worker_ext(conf->uw_map, clean_uri,
4055 NULL, &e, NULL, conf->log);
4056 if (worker) {
4057 rconf->rule_extensions = e;
4058 rconf->orig_uri = r->uri;
4059 r->uri = clean_uri;
4060 }
4061 }
4062
4063 if (worker) {
4064 r->handler = apr_pstrdup(r->pool, JK_HANDLER);
4065 apr_table_setn(r->notes, JK_NOTE_WORKER_NAME, worker);
4066
4067 /* This could be a sub-request, possibly from mod_dir */
4068 if (r->main)
4069 apr_table_setn(r->main->notes, JK_NOTE_WORKER_NAME, worker);
4070
4071 }
4072 else {
4073 if (JK_IS_DEBUG_LEVEL(conf->log))
4074 jk_log(conf->log, JK_LOG_DEBUG,
4075 "no match for %s found",
4076 r->uri);
4077 if (conf->strip_session == JK_TRUE && conf->strip_session_name) {
4078 if (r->uri) {
4079 jk_strip_session_id(r->uri, conf->strip_session_name, conf->log);
4080 }
4081 if (r->filename) {
4082 jk_strip_session_id(r->filename, conf->strip_session_name, conf->log);
4083 }
4084 JK_TRACE_EXIT(conf->log);
4085 return DECLINED;
4086 }
4087 }
4088 JK_TRACE_EXIT(conf->log);
4089 }
4090 }
4091
4092 if (apr_table_get(r->notes, JK_NOTE_WORKER_NAME)) {
4093
4094 /* First find just the name of the file, no directory */
4095 r->filename = (char *)apr_filepath_name_get(r->uri);
4096
4097 /* Only if sub-request for a directory, most likely from mod_dir */
4098 if (r->main && r->main->filename &&
4099 (!apr_filepath_name_get(r->main->filename) ||
4100 !strlen(apr_filepath_name_get(r->main->filename)))) {
4101
4102 /* The filename from the main request will be set to what should
4103 * be picked up, aliases included. Tomcat will need to know about
4104 * those aliases or things won't work for them. Normal files should
4105 * be fine. */
4106
4107 /* Need absolute path to stat */
4108 if (apr_filepath_merge(&r->filename,
4109 r->main->filename, r->filename,
4110 APR_FILEPATH_SECUREROOT |
4111 APR_FILEPATH_TRUENAME, r->pool)
4112 != APR_SUCCESS) {
4113 return DECLINED; /* We should never get here, very bad */
4114 }
4115
4116 /* Stat the file so that mod_dir knows it's there */
4117 apr_stat(&r->finfo, r->filename, APR_FINFO_TYPE, r->pool);
4118 }
4119
4120 return OK;
4121 }
4122 return DECLINED;
4123 }
4124
jk_register_hooks(apr_pool_t * p)4125 static void jk_register_hooks(apr_pool_t * p)
4126 {
4127 ap_hook_post_config(jk_post_config, NULL, NULL, APR_HOOK_MIDDLE);
4128 ap_hook_child_init(jk_child_init, NULL, NULL, APR_HOOK_MIDDLE);
4129 ap_hook_translate_name(jk_translate, NULL, NULL, APR_HOOK_MIDDLE);
4130 ap_hook_map_to_storage(jk_map_to_storage, NULL, NULL, APR_HOOK_MIDDLE);
4131 ap_hook_handler(jk_handler, NULL, NULL, APR_HOOK_MIDDLE);
4132 ap_hook_log_transaction(request_log_transaction, NULL, NULL, APR_HOOK_MIDDLE);
4133 }
4134
4135 module AP_MODULE_DECLARE_DATA jk_module = {
4136 STANDARD20_MODULE_STUFF,
4137 NULL, /* dir config creater */
4138 NULL, /* dir merger --- default is to override */
4139 create_jk_config, /* server config */
4140 merge_jk_config, /* merge server config */
4141 jk_cmds, /* command ap_table_t */
4142 jk_register_hooks /* register hooks */
4143 };
4144