diff --git a/modules/proxy/mod_proxy.h b/modules/proxy/mod_proxy.h index 1ad95309de..74d7102952 100644 --- a/modules/proxy/mod_proxy.h +++ b/modules/proxy/mod_proxy.h @@ -1347,6 +1347,15 @@ APR_DECLARE_OPTIONAL_FN(int, ap_proxy_clear_connection, APR_DECLARE_OPTIONAL_FN(apr_status_t, balancer_manage, (request_rec *, apr_table_t *params)); +/** + * Do a AJP CPING and wait for CPONG on the socket + * + */ +APR_DECLARE_OPTIONAL_FN(apr_status_t, ajp_handle_cping_cpong, + (apr_socket_t *sock, request_rec *r, + apr_interval_time_t timeout)); + + /** * @param socket socket to test * @return TRUE if socket is connected/active diff --git a/modules/proxy/mod_proxy_ajp.c b/modules/proxy/mod_proxy_ajp.c index 9ae0f437da..838ef7bbe3 100644 --- a/modules/proxy/mod_proxy_ajp.c +++ b/modules/proxy/mod_proxy_ajp.c @@ -831,6 +831,7 @@ static void ap_proxy_http_register_hook(apr_pool_t *p) { proxy_hook_scheme_handler(proxy_ajp_handler, NULL, NULL, APR_HOOK_FIRST); proxy_hook_canon_handler(proxy_ajp_canon, NULL, NULL, APR_HOOK_FIRST); + APR_REGISTER_OPTIONAL_FN(ajp_handle_cping_cpong); } AP_DECLARE_MODULE(proxy_ajp) = { diff --git a/modules/proxy/mod_proxy_balancer.c b/modules/proxy/mod_proxy_balancer.c index 0bff999d80..fd361bcca6 100644 --- a/modules/proxy/mod_proxy_balancer.c +++ b/modules/proxy/mod_proxy_balancer.c @@ -1087,6 +1087,8 @@ static void push2table(const char *input, apr_table_t *params, } ap_unescape_url(key); ap_unescape_url(val); + /* hcuri, worker name, balancer name, at least are escaped when building the form, so twice */ + ap_unescape_url(val); if (allowed == NULL) { /* allow all */ apr_table_set(params, key, val); } @@ -1215,7 +1217,7 @@ static int balancer_process_balancer_worker(request_rec *r, proxy_server_conf *c *wsel->s->hcexpr = '\0'; } /* If the health check method doesn't support an expr, then null it */ - if (wsel->s->method == NONE || wsel->s->method == TCP) { + if (wsel->s->method == NONE || wsel->s->method == TCP || wsel->s->method == CPING) { *wsel->s->hcexpr = '\0'; } /* if enabling, we need to reset all lb params */ diff --git a/modules/proxy/mod_proxy_hcheck.c b/modules/proxy/mod_proxy_hcheck.c index 6f9902ea33..9986f1a9bd 100644 --- a/modules/proxy/mod_proxy_hcheck.c +++ b/modules/proxy/mod_proxy_hcheck.c @@ -75,6 +75,8 @@ typedef struct { apr_time_t *now; } baton_t; +static APR_OPTIONAL_FN_TYPE(ajp_handle_cping_cpong) *ajp_handle_cping_cpong = NULL; + static void *hc_create_config(apr_pool_t *p, server_rec *s) { sctx_t *ctx = apr_pcalloc(p, sizeof(sctx_t)); @@ -613,6 +615,39 @@ static int hc_get_backend(const char *proxy_function, proxy_conn_rec **backend, return hc_determine_connection(ctx, hc, &(*backend)->addr, ptemp); } +static apr_status_t hc_check_cping(baton_t *baton) +{ + int status; + sctx_t *ctx = baton->ctx; + proxy_worker *hc = baton->hc; + proxy_conn_rec *backend = NULL; + apr_pool_t *ptemp = baton->ptemp; + request_rec *r; + apr_interval_time_t timeout; + + if (!ajp_handle_cping_cpong) { + return APR_ENOTIMPL; + } + + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, baton->ctx->s, "HCCPING starting"); + if ((status = hc_get_backend("HCCPING", &backend, hc, ctx, baton->ptemp)) != OK) { + return backend_cleanup("HCCPING", backend, ctx->s, status); + } + if ((status = ap_proxy_connect_backend("HCCPING", backend, hc, ctx->s)) != OK) { + return backend_cleanup("HCCPING", backend, ctx->s, status); + } + r = create_request_rec(ptemp, ctx->s, baton->balancer, "CPING"); + if ((status = ap_proxy_connection_create_ex("HCCPING", backend, r)) != OK) { + return backend_cleanup("HCCPING", backend, ctx->s, status); + } + set_request_connection(r, backend->connection); + + timeout = apr_time_from_sec(10); /* 10 seconds */ + status = ajp_handle_cping_cpong(backend->sock, r, timeout); + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, baton->ctx->s, "HCCPING done %d", status); + return backend_cleanup("HCCPING", backend, ctx->s, status); +} + static apr_status_t hc_check_tcp(baton_t *baton) { int status; @@ -848,6 +883,9 @@ static void * APR_THREAD_FUNC hc_check(apr_thread_t *thread, void *b) if (hc->s->method == TCP) { rv = hc_check_tcp(baton); } + else if (hc->s->method == CPING) { + rv = hc_check_cping(baton); + } else { rv = hc_check_http(baton); } @@ -1075,6 +1113,18 @@ static int hc_post_config(apr_pool_t *p, apr_pool_t *plog, "watchdog callback registered (%s for %s)", HCHECK_WATHCHDOG_NAME, s->server_hostname); s = s->next; } + + ajp_handle_cping_cpong = APR_RETRIEVE_OPTIONAL_FN(ajp_handle_cping_cpong); + if (ajp_handle_cping_cpong) { + proxy_hcmethods_t *method = proxy_hcmethods; + for (; method->name; method++) { + if (method->method == CPING) { + method->implemented = 1; + break; + } + } + } + return OK; }