Mod_jk是apache module模块中鼎鼎大名的
static int jk_handler(request_rec * r) { const char *worker_name; jk_server_conf_t *xconf; jk_request_conf_t *rconf; int rc, dmt = 1; int worker_name_extension = JK_FALSE; /* We do DIR_MAGIC_TYPE here to make sure TC gets all requests, even * if they are directory requests, in case there are no static files * visible to Apache and/or DirectoryIndex was not used. This is only * used when JkOptions has ForwardDirectories set. */ /* Not for me, try next handler */ if (strcmp(r->handler, JK_HANDLER) && (dmt = strcmp(r->handler, DIR_MAGIC_TYPE))) return DECLINED; xconf = (jk_server_conf_t *) ap_get_module_config(r->server->module_config, &jk_module); JK_TRACE_ENTER(xconf->log); if (apr_table_get(r->subprocess_env, "no-jk")) { if (JK_IS_DEBUG_LEVEL(xconf->log)) jk_log(xconf->log, JK_LOG_DEBUG, "Into handler no-jk env var detected for uri=%s, declined", r->uri); JK_TRACE_EXIT(xconf->log); return DECLINED; } /* Was the option to forward directories to Tomcat set? */ if (!dmt && !(xconf->options & JK_OPT_FWDDIRS)) { JK_TRACE_EXIT(xconf->log); return DECLINED; } worker_name = apr_table_get(r->notes, JK_NOTE_WORKER_NAME); if (worker_name == NULL) { /* we may be here because of a manual directive ( that overrides translate and sets the handler directly ). We still need to know the worker. */ worker_name = apr_table_get(r->subprocess_env, xconf->worker_indicator); if (worker_name) { /* The JkWorkerIndicator environment variable has * been used to explicitely set the worker without JkMount. * This is useful in combination with LocationMatch or mod_rewrite. */ if (JK_IS_DEBUG_LEVEL(xconf->log)) jk_log(xconf->log, JK_LOG_DEBUG, "Retrieved worker (%s) from env %s for %s", worker_name, xconf->worker_indicator, r->uri); if (ap_strchr_c(worker_name, ';')) { rule_extension_t *e = apr_palloc(r->pool, sizeof(rule_extension_t)); char *w = apr_pstrdup(r->pool, worker_name); worker_name_extension = JK_TRUE; parse_rule_extensions(w, e, xconf->log); worker_name = w; rconf = (jk_request_conf_t *)ap_get_module_config(r->request_config, &jk_module); rconf->rule_extensions = e; } } else if (worker_env.num_of_workers == 1) { /** We have a single worker ( the common case ). ( lb is a bit special, it should count as a single worker but I'm not sure how ). We also have a manual config directive that explicitely give control to us. */ worker_name = worker_env.worker_list[0]; if (JK_IS_DEBUG_LEVEL(xconf->log)) jk_log(xconf->log, JK_LOG_DEBUG, "Single worker (%s) configuration for %s", worker_name, r->uri); } else { if (!xconf->uw_map) { if (JK_IS_DEBUG_LEVEL(xconf->log)) jk_log(xconf->log, JK_LOG_DEBUG, "missing uri map for %s:%s", xconf->s->server_hostname ? xconf->s->server_hostname : "_default_", r->uri); } else { rule_extension_t *e; worker_name = map_uri_to_worker_ext(xconf->uw_map, r->uri, NULL, &e, NULL, xconf->log); rconf = (jk_request_conf_t *)ap_get_module_config(r->request_config, &jk_module); rconf->rule_extensions = e; } if (worker_name == NULL && worker_env.num_of_workers) { worker_name = worker_env.worker_list[0]; if (JK_IS_DEBUG_LEVEL(xconf->log)) jk_log(xconf->log, JK_LOG_DEBUG, "Using first worker (%s) from %d workers for %s", worker_name, worker_env.num_of_workers, r->uri); } } if (worker_name) apr_table_setn(r->notes, JK_NOTE_WORKER_NAME, worker_name); } if (JK_IS_DEBUG_LEVEL(xconf->log)) jk_log(xconf->log, JK_LOG_DEBUG, "Into handler %s worker=%s" " r->proxyreq=%d", r->handler, STRNULL_FOR_NULL(worker_name), r->proxyreq); rconf = (jk_request_conf_t *)ap_get_module_config(r->request_config, &jk_module); rconf->jk_handled = JK_TRUE; /* If this is a proxy request, we'll notify an error */ if (r->proxyreq) { jk_log(xconf->log, JK_LOG_INFO, "Proxy request for worker=%s" " is not allowed", STRNULL_FOR_NULL(worker_name)); JK_TRACE_EXIT(xconf->log); return HTTP_INTERNAL_SERVER_ERROR; } /* Set up r->read_chunked flags for chunked encoding, if present */ if ((rc = ap_setup_client_block(r, REQUEST_CHUNKED_DECHUNK)) != APR_SUCCESS) { JK_TRACE_EXIT(xconf->log); return rc; } if (worker_name) { jk_worker_t *worker = wc_get_worker_for_name(worker_name, xconf->log); /* If the remote client has aborted, just ignore the request */ if (r->connection->aborted) { jk_log(xconf->log, JK_LOG_INFO, "Client connection aborted for" " worker=%s", worker_name); JK_TRACE_EXIT(xconf->log); return OK; } if (worker) { long micro, seconds; char *duration = NULL; apr_time_t rd; apr_time_t request_begin = 0; int is_error = HTTP_INTERNAL_SERVER_ERROR; int rc = JK_FALSE; apache_private_data_t private_data; jk_ws_service_t s; jk_pool_atom_t buf[SMALL_POOL_SIZE]; jk_open_pool(&private_data.p, buf, sizeof(buf)); private_data.read_body_started = JK_FALSE; private_data.r = r; if (worker_name_extension == JK_TRUE) { extension_fix(&private_data.p, worker_name, rconf->rule_extensions, xconf->log); } /* Maintain will be done by watchdog thread */ if (!jk_watchdog_interval) wc_maintain(xconf->log); jk_init_ws_service(&s); s.ws_private = &private_data; s.pool = &private_data.p; apr_table_setn(r->notes, JK_NOTE_WORKER_TYPE, wc_get_name_for_type(worker->type, xconf->log)); request_begin = apr_time_now(); if (init_ws_service(&private_data, &s, xconf)) { jk_endpoint_t *end = NULL; /* Use per/thread pool ( or "context" ) to reuse the endpoint. It's a bit faster, but I don't know how to deal with load balancing - but it's usefull for JNI */ /* worker->get_endpoint might fail if we are out of memory so check */ /* and handle it */ if (worker->get_endpoint(worker, &end, xconf->log)) { rc = end->service(end, &s, xconf->log, &is_error); end->done(&end, xconf->log); if (s.content_read < s.content_length || (s.is_chunked && !s.no_more_chunks)) { /* * If the servlet engine didn't consume all of the * request data, consume and discard all further * characters left to read from client */ char *buff = apr_palloc(r->pool, 2048); int consumed = 0; if (buff != NULL) { int rd; while ((rd = ap_get_client_block(r, buff, 2048)) > 0) { s.content_read += rd; consumed += rd; } } if (JK_IS_DEBUG_LEVEL(xconf->log)) { jk_log(xconf->log, JK_LOG_DEBUG, "Consumed %d bytes of remaining request data for worker=%s", consumed, STRNULL_FOR_NULL(worker_name)); } } } else { /* this means we couldn't get an endpoint */ jk_log(xconf->log, JK_LOG_ERROR, "Could not get endpoint" " for worker=%s", worker_name); rc = 0; /* just to make sure that we know we've failed */ } } else { jk_log(xconf->log, JK_LOG_ERROR, "Could not init service" " for worker=%s", worker_name); jk_close_pool(&private_data.p); JK_TRACE_EXIT(xconf->log); return HTTP_INTERNAL_SERVER_ERROR; } rd = apr_time_now() - request_begin; seconds = (long)apr_time_sec(rd); micro = (long)(rd - apr_time_from_sec(seconds)); duration = apr_psprintf(r->pool, "%.1ld.%.6ld", seconds, micro); apr_table_setn(r->notes, JK_NOTE_REQUEST_DURATION, duration); if (s.route && *s.route) apr_table_setn(r->notes, JK_NOTE_WORKER_ROUTE, s.route); jk_close_pool(&private_data.p); if (rc > 0) { if (s.extension.use_server_error_pages && s.http_response_status >= s.extension.use_server_error_pages) { if (JK_IS_DEBUG_LEVEL(xconf->log)) jk_log(xconf->log, JK_LOG_DEBUG, "Forwarding status=%d" " for worker=%s", s.http_response_status, worker_name); JK_TRACE_EXIT(xconf->log); return s.http_response_status; } /* If tomcat returned no body and the status is not OK, let apache handle the error code */ if (!r->sent_bodyct && r->status >= HTTP_BAD_REQUEST) { jk_log(xconf->log, JK_LOG_INFO, "No body with status=%d" " for worker=%s", r->status, worker_name); JK_TRACE_EXIT(xconf->log); return r->status; } if (JK_IS_DEBUG_LEVEL(xconf->log)) jk_log(xconf->log, JK_LOG_DEBUG, "Service finished" " with status=%d for worker=%s", r->status, worker_name); JK_TRACE_EXIT(xconf->log); return OK; /* NOT r->status, even if it has changed. */ } else if (rc == JK_CLIENT_ERROR) { if (is_error != HTTP_REQUEST_ENTITY_TOO_LARGE) r->connection->aborted = 1; jk_log(xconf->log, JK_LOG_INFO, "Aborting connection" " for worker=%s", worker_name); JK_TRACE_EXIT(xconf->log); return is_error; } else { jk_log(xconf->log, JK_LOG_INFO, "Service error=%d" " for worker=%s", rc, worker_name); JK_TRACE_EXIT(xconf->log); return is_error; } } else { jk_log(xconf->log, JK_LOG_INFO, "Could not find a worker" " for worker name=%s", worker_name); JK_TRACE_EXIT(xconf->log); return HTTP_INTERNAL_SERVER_ERROR; } } rconf->jk_handled = JK_FALSE; JK_TRACE_EXIT(xconf->log); return DECLINED; }