mod_proxy_balancer.c revision 53412cc2f0c1676b1df5cc65f54e1784e0dc42ca
181e56d8b348d301d615ccf5465ae600fee2867berikabele/* Copyright 1999-2005 The Apache Software Foundation or its licensors, as
181e56d8b348d301d615ccf5465ae600fee2867berikabele * applicable.
fd9abdda70912b99b24e3bf1a38f26fde908a74cnd *
fd9abdda70912b99b24e3bf1a38f26fde908a74cnd * Licensed under the Apache License, Version 2.0 (the "License");
fd9abdda70912b99b24e3bf1a38f26fde908a74cnd * you may not use this file except in compliance with the License.
dd9f0e560e29dc86fba5f5d4fa5e72cda5cefb16slive * You may obtain a copy of the License at
dd9f0e560e29dc86fba5f5d4fa5e72cda5cefb16slive *
dd9f0e560e29dc86fba5f5d4fa5e72cda5cefb16slive * http://www.apache.org/licenses/LICENSE-2.0
5a58787efeb02a1c3f06569d019ad81fd2efa06end *
96ad5d81ee4a2cc66a4ae19893efc8aa6d06fae7jailletc * Unless required by applicable law or agreed to in writing, software
7add1372edb1ee95a2c4d1314df4c7567bda7c62jim * distributed under the License is distributed on an "AS IS" BASIS,
7add1372edb1ee95a2c4d1314df4c7567bda7c62jim * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
d29d9ab4614ff992b0e8de6e2b88d52b6f1f153erbowen * See the License for the specific language governing permissions and
2e545ce2450a9953665f701bb05350f0d3f26275nd * limitations under the License.
d29d9ab4614ff992b0e8de6e2b88d52b6f1f153erbowen */
d29d9ab4614ff992b0e8de6e2b88d52b6f1f153erbowen
7add1372edb1ee95a2c4d1314df4c7567bda7c62jim/* Load balancer module for Apache proxy */
5a58787efeb02a1c3f06569d019ad81fd2efa06end
af33a4994ae2ff15bc67d19ff1a7feb906745bf8rbowen#define CORE_PRIVATE
3f08db06526d6901aa08c110b5bc7dde6bc39905nd
7add1372edb1ee95a2c4d1314df4c7567bda7c62jim#include "mod_proxy.h"
7add1372edb1ee95a2c4d1314df4c7567bda7c62jim#include "ap_mpm.h"
5a58787efeb02a1c3f06569d019ad81fd2efa06end#include "apr_version.h"
3f08db06526d6901aa08c110b5bc7dde6bc39905nd#include "apr_hooks.h"
3b3b7fc78d1f5bfc2769903375050048ff41ff26nd
7add1372edb1ee95a2c4d1314df4c7567bda7c62jimmodule AP_MODULE_DECLARE_DATA proxy_balancer_module;
ee649f9236fe7fcf255bbfa11f2cce080f996521sf
7f5b59ccc63c0c0e3e678a168f09ee6a2f51f9d0ndstatic int proxy_balancer_canon(request_rec *r, char *url)
1ac39787115a288f5e848344b1b1e8dccb1c58f1nd{
f086b4b402fa9a2fefc7dda85de2a3cc1cd0a654rjung char *host, *path, *search;
3b3b7fc78d1f5bfc2769903375050048ff41ff26nd const char *err;
3b3b7fc78d1f5bfc2769903375050048ff41ff26nd apr_port_t port = 0;
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen
c68aa7f213d409d464eaa6b963afb28678548f4frbowen if (strncasecmp(url, "balancer:", 9) == 0) {
2df40fa998d3364133c4dd29eb395f5ae70dfc1fslive url += 9;
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen }
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen else {
2df40fa998d3364133c4dd29eb395f5ae70dfc1fslive return DECLINED;
2df40fa998d3364133c4dd29eb395f5ae70dfc1fslive }
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
dd9f0e560e29dc86fba5f5d4fa5e72cda5cefb16slive "proxy: BALANCER: canonicalising URL %s", url);
7add1372edb1ee95a2c4d1314df4c7567bda7c62jim
2684d5de7d8996ac96df3a37e8f8a49c502f26dfjsl /* do syntatic check.
5a58787efeb02a1c3f06569d019ad81fd2efa06end * We break the URL into host, port, path, search
7add1372edb1ee95a2c4d1314df4c7567bda7c62jim */
cfebc848e619d381e71d40b6f489db4aac180ee5rbowen err = ap_proxy_canon_netloc(r->pool, &url, NULL, NULL, &host, &port);
7add1372edb1ee95a2c4d1314df4c7567bda7c62jim if (err) {
7add1372edb1ee95a2c4d1314df4c7567bda7c62jim ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
5a58787efeb02a1c3f06569d019ad81fd2efa06end "error parsing URL %s: %s",
7add1372edb1ee95a2c4d1314df4c7567bda7c62jim url, err);
5a58787efeb02a1c3f06569d019ad81fd2efa06end return HTTP_BAD_REQUEST;
7add1372edb1ee95a2c4d1314df4c7567bda7c62jim }
7add1372edb1ee95a2c4d1314df4c7567bda7c62jim /* now parse path/search args, according to rfc1738 */
30471a4650391f57975f60bbb6e4a90be7b284bfhumbedooh /* N.B. if this isn't a true proxy request, then the URL _path_
7add1372edb1ee95a2c4d1314df4c7567bda7c62jim * has already been decoded. True proxy requests have r->uri
5a58787efeb02a1c3f06569d019ad81fd2efa06end * == r->unparsed_uri, and no others have that property.
5a58787efeb02a1c3f06569d019ad81fd2efa06end */
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen if (r->uri == r->unparsed_uri) {
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen search = strchr(url, '?');
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen if (search != NULL)
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen *(search++) = '\0';
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen }
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen else
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen search = r->args;
2684d5de7d8996ac96df3a37e8f8a49c502f26dfjsl
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen /* process path */
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen path = ap_proxy_canonenc(r->pool, url, strlen(url), enc_path, 0, r->proxyreq);
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen if (path == NULL)
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen return HTTP_BAD_REQUEST;
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen
dd9f0e560e29dc86fba5f5d4fa5e72cda5cefb16slive r->filename = apr_pstrcat(r->pool, "proxy:balancer://", host,
181e56d8b348d301d615ccf5465ae600fee2867berikabele "/", path, (search) ? "?" : "", (search) ? search : "", NULL);
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen return OK;
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen}
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowenstatic int init_balancer_members(proxy_server_conf *conf, server_rec *s,
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen proxy_balancer *balancer)
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen{
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen int i;
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen proxy_worker *workers;
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen workers = (proxy_worker *)balancer->workers->elts;
dd9f0e560e29dc86fba5f5d4fa5e72cda5cefb16slive
181e56d8b348d301d615ccf5465ae600fee2867berikabele for (i = 0; i < balancer->workers->nelts; i++) {
181e56d8b348d301d615ccf5465ae600fee2867berikabele ap_proxy_initialize_worker_share(conf, workers, s);
dd9f0e560e29dc86fba5f5d4fa5e72cda5cefb16slive if (!(workers->s->status & PROXY_WORKER_INITIALIZED)) {
181e56d8b348d301d615ccf5465ae600fee2867berikabele workers->s->status |= (workers->status | PROXY_WORKER_INITIALIZED);
dd9f0e560e29dc86fba5f5d4fa5e72cda5cefb16slive ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
cfebc848e619d381e71d40b6f489db4aac180ee5rbowen "proxy: BALANCER: initialized balancer member %d for "
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen "balancer %s in child %" APR_PID_T_FMT " for (%s) "
2684d5de7d8996ac96df3a37e8f8a49c502f26dfjsl "min=%d max=%d smax=%d",
198c35e2b8696f42f3b2a4130f2ae1225b26d2c6humbedooh workers->id, balancer->name, getpid(),
cfebc848e619d381e71d40b6f489db4aac180ee5rbowen workers->hostname, workers->min, workers->hmax,
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen workers->smax);
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen }
2684d5de7d8996ac96df3a37e8f8a49c502f26dfjsl ++workers;
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen }
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen
cfebc848e619d381e71d40b6f489db4aac180ee5rbowen workers = (proxy_worker *)balancer->workers->elts;
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen for (i = 0; i < balancer->workers->nelts; i++) {
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen /* Set to the original configuration */
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen workers[i].s->lbstatus = workers[i].s->lbfactor =
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen (workers[i].lbfactor ? workers[i].lbfactor : 1);
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen }
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen /* Set default number of attempts to the number of
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen * workers.
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen */
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen if (!balancer->max_attempts_set && balancer->workers->nelts > 1) {
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen balancer->max_attempts = balancer->workers->nelts - 1;
7add1372edb1ee95a2c4d1314df4c7567bda7c62jim balancer->max_attempts_set = 1;
5a58787efeb02a1c3f06569d019ad81fd2efa06end }
cfebc848e619d381e71d40b6f489db4aac180ee5rbowen return 0;
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen}
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen/* Retrieve the parameter with the given name
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen * Something like 'JSESSIONID=12345...N'
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen */
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowenstatic char *get_path_param(apr_pool_t *pool, char *url,
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen const char *name)
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen{
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen char *path = NULL;
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen for (path = strstr(url, name); path; path = strstr(path + 1, name)) {
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen path += strlen(name);
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen if (*path == '=') {
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen /*
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen * Session path was found, get it's value
181e56d8b348d301d615ccf5465ae600fee2867berikabele */
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen ++path;
20189240503ef2c8f5dc6e2248b57faab4b23b5and if (strlen(path)) {
20189240503ef2c8f5dc6e2248b57faab4b23b5and char *q;
cfebc848e619d381e71d40b6f489db4aac180ee5rbowen path = apr_pstrdup(pool, path);
20189240503ef2c8f5dc6e2248b57faab4b23b5and if ((q = strchr(path, '?')))
20189240503ef2c8f5dc6e2248b57faab4b23b5and *q = '\0';
20189240503ef2c8f5dc6e2248b57faab4b23b5and return path;
20189240503ef2c8f5dc6e2248b57faab4b23b5and }
2684d5de7d8996ac96df3a37e8f8a49c502f26dfjsl }
5d01f40ffd657dd2ac567aacd93cabd162ddfa79coar }
25bc0cc439abc002c56f746a04ae3d6ed15fbd7ehumbedooh return NULL;
2684d5de7d8996ac96df3a37e8f8a49c502f26dfjsl}
dd9f0e560e29dc86fba5f5d4fa5e72cda5cefb16slive
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowenstatic char *get_cookie_param(request_rec *r, const char *name)
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen{
b9f7b2acbe4a228c3eaeb6293554ca9488330c83rbowen const char *cookies;
b9f7b2acbe4a228c3eaeb6293554ca9488330c83rbowen const char *start_cookie;
b9f7b2acbe4a228c3eaeb6293554ca9488330c83rbowen
b9f7b2acbe4a228c3eaeb6293554ca9488330c83rbowen if ((cookies = apr_table_get(r->headers_in, "Cookie"))) {
9a58dc6a2b26ec128b1270cf48810e705f1a90dbsf for (start_cookie = ap_strstr_c(cookies, name); start_cookie;
b9f7b2acbe4a228c3eaeb6293554ca9488330c83rbowen start_cookie = ap_strstr_c(start_cookie + 1, name)) {
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen if (start_cookie == cookies ||
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen start_cookie[-1] == ';' ||
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen start_cookie[-1] == ',' ||
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen isspace(start_cookie[-1])) {
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen
b9f7b2acbe4a228c3eaeb6293554ca9488330c83rbowen start_cookie += strlen(name);
b9f7b2acbe4a228c3eaeb6293554ca9488330c83rbowen while(*start_cookie && isspace(*start_cookie))
b9f7b2acbe4a228c3eaeb6293554ca9488330c83rbowen ++start_cookie;
b9f7b2acbe4a228c3eaeb6293554ca9488330c83rbowen if (*start_cookie == '=' && start_cookie[1]) {
b9f7b2acbe4a228c3eaeb6293554ca9488330c83rbowen /*
b9f7b2acbe4a228c3eaeb6293554ca9488330c83rbowen * Session cookie was found, get it's value
b9f7b2acbe4a228c3eaeb6293554ca9488330c83rbowen */
dd9f0e560e29dc86fba5f5d4fa5e72cda5cefb16slive char *end_cookie, *cookie;
181e56d8b348d301d615ccf5465ae600fee2867berikabele ++start_cookie;
181e56d8b348d301d615ccf5465ae600fee2867berikabele cookie = apr_pstrdup(r->pool, start_cookie);
181e56d8b348d301d615ccf5465ae600fee2867berikabele if ((end_cookie = strchr(cookie, ';')) != NULL)
181e56d8b348d301d615ccf5465ae600fee2867berikabele *end_cookie = '\0';
181e56d8b348d301d615ccf5465ae600fee2867berikabele if((end_cookie = strchr(cookie, ',')) != NULL)
181e56d8b348d301d615ccf5465ae600fee2867berikabele *end_cookie = '\0';
181e56d8b348d301d615ccf5465ae600fee2867berikabele return cookie;
181e56d8b348d301d615ccf5465ae600fee2867berikabele }
181e56d8b348d301d615ccf5465ae600fee2867berikabele }
181e56d8b348d301d615ccf5465ae600fee2867berikabele }
181e56d8b348d301d615ccf5465ae600fee2867berikabele }
b9f7b2acbe4a228c3eaeb6293554ca9488330c83rbowen return NULL;
dd9f0e560e29dc86fba5f5d4fa5e72cda5cefb16slive}
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen/* Find the worker that has the 'route' defined
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen */
2684d5de7d8996ac96df3a37e8f8a49c502f26dfjslstatic proxy_worker *find_route_worker(proxy_balancer *balancer,
dd9f0e560e29dc86fba5f5d4fa5e72cda5cefb16slive const char *route)
181e56d8b348d301d615ccf5465ae600fee2867berikabele{
181e56d8b348d301d615ccf5465ae600fee2867berikabele int i;
181e56d8b348d301d615ccf5465ae600fee2867berikabele proxy_worker *worker = (proxy_worker *)balancer->workers->elts;
181e56d8b348d301d615ccf5465ae600fee2867berikabele for (i = 0; i < balancer->workers->nelts; i++) {
181e56d8b348d301d615ccf5465ae600fee2867berikabele if (*(worker->s->route) && strcmp(worker->s->route, route) == 0) {
181e56d8b348d301d615ccf5465ae600fee2867berikabele return worker;
181e56d8b348d301d615ccf5465ae600fee2867berikabele }
181e56d8b348d301d615ccf5465ae600fee2867berikabele worker++;
181e56d8b348d301d615ccf5465ae600fee2867berikabele }
181e56d8b348d301d615ccf5465ae600fee2867berikabele return NULL;
181e56d8b348d301d615ccf5465ae600fee2867berikabele}
181e56d8b348d301d615ccf5465ae600fee2867berikabele
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowenstatic proxy_worker *find_session_route(proxy_balancer *balancer,
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen request_rec *r,
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen char **route,
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen char **url)
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen{
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen proxy_worker *worker = NULL;
2684d5de7d8996ac96df3a37e8f8a49c502f26dfjsl
2684d5de7d8996ac96df3a37e8f8a49c502f26dfjsl if (!balancer->sticky)
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen return NULL;
2684d5de7d8996ac96df3a37e8f8a49c502f26dfjsl /* Try to find the sticky route inside url */
2684d5de7d8996ac96df3a37e8f8a49c502f26dfjsl *route = get_path_param(r->pool, *url, balancer->sticky);
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen if (!*route)
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen *route = get_cookie_param(r, balancer->sticky);
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen "proxy: BALANCER: Found value %s for "
f6066dc0a6ad0432b74774e290c04c3cc4aa2dafrbowen "stickysession %s", *route, balancer->sticky);
dd9f0e560e29dc86fba5f5d4fa5e72cda5cefb16slive /*
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen * If we found a value for sticksession, find the first '.' within.
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen * Everything after '.' (if present) is our route.
181e56d8b348d301d615ccf5465ae600fee2867berikabele */
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen if ((*route) && ((*route = strchr(*route, '.')) != NULL ))
dd9f0e560e29dc86fba5f5d4fa5e72cda5cefb16slive (*route)++;
7add1372edb1ee95a2c4d1314df4c7567bda7c62jim if ((*route) && (**route)) {
7add1372edb1ee95a2c4d1314df4c7567bda7c62jim ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
7add1372edb1ee95a2c4d1314df4c7567bda7c62jim "proxy: BALANCER: Found route %s", *route);
dd9f0e560e29dc86fba5f5d4fa5e72cda5cefb16slive /* We have a route in path or in cookie
dd9f0e560e29dc86fba5f5d4fa5e72cda5cefb16slive * Find the worker that has this route defined.
dd9f0e560e29dc86fba5f5d4fa5e72cda5cefb16slive */
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen worker = find_route_worker(balancer, *route);
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen if (worker && !PROXY_WORKER_IS_USABLE(worker)) {
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen /* We have a worker that is unusable.
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen * It can be in error or disabled, but in case
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen * it has a redirection set use that redirection worker.
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen * This enables to safely remove the member from the
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen * balancer. Of course you will need a some kind of
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen * session replication between those two remote.
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen */
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen if (*worker->s->redirect)
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen worker = find_route_worker(balancer, worker->s->redirect);
dd9f0e560e29dc86fba5f5d4fa5e72cda5cefb16slive /* Check if the redirect worker is usable */
7add1372edb1ee95a2c4d1314df4c7567bda7c62jim if (worker && !PROXY_WORKER_IS_USABLE(worker))
dd9f0e560e29dc86fba5f5d4fa5e72cda5cefb16slive worker = NULL;
dd9f0e560e29dc86fba5f5d4fa5e72cda5cefb16slive }
5d01f40ffd657dd2ac567aacd93cabd162ddfa79coar return worker;
25bc0cc439abc002c56f746a04ae3d6ed15fbd7ehumbedooh }
dd9f0e560e29dc86fba5f5d4fa5e72cda5cefb16slive else
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen return NULL;
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen}
dd9f0e560e29dc86fba5f5d4fa5e72cda5cefb16slive
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowenstatic proxy_worker *find_best_worker(proxy_balancer *balancer,
2df40fa998d3364133c4dd29eb395f5ae70dfc1fslive request_rec *r)
2df40fa998d3364133c4dd29eb395f5ae70dfc1fslive{
2df40fa998d3364133c4dd29eb395f5ae70dfc1fslive proxy_worker *candidate = NULL;
7add1372edb1ee95a2c4d1314df4c7567bda7c62jim
dd9f0e560e29dc86fba5f5d4fa5e72cda5cefb16slive if (PROXY_THREAD_LOCK(balancer) != APR_SUCCESS)
dd9f0e560e29dc86fba5f5d4fa5e72cda5cefb16slive return NULL;
dd9f0e560e29dc86fba5f5d4fa5e72cda5cefb16slive
7add1372edb1ee95a2c4d1314df4c7567bda7c62jim candidate = (*balancer->lbmethod->finder)(balancer, r);
5a58787efeb02a1c3f06569d019ad81fd2efa06end
5a58787efeb02a1c3f06569d019ad81fd2efa06end/*
dd9f0e560e29dc86fba5f5d4fa5e72cda5cefb16slive PROXY_THREAD_UNLOCK(balancer);
cfebc848e619d381e71d40b6f489db4aac180ee5rbowen return NULL;
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen*/
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen PROXY_THREAD_UNLOCK(balancer);
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen
cfebc848e619d381e71d40b6f489db4aac180ee5rbowen if (candidate == NULL) {
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen /* All the workers are in error state or disabled.
dd9f0e560e29dc86fba5f5d4fa5e72cda5cefb16slive * If the balancer has a timeout sleep for a while
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen * and try again to find the worker. The chances are
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen * that some other thread will release a connection.
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen * By default the timeout is not set, and the server
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen * returns SERVER_BUSY.
cfebc848e619d381e71d40b6f489db4aac180ee5rbowen */
cfebc848e619d381e71d40b6f489db4aac180ee5rbowen#if APR_HAS_THREADS
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen if (balancer->timeout) {
cfebc848e619d381e71d40b6f489db4aac180ee5rbowen /* XXX: This can perhaps be build using some
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen * smarter mechanism, like tread_cond.
cfebc848e619d381e71d40b6f489db4aac180ee5rbowen * But since the statuses can came from
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen * different childs, use the provided algo.
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen */
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen apr_interval_time_t timeout = balancer->timeout;
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen apr_interval_time_t step, tval = 0;
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen /* Set the timeout to 0 so that we don't
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen * end in infinite loop
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen */
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen balancer->timeout = 0;
cfebc848e619d381e71d40b6f489db4aac180ee5rbowen step = timeout / 100;
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen while (tval < timeout) {
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen apr_sleep(step);
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen /* Try again */
181e56d8b348d301d615ccf5465ae600fee2867berikabele if ((candidate = find_best_worker(balancer, r)))
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen break;
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen tval += step;
9fc1345bb54ea7f68c2e59ff3a618c1237a30918yoshiki }
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen /* restore the timeout */
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen balancer->timeout = timeout;
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen }
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen#endif
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen }
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen return candidate;
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen}
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowenstatic int rewrite_url(request_rec *r, proxy_worker *worker,
70fce89e67f707c03f70d437a64e189a205ffc35jsl char **url)
f92d094f13138be62bcc1a4b8187d72705d2cb05jsl{
f92d094f13138be62bcc1a4b8187d72705d2cb05jsl const char *scheme = strstr(*url, "://");
f92d094f13138be62bcc1a4b8187d72705d2cb05jsl const char *path = NULL;
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen if (scheme)
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen path = ap_strchr_c(scheme + 3, '/');
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen /* we break the URL into host, port, uri */
70fce89e67f707c03f70d437a64e189a205ffc35jsl if (!worker) {
f92d094f13138be62bcc1a4b8187d72705d2cb05jsl return ap_proxyerror(r, HTTP_BAD_REQUEST, apr_pstrcat(r->pool,
f92d094f13138be62bcc1a4b8187d72705d2cb05jsl "missing worker. URI cannot be parsed: ", *url,
f92d094f13138be62bcc1a4b8187d72705d2cb05jsl NULL));
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen }
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen *url = apr_pstrcat(r->pool, worker->name, path, NULL);
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen return OK;
70fce89e67f707c03f70d437a64e189a205ffc35jsl}
f92d094f13138be62bcc1a4b8187d72705d2cb05jsl
f92d094f13138be62bcc1a4b8187d72705d2cb05jslstatic int proxy_balancer_pre_request(proxy_worker **worker,
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen proxy_balancer **balancer,
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen request_rec *r,
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen proxy_server_conf *conf, char **url)
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen{
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen int access_status;
70fce89e67f707c03f70d437a64e189a205ffc35jsl proxy_worker *runtime;
f92d094f13138be62bcc1a4b8187d72705d2cb05jsl char *route = NULL;
f92d094f13138be62bcc1a4b8187d72705d2cb05jsl apr_status_t rv;
f92d094f13138be62bcc1a4b8187d72705d2cb05jsl
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen *worker = NULL;
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen /* Step 1: check if the url is for us
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen * The url we can handle starts with 'balancer://'
dd9f0e560e29dc86fba5f5d4fa5e72cda5cefb16slive * If balancer is already provided skip the search
cfebc848e619d381e71d40b6f489db4aac180ee5rbowen * for balancer, because this is failover attempt.
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen */
cfebc848e619d381e71d40b6f489db4aac180ee5rbowen if (!*balancer &&
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen !(*balancer = ap_proxy_get_balancer(r->pool, conf, *url)))
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen return DECLINED;
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen /* Step 2: find the session route */
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen runtime = find_session_route(*balancer, r, &route, url);
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen /* Lock the LoadBalancer
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen * XXX: perhaps we need the process lock here
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen */
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen if ((rv = PROXY_THREAD_LOCK(*balancer)) != APR_SUCCESS) {
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server,
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen "proxy: BALANCER: lock");
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen return DECLINED;
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen }
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen if (runtime) {
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen int i, total_factor = 0;
9a58dc6a2b26ec128b1270cf48810e705f1a90dbsf proxy_worker *workers;
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen /* We have a sticky load balancer
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen * Update the workers status
70fce89e67f707c03f70d437a64e189a205ffc35jsl * so that even session routes get
f92d094f13138be62bcc1a4b8187d72705d2cb05jsl * into account.
f92d094f13138be62bcc1a4b8187d72705d2cb05jsl */
f92d094f13138be62bcc1a4b8187d72705d2cb05jsl workers = (proxy_worker *)(*balancer)->workers->elts;
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen for (i = 0; i < (*balancer)->workers->nelts; i++) {
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen /* Take into calculation only the workers that are
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen * not in error state or not disabled.
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen */
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen if (PROXY_WORKER_IS_USABLE(workers)) {
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen workers->s->lbstatus += workers->s->lbfactor;
70fce89e67f707c03f70d437a64e189a205ffc35jsl total_factor += workers->s->lbfactor;
f92d094f13138be62bcc1a4b8187d72705d2cb05jsl }
f92d094f13138be62bcc1a4b8187d72705d2cb05jsl workers++;
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen }
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen runtime->s->lbstatus -= total_factor;
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen runtime->s->elected++;
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen *worker = runtime;
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen }
f92d094f13138be62bcc1a4b8187d72705d2cb05jsl else if (route && (*balancer)->sticky_force) {
f92d094f13138be62bcc1a4b8187d72705d2cb05jsl ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
f92d094f13138be62bcc1a4b8187d72705d2cb05jsl "proxy: BALANCER: (%s). All workers are in error state for route (%s)",
f92d094f13138be62bcc1a4b8187d72705d2cb05jsl (*balancer)->name, route);
f92d094f13138be62bcc1a4b8187d72705d2cb05jsl PROXY_THREAD_UNLOCK(*balancer);
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen return HTTP_SERVICE_UNAVAILABLE;
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen }
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen PROXY_THREAD_UNLOCK(*balancer);
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen if (!*worker) {
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen runtime = find_best_worker(*balancer, r);
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen if (!runtime) {
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen "proxy: BALANCER: (%s). All workers are in error state",
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen (*balancer)->name);
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen return HTTP_SERVICE_UNAVAILABLE;
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen }
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen *worker = runtime;
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen }
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen /* Rewrite the url from 'balancer://url'
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen * to the 'worker_scheme://worker_hostname[:worker_port]/url'
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen * This replaces the balancers fictional name with the
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen * real hostname of the elected worker.
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen */
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen access_status = rewrite_url(r, *worker, url);
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen /* Add the session route to request notes if present */
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen if (route) {
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen apr_table_setn(r->notes, "session-sticky", (*balancer)->sticky);
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen apr_table_setn(r->notes, "session-route", route);
70fce89e67f707c03f70d437a64e189a205ffc35jsl }
70fce89e67f707c03f70d437a64e189a205ffc35jsl ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
70fce89e67f707c03f70d437a64e189a205ffc35jsl "proxy: BALANCER (%s) worker (%s) rewritten to %s",
70fce89e67f707c03f70d437a64e189a205ffc35jsl (*balancer)->name, (*worker)->name, *url);
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen return access_status;
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen}
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowenstatic int proxy_balancer_post_request(proxy_worker *worker,
70fce89e67f707c03f70d437a64e189a205ffc35jsl proxy_balancer *balancer,
70fce89e67f707c03f70d437a64e189a205ffc35jsl request_rec *r,
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen proxy_server_conf *conf)
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen{
7add1372edb1ee95a2c4d1314df4c7567bda7c62jim apr_status_t rv;
5a58787efeb02a1c3f06569d019ad81fd2efa06end
5a58787efeb02a1c3f06569d019ad81fd2efa06end if ((rv = PROXY_THREAD_LOCK(balancer)) != APR_SUCCESS) {
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server,
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen "proxy: BALANCER: lock");
cfebc848e619d381e71d40b6f489db4aac180ee5rbowen return HTTP_INTERNAL_SERVER_ERROR;
cfebc848e619d381e71d40b6f489db4aac180ee5rbowen }
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen /* TODO: calculate the bytes transferred
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen * This will enable to elect the worker that has
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen * the lowest load.
70fce89e67f707c03f70d437a64e189a205ffc35jsl * The bytes transferred depends on the protocol
70fce89e67f707c03f70d437a64e189a205ffc35jsl * used, so each protocol handler should keep the
70fce89e67f707c03f70d437a64e189a205ffc35jsl * track on that.
70fce89e67f707c03f70d437a64e189a205ffc35jsl */
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen
181e56d8b348d301d615ccf5465ae600fee2867berikabele PROXY_THREAD_UNLOCK(balancer);
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
70fce89e67f707c03f70d437a64e189a205ffc35jsl "proxy_balancer_post_request for (%s)", balancer->name);
70fce89e67f707c03f70d437a64e189a205ffc35jsl
70fce89e67f707c03f70d437a64e189a205ffc35jsl return OK;
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen}
dd9f0e560e29dc86fba5f5d4fa5e72cda5cefb16slive
181e56d8b348d301d615ccf5465ae600fee2867berikabelestatic void recalc_factors(proxy_balancer *balancer)
dd9f0e560e29dc86fba5f5d4fa5e72cda5cefb16slive{
dd9f0e560e29dc86fba5f5d4fa5e72cda5cefb16slive int i;
e2108029921973b4522af1fe5ecd634a2a55ae07slive proxy_worker *workers;
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen
dd9f0e560e29dc86fba5f5d4fa5e72cda5cefb16slive
dd9f0e560e29dc86fba5f5d4fa5e72cda5cefb16slive /* Recalculate lbfactors */
181e56d8b348d301d615ccf5465ae600fee2867berikabele workers = (proxy_worker *)balancer->workers->elts;
cdf912a26be170e1528d1f6c9db8a2a8f9937420pcs /* Special case if there is only one worker it's
181e56d8b348d301d615ccf5465ae600fee2867berikabele * load factor will always be 1
dd9f0e560e29dc86fba5f5d4fa5e72cda5cefb16slive */
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen if (balancer->workers->nelts == 1) {
e2108029921973b4522af1fe5ecd634a2a55ae07slive workers->s->lbstatus = workers->s->lbfactor = 1;
e2108029921973b4522af1fe5ecd634a2a55ae07slive return;
181e56d8b348d301d615ccf5465ae600fee2867berikabele }
cdf912a26be170e1528d1f6c9db8a2a8f9937420pcs for (i = 0; i < balancer->workers->nelts; i++) {
181e56d8b348d301d615ccf5465ae600fee2867berikabele /* Update the status entries */
dd9f0e560e29dc86fba5f5d4fa5e72cda5cefb16slive workers[i].s->lbstatus = workers[i].s->lbfactor;
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen }
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen}
dd9f0e560e29dc86fba5f5d4fa5e72cda5cefb16slive
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen/* Manages the loadfactors and member status
70fce89e67f707c03f70d437a64e189a205ffc35jsl */
cfebc848e619d381e71d40b6f489db4aac180ee5rbowenstatic int balancer_handler(request_rec *r)
70fce89e67f707c03f70d437a64e189a205ffc35jsl{
70fce89e67f707c03f70d437a64e189a205ffc35jsl void *sconf = r->server->module_config;
70fce89e67f707c03f70d437a64e189a205ffc35jsl proxy_server_conf *conf = (proxy_server_conf *)
70fce89e67f707c03f70d437a64e189a205ffc35jsl ap_get_module_config(sconf, &proxy_module);
70fce89e67f707c03f70d437a64e189a205ffc35jsl proxy_balancer *balancer, *bsel = NULL;
70fce89e67f707c03f70d437a64e189a205ffc35jsl proxy_worker *worker, *wsel = NULL;
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen apr_table_t *params = apr_table_make(r->pool, 10);
dd9f0e560e29dc86fba5f5d4fa5e72cda5cefb16slive int access_status;
181e56d8b348d301d615ccf5465ae600fee2867berikabele int i, n;
2df40fa998d3364133c4dd29eb395f5ae70dfc1fslive const char *name;
cfebc848e619d381e71d40b6f489db4aac180ee5rbowen
103f414dc9a63f76c48bc1d81162ea6f3c5ef495slive /* is this for us? */
103f414dc9a63f76c48bc1d81162ea6f3c5ef495slive if (strcmp(r->handler, "balancer-manager"))
103f414dc9a63f76c48bc1d81162ea6f3c5ef495slive return DECLINED;
2df40fa998d3364133c4dd29eb395f5ae70dfc1fslive r->allowed = (AP_METHOD_BIT << M_GET);
70fce89e67f707c03f70d437a64e189a205ffc35jsl if (r->method_number != M_GET)
70fce89e67f707c03f70d437a64e189a205ffc35jsl return DECLINED;
2df40fa998d3364133c4dd29eb395f5ae70dfc1fslive
2df40fa998d3364133c4dd29eb395f5ae70dfc1fslive if (r->args) {
cfebc848e619d381e71d40b6f489db4aac180ee5rbowen char *args = apr_pstrdup(r->pool, r->args);
70fce89e67f707c03f70d437a64e189a205ffc35jsl char *tok, *val;
70fce89e67f707c03f70d437a64e189a205ffc35jsl while (args && *args) {
7add1372edb1ee95a2c4d1314df4c7567bda7c62jim if ((val = ap_strchr(args, '='))) {
2df40fa998d3364133c4dd29eb395f5ae70dfc1fslive *val++ = '\0';
70fce89e67f707c03f70d437a64e189a205ffc35jsl if ((tok = ap_strchr(val, '&')))
7add1372edb1ee95a2c4d1314df4c7567bda7c62jim *tok++ = '\0';
2df40fa998d3364133c4dd29eb395f5ae70dfc1fslive /*
2df40fa998d3364133c4dd29eb395f5ae70dfc1fslive * Special case: workers are allowed path information
103f414dc9a63f76c48bc1d81162ea6f3c5ef495slive */
103f414dc9a63f76c48bc1d81162ea6f3c5ef495slive if ((access_status = ap_unescape_url(val)) != OK)
103f414dc9a63f76c48bc1d81162ea6f3c5ef495slive if (strcmp(args, "w") || (access_status != HTTP_NOT_FOUND))
103f414dc9a63f76c48bc1d81162ea6f3c5ef495slive return access_status;
103f414dc9a63f76c48bc1d81162ea6f3c5ef495slive apr_table_setn(params, args, val);
2df40fa998d3364133c4dd29eb395f5ae70dfc1fslive args = tok;
2df40fa998d3364133c4dd29eb395f5ae70dfc1fslive }
70fce89e67f707c03f70d437a64e189a205ffc35jsl else
70fce89e67f707c03f70d437a64e189a205ffc35jsl return HTTP_BAD_REQUEST;
70fce89e67f707c03f70d437a64e189a205ffc35jsl }
70fce89e67f707c03f70d437a64e189a205ffc35jsl }
70fce89e67f707c03f70d437a64e189a205ffc35jsl if ((name = apr_table_get(params, "b")))
7add1372edb1ee95a2c4d1314df4c7567bda7c62jim bsel = ap_proxy_get_balancer(r->pool, conf,
dd9f0e560e29dc86fba5f5d4fa5e72cda5cefb16slive apr_pstrcat(r->pool, "balancer://", name, NULL));
cfebc848e619d381e71d40b6f489db4aac180ee5rbowen if ((name = apr_table_get(params, "w"))) {
dd9f0e560e29dc86fba5f5d4fa5e72cda5cefb16slive proxy_worker *ws;
dd9f0e560e29dc86fba5f5d4fa5e72cda5cefb16slive
e6b1bd85e7da3cac168dfef875298c55829c7ce1nd ws = ap_proxy_get_worker(r->pool, conf, name);
dd9f0e560e29dc86fba5f5d4fa5e72cda5cefb16slive if (ws) {
dd9f0e560e29dc86fba5f5d4fa5e72cda5cefb16slive worker = (proxy_worker *)bsel->workers->elts;
dd9f0e560e29dc86fba5f5d4fa5e72cda5cefb16slive for (n = 0; n < bsel->workers->nelts; n++) {
dd9f0e560e29dc86fba5f5d4fa5e72cda5cefb16slive if (strcasecmp(worker->name, ws->name) == 0) {
dd9f0e560e29dc86fba5f5d4fa5e72cda5cefb16slive wsel = worker;
70fce89e67f707c03f70d437a64e189a205ffc35jsl break;
5d81a8bafa2703e966db5bfd5abb33b176d47589nd }
cfebc848e619d381e71d40b6f489db4aac180ee5rbowen ++worker;
5d81a8bafa2703e966db5bfd5abb33b176d47589nd }
5d81a8bafa2703e966db5bfd5abb33b176d47589nd }
7add1372edb1ee95a2c4d1314df4c7567bda7c62jim }
5d81a8bafa2703e966db5bfd5abb33b176d47589nd /* First set the params */
5d81a8bafa2703e966db5bfd5abb33b176d47589nd if (bsel) {
5d81a8bafa2703e966db5bfd5abb33b176d47589nd const char *val;
4aa603e6448b99f9371397d439795c91a93637eand if ((val = apr_table_get(params, "ss"))) {
4aa603e6448b99f9371397d439795c91a93637eand if (strlen(val))
25bc0cc439abc002c56f746a04ae3d6ed15fbd7ehumbedooh bsel->sticky = apr_pstrdup(conf->pool, val);
5d81a8bafa2703e966db5bfd5abb33b176d47589nd else
7add1372edb1ee95a2c4d1314df4c7567bda7c62jim bsel->sticky = NULL;
5a58787efeb02a1c3f06569d019ad81fd2efa06end }
5a58787efeb02a1c3f06569d019ad81fd2efa06end if ((val = apr_table_get(params, "tm"))) {
9a58dc6a2b26ec128b1270cf48810e705f1a90dbsf int ival = atoi(val);
dd9f0e560e29dc86fba5f5d4fa5e72cda5cefb16slive if (ival >= 0)
cfebc848e619d381e71d40b6f489db4aac180ee5rbowen bsel->timeout = apr_time_from_sec(ival);
dd9f0e560e29dc86fba5f5d4fa5e72cda5cefb16slive }
dd9f0e560e29dc86fba5f5d4fa5e72cda5cefb16slive if ((val = apr_table_get(params, "fa"))) {
dd9f0e560e29dc86fba5f5d4fa5e72cda5cefb16slive int ival = atoi(val);
dd9f0e560e29dc86fba5f5d4fa5e72cda5cefb16slive if (ival >= 0)
dd9f0e560e29dc86fba5f5d4fa5e72cda5cefb16slive bsel->max_attempts = ival;
70fce89e67f707c03f70d437a64e189a205ffc35jsl bsel->max_attempts_set = 1;
70fce89e67f707c03f70d437a64e189a205ffc35jsl }
70fce89e67f707c03f70d437a64e189a205ffc35jsl if ((val = apr_table_get(params, "lm"))) {
7add1372edb1ee95a2c4d1314df4c7567bda7c62jim proxy_balancer_method *provider;
5a58787efeb02a1c3f06569d019ad81fd2efa06end provider = ap_lookup_provider(PROXY_LBMETHOD, val, "0");
5a58787efeb02a1c3f06569d019ad81fd2efa06end if (provider) {
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen bsel->lbmethod = provider;
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen }
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen }
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen }
dd9f0e560e29dc86fba5f5d4fa5e72cda5cefb16slive if (wsel) {
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen const char *val;
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen if ((val = apr_table_get(params, "lf"))) {
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen int ival = atoi(val);
dd9f0e560e29dc86fba5f5d4fa5e72cda5cefb16slive if (ival >= 1 && ival <= 100) {
dd9f0e560e29dc86fba5f5d4fa5e72cda5cefb16slive wsel->s->lbfactor = ival;
dd9f0e560e29dc86fba5f5d4fa5e72cda5cefb16slive if (bsel)
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen recalc_factors(bsel);
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen }
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen }
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen if ((val = apr_table_get(params, "wr"))) {
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen if (strlen(val) && strlen(val) < PROXY_WORKER_MAX_ROUTE_SIZ)
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen strcpy(wsel->s->route, val);
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen else
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen *wsel->s->route = '\0';
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen }
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen if ((val = apr_table_get(params, "rr"))) {
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen if (strlen(val) && strlen(val) < PROXY_WORKER_MAX_ROUTE_SIZ)
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen strcpy(wsel->s->redirect, val);
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen else
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen *wsel->s->redirect = '\0';
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen }
181e56d8b348d301d615ccf5465ae600fee2867berikabele if ((val = apr_table_get(params, "dw"))) {
9fc1345bb54ea7f68c2e59ff3a618c1237a30918yoshiki if (!strcasecmp(val, "Disable"))
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen wsel->s->status |= PROXY_WORKER_DISABLED;
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen else if (!strcasecmp(val, "Enable"))
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen wsel->s->status &= ~PROXY_WORKER_DISABLED;
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen }
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen }
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen if (apr_table_get(params, "xml")) {
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen ap_set_content_type(r, "text/xml");
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen ap_rputs("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n", r);
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen ap_rputs("<httpd:manager xmlns:httpd=\"http://httpd.apache.org\">\n", r);
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen ap_rputs(" <httpd:balancers>\n", r);
181e56d8b348d301d615ccf5465ae600fee2867berikabele balancer = (proxy_balancer *)conf->balancers->elts;
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen for (i = 0; i < conf->balancers->nelts; i++) {
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen ap_rputs(" <httpd:balancer>\n", r);
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen ap_rvputs(r, " <httpd:name>", balancer->name, "</httpd:name>\n", NULL);
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen ap_rputs(" <httpd:workers>\n", r);
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen worker = (proxy_worker *)balancer->workers->elts;
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen for (n = 0; n < balancer->workers->nelts; n++) {
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen ap_rputs(" <httpd:worker>\n", r);
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen ap_rvputs(r, " <httpd:scheme>", worker->scheme,
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen "</httpd:scheme>\n", NULL);
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen ap_rvputs(r, " <httpd:hostname>", worker->hostname,
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen "</httpd:hostname>\n", NULL);
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen ap_rprintf(r, " <httpd:loadfactor>%d</httpd:loadfactor>\n",
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen worker->s->lbfactor);
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen ap_rputs(" </httpd:worker>\n", r);
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen ++worker;
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen }
181e56d8b348d301d615ccf5465ae600fee2867berikabele ap_rputs(" </httpd:workers>\n", r);
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen ap_rputs(" </httpd:balancer>\n", r);
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen ++balancer;
181e56d8b348d301d615ccf5465ae600fee2867berikabele }
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen ap_rputs(" </httpd:balancers>\n", r);
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen ap_rputs("</httpd:manager>", r);
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen }
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen else {
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen ap_set_content_type(r, "text/html");
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen ap_rputs(DOCTYPE_HTML_3_2
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen "<html><head><title>Balancer Manager</title></head>\n", r);
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen ap_rputs("<body><h1>Load Balancer Manager for ", r);
181e56d8b348d301d615ccf5465ae600fee2867berikabele ap_rvputs(r, ap_get_server_name(r), "</h1>\n\n", NULL);
181e56d8b348d301d615ccf5465ae600fee2867berikabele ap_rvputs(r, "<dl><dt>Server Version: ",
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen ap_get_server_version(), "</dt>\n", NULL);
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen ap_rvputs(r, "<dt>Server Built: ",
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen ap_get_server_built(), "\n</dt></dl>\n", NULL);
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen balancer = (proxy_balancer *)conf->balancers->elts;
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen for (i = 0; i < conf->balancers->nelts; i++) {
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen
181e56d8b348d301d615ccf5465ae600fee2867berikabele ap_rputs("<hr />\n<h3>LoadBalancer Status for ", r);
181e56d8b348d301d615ccf5465ae600fee2867berikabele ap_rvputs(r, "<a href=\"", r->uri, "?b=",
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen balancer->name + sizeof("balancer://") - 1,
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen "\">", NULL);
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen ap_rvputs(r, balancer->name, "</a></h3>\n\n", NULL);
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen ap_rputs("\n\n<table border=\"0\" style=\"text-align: left;\"><tr>"
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen "<th>StickySession</th><th>Timeout</th><th>FailoverAttempts</th><th>Method</th>"
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen "</tr>\n<tr>", r);
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen ap_rvputs(r, "<td>", balancer->sticky, NULL);
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen ap_rprintf(r, "</td><td>%" APR_TIME_T_FMT "</td>",
181e56d8b348d301d615ccf5465ae600fee2867berikabele apr_time_sec(balancer->timeout));
181e56d8b348d301d615ccf5465ae600fee2867berikabele ap_rprintf(r, "<td>%d</td>\n", balancer->max_attempts);
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen ap_rprintf(r, "<td>%s</td>\n",
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen balancer->lbmethod->name);
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen ap_rputs("</table>\n<br />", r);
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen ap_rputs("\n\n<table border=\"0\" style=\"text-align: left;\"><tr>"
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen "<th>Worker URL</th>"
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen "<th>Route</th><th>RouteRedir</th>"
e884f58207082fa2136d5fc86635c31252338948erikabele "<th>Factor</th><th>Status</th>"
e884f58207082fa2136d5fc86635c31252338948erikabele "</tr>\n", r);
dd9f0e560e29dc86fba5f5d4fa5e72cda5cefb16slive
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen worker = (proxy_worker *)balancer->workers->elts;
dd9f0e560e29dc86fba5f5d4fa5e72cda5cefb16slive for (n = 0; n < balancer->workers->nelts; n++) {
dd9f0e560e29dc86fba5f5d4fa5e72cda5cefb16slive
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen ap_rvputs(r, "<tr>\n<td><a href=\"", r->uri, "?b=",
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen balancer->name + sizeof("balancer://") - 1, "&w=",
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen ap_escape_uri(r->pool, worker->name),
dd9f0e560e29dc86fba5f5d4fa5e72cda5cefb16slive "\">", NULL);
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen ap_rvputs(r, worker->name, "</a></td>", NULL);
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen ap_rvputs(r, "<td>", worker->s->route, NULL);
dd9f0e560e29dc86fba5f5d4fa5e72cda5cefb16slive ap_rvputs(r, "</td><td>", worker->s->redirect, NULL);
7add1372edb1ee95a2c4d1314df4c7567bda7c62jim ap_rprintf(r, "</td><td>%d</td><td>", worker->s->lbfactor);
5a58787efeb02a1c3f06569d019ad81fd2efa06end if (worker->s->status & PROXY_WORKER_DISABLED)
5a58787efeb02a1c3f06569d019ad81fd2efa06end ap_rputs("Dis", r);
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen else if (worker->s->status & PROXY_WORKER_IN_ERROR)
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen ap_rputs("Err", r);
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen else if (worker->s->status & PROXY_WORKER_INITIALIZED)
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen ap_rputs("Ok", r);
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen else
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen ap_rputs("-", r);
cfebc848e619d381e71d40b6f489db4aac180ee5rbowen ap_rputs("</td></tr>\n", r);
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen
cfebc848e619d381e71d40b6f489db4aac180ee5rbowen ++worker;
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen }
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen ap_rputs("</table>\n", r);
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen ++balancer;
57d0156f7bbd9ea3a72342cf9912aba61d118702rbowen }
7add1372edb1ee95a2c4d1314df4c7567bda7c62jim ap_rputs("<hr />\n", r);
dd9f0e560e29dc86fba5f5d4fa5e72cda5cefb16slive if (wsel && bsel) {
dd9f0e560e29dc86fba5f5d4fa5e72cda5cefb16slive ap_rputs("<h3>Edit worker settings for ", r);
dd9f0e560e29dc86fba5f5d4fa5e72cda5cefb16slive ap_rvputs(r, wsel->name, "</h3>\n", NULL);
dd9f0e560e29dc86fba5f5d4fa5e72cda5cefb16slive ap_rvputs(r, "<form method=\"GET\" action=\"", NULL);
221e8a19d2201546e7efe590924383c2a7f0fd72slive ap_rvputs(r, r->uri, "\">\n<dl>", NULL);
cfebc848e619d381e71d40b6f489db4aac180ee5rbowen ap_rputs("<table><tr><td>Load factor:</td><td><input name=\"lf\" type=text ", r);
221e8a19d2201546e7efe590924383c2a7f0fd72slive ap_rprintf(r, "value=\"%d\"></td><tr>\n", wsel->s->lbfactor);
221e8a19d2201546e7efe590924383c2a7f0fd72slive ap_rputs("<tr><td>Route:</td><td><input name=\"wr\" type=text ", r);
221e8a19d2201546e7efe590924383c2a7f0fd72slive ap_rvputs(r, "value=\"", wsel->route, NULL);
221e8a19d2201546e7efe590924383c2a7f0fd72slive ap_rputs("\"></td><tr>\n", r);
221e8a19d2201546e7efe590924383c2a7f0fd72slive ap_rputs("<tr><td>Route Redirect:</td><td><input name=\"rr\" type=text ", r);
221e8a19d2201546e7efe590924383c2a7f0fd72slive ap_rvputs(r, "value=\"", wsel->redirect, NULL);
5a58787efeb02a1c3f06569d019ad81fd2efa06end ap_rputs("\"></td><tr>\n", r);
3b3b7fc78d1f5bfc2769903375050048ff41ff26nd ap_rputs("<tr><td>Status:</td><td>Disabled: <input name=\"dw\" value=\"Disable\" type=radio", r);
7add1372edb1ee95a2c4d1314df4c7567bda7c62jim if (wsel->s->status & PROXY_WORKER_DISABLED)
ee649f9236fe7fcf255bbfa11f2cce080f996521sf ap_rputs(" checked", r);
7f5b59ccc63c0c0e3e678a168f09ee6a2f51f9d0nd ap_rputs("> | Enabled: <input name=\"dw\" value=\"Enable\" type=radio", r);
1ac39787115a288f5e848344b1b1e8dccb1c58f1nd if (!(wsel->s->status & PROXY_WORKER_DISABLED))
f086b4b402fa9a2fefc7dda85de2a3cc1cd0a654rjung ap_rputs(" checked", r);
727872d18412fc021f03969b8641810d8896820bhumbedooh ap_rputs("></td><tr>\n", r);
0d0ba3a410038e179b695446bb149cce6264e0abnd ap_rputs("<tr><td colspan=2><input type=submit value=\"Submit\"></td></tr>\n", r);
727872d18412fc021f03969b8641810d8896820bhumbedooh ap_rvputs(r, "</table>\n<input type=hidden name=\"w\" ", NULL);
cc7e1025de9ac63bd4db6fe7f71c158b2cf09fe4humbedooh ap_rvputs(r, "value=\"", ap_escape_uri(r->pool, wsel->name), "\">\n", NULL);
0d0ba3a410038e179b695446bb149cce6264e0abnd ap_rvputs(r, "<input type=hidden name=\"b\" ", NULL);
cc7e1025de9ac63bd4db6fe7f71c158b2cf09fe4humbedooh ap_rvputs(r, "value=\"", bsel->name + sizeof("balancer://") - 1,
727872d18412fc021f03969b8641810d8896820bhumbedooh "\">\n</form>\n", NULL);
0d0ba3a410038e179b695446bb149cce6264e0abnd ap_rputs("<hr />\n", r);
0d0ba3a410038e179b695446bb149cce6264e0abnd }
0d0ba3a410038e179b695446bb149cce6264e0abnd else if (bsel) {
ac082aefa89416cbdc9a1836eaf3bed9698201c8humbedooh ap_rputs("<h3>Edit balancer settings for ", r);
0d0ba3a410038e179b695446bb149cce6264e0abnd ap_rvputs(r, bsel->name, "</h3>\n", NULL);
0d0ba3a410038e179b695446bb149cce6264e0abnd ap_rvputs(r, "<form method=\"GET\" action=\"", NULL);
0d0ba3a410038e179b695446bb149cce6264e0abnd ap_rvputs(r, r->uri, "\">\n<dl>", NULL);
727872d18412fc021f03969b8641810d8896820bhumbedooh ap_rputs("<table><tr><td>StickySession Identifier:</td><td><input name=\"ss\" type=text ", r);
0d0ba3a410038e179b695446bb149cce6264e0abnd if (bsel->sticky)
0d0ba3a410038e179b695446bb149cce6264e0abnd ap_rvputs(r, "value=\"", bsel->sticky, "\"", NULL);
30471a4650391f57975f60bbb6e4a90be7b284bfhumbedooh ap_rputs("></td><tr>\n<tr><td>Timeout:</td><td><input name=\"tm\" type=text ", r);
205f749042ed530040a4f0080dbcb47ceae8a374rjung ap_rprintf(r, "value=\"%" APR_TIME_T_FMT "\"></td></tr>\n",
af33a4994ae2ff15bc67d19ff1a7feb906745bf8rbowen apr_time_sec(bsel->timeout));
0d0ba3a410038e179b695446bb149cce6264e0abnd ap_rputs("<tr><td>Failover Attempts:</td><td><input name=\"fa\" type=text ", r);
7fec19672a491661b2fe4b29f685bc7f4efa64d4nd ap_rprintf(r, "value=\"%d\"></td></tr>\n",
7fec19672a491661b2fe4b29f685bc7f4efa64d4nd bsel->max_attempts);
7fec19672a491661b2fe4b29f685bc7f4efa64d4nd ap_rputs("<tr><td>LB Method:</td><td><select name=\"lm\">", r);
5a58787efeb02a1c3f06569d019ad81fd2efa06end {
apr_array_header_t *methods;
ap_list_provider_names_t *method;
int i;
methods = ap_list_provider_names(r->pool, PROXY_LBMETHOD, "0");
method = (ap_list_provider_names_t *)methods->elts;
for (i = 0; i < methods->nelts; i++) {
ap_rprintf(r, "<option value=\"%s\" %s>%s</option>", method->provider_name,
(!strcasecmp(bsel->lbmethod->name, method->provider_name)) ? "selected" : "",
method->provider_name);
method++;
}
}
ap_rputs("</select></td></tr>\n", r);
ap_rputs("<tr><td colspan=2><input type=submit value=\"Submit\"></td></tr>\n", r);
ap_rvputs(r, "</table>\n<input type=hidden name=\"b\" ", NULL);
ap_rvputs(r, "value=\"", bsel->name + sizeof("balancer://") - 1,
"\">\n</form>\n", NULL);
ap_rputs("<hr />\n", r);
}
ap_rputs(ap_psignature("",r), r);
ap_rputs("</body></html>\n", r);
}
return OK;
}
static void child_init(apr_pool_t *p, server_rec *s)
{
while (s) {
void *sconf = s->module_config;
proxy_server_conf *conf;
proxy_balancer *balancer;
int i;
conf = (proxy_server_conf *)ap_get_module_config(sconf, &proxy_module);
/* Initialize shared scoreboard data */
balancer = (proxy_balancer *)conf->balancers->elts;
for (i = 0; i < conf->balancers->nelts; i++) {
init_balancer_members(conf, s, balancer);
balancer++;
}
s = s->next;
}
}
/*
* The idea behind the find_best_byrequests scheduler is the following:
*
* lbfactor is "how much we expect this worker to work", or "the worker's
* normalized work quota".
*
* lbstatus is "how urgent this worker has to work to fulfill its quota
* of work".
*
* We distribute each worker's work quota to the worker, and then look
* which of them needs to work most urgently (biggest lbstatus). This
* worker is then selected for work, and its lbstatus reduced by the
* total work quota we distributed to all workers. Thus the sum of all
* lbstatus does not change.(*)
*
* If some workers are disabled, the others will
* still be scheduled correctly.
*
* If a balancer is configured as follows:
*
* worker a b c d
* lbfactor 25 25 25 25
*
* And b gets disabled, the following schedule is produced:
*
* a c d a c d a c d ...
*
* Note that the above lbfactor setting is the *exact* same as:
*
* worker a b c d
* lbfactor 1 1 1 1
*
* Asymmetric configurations work as one would expect. For
* example:
*
* worker a b c d
* lbfactor 1 1 1 2
*
* would have a, b and c all handling about the same
* amount of load with d handling twice what a or b
* or c handles individually. So we could see:
*
* b a d c d a c d b d ...
*
*/
static proxy_worker *find_best_byrequests(proxy_balancer *balancer,
request_rec *r)
{
int i;
int total_factor = 0;
proxy_worker *worker = (proxy_worker *)balancer->workers->elts;
proxy_worker *mycandidate = NULL;
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
"proxy: Entering byrequests for BALANCER (%s)",
balancer->name);
/* First try to see if we have available candidate */
for (i = 0; i < balancer->workers->nelts; i++) {
/* If the worker is in error state run
* retry on that worker. It will be marked as
* operational if the retry timeout is elapsed.
* The worker might still be unusable, but we try
* anyway.
*/
if (!PROXY_WORKER_IS_USABLE(worker))
ap_proxy_retry_worker("BALANCER", worker, r->server);
/* Take into calculation only the workers that are
* not in error state or not disabled.
*/
if (PROXY_WORKER_IS_USABLE(worker)) {
worker->s->lbstatus += worker->s->lbfactor;
total_factor += worker->s->lbfactor;
if (!mycandidate || worker->s->lbstatus > mycandidate->s->lbstatus)
mycandidate = worker;
}
worker++;
}
if (mycandidate) {
mycandidate->s->lbstatus -= total_factor;
mycandidate->s->elected++;
}
return mycandidate;
}
/*
* The idea behind the find_best_bytraffic scheduler is the following:
*
* We know the amount of traffic (bytes in and out) handled by each
* worker. We normalize that traffic by each workers' weight. So assuming
* a setup as below:
*
* worker a b c
* lbfactor 1 1 3
*
* the scheduler will allow worker c to handle 3 times the
* traffic of a and b. If each request/response results in the
* same amount of traffic, then c would be accessed 3 times as
* often as a or b. If, for example, a handled a request that
* resulted in a large i/o bytecount, then b and c would be
* chosen more often, to even things out.
*/
static proxy_worker *find_best_bytraffic(proxy_balancer *balancer,
request_rec *r)
{
int i;
apr_off_t mytraffic = 0;
apr_off_t curmin = 0;
proxy_worker *worker = (proxy_worker *)balancer->workers->elts;
proxy_worker *mycandidate = NULL;
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
"proxy: Entering bytraffic for BALANCER (%s)",
balancer->name);
/* First try to see if we have available candidate */
for (i = 0; i < balancer->workers->nelts; i++) {
/* If the worker is in error state run
* retry on that worker. It will be marked as
* operational if the retry timeout is elapsed.
* The worker might still be unusable, but we try
* anyway.
*/
if (!PROXY_WORKER_IS_USABLE(worker))
ap_proxy_retry_worker("BALANCER", worker, r->server);
/* Take into calculation only the workers that are
* not in error state or not disabled.
*/
if (PROXY_WORKER_IS_USABLE(worker)) {
mytraffic = (worker->s->transferred/worker->s->lbfactor) +
(worker->s->read/worker->s->lbfactor);
if (!mycandidate || mytraffic < curmin) {
mycandidate = worker;
curmin = mytraffic;
}
}
worker++;
}
if (mycandidate) {
mycandidate->s->elected++;
}
return mycandidate;
}
/*
* How to add additional lbmethods:
* 1. Create func which determines "best" candidate worker
* (eg: find_best_bytraffic, above)
* 2. Register it as a provider.
*/
static const proxy_balancer_method byrequests =
{
"byrequests",
&find_best_byrequests,
NULL
};
static const proxy_balancer_method bytraffic =
{
"bytraffic",
&find_best_bytraffic,
NULL
};
static void ap_proxy_balancer_register_hook(apr_pool_t *p)
{
/* Only the mpm_winnt has child init hook handler.
* make sure that we are called after the mpm
* initializes and after the mod_proxy
*/
static const char *const aszPred[] = { "mpm_winnt.c", "mod_proxy.c", NULL};
/* manager handler */
ap_hook_handler(balancer_handler, NULL, NULL, APR_HOOK_FIRST);
ap_hook_child_init(child_init, aszPred, NULL, APR_HOOK_MIDDLE);
proxy_hook_pre_request(proxy_balancer_pre_request, NULL, NULL, APR_HOOK_FIRST);
proxy_hook_post_request(proxy_balancer_post_request, NULL, NULL, APR_HOOK_FIRST);
proxy_hook_canon_handler(proxy_balancer_canon, NULL, NULL, APR_HOOK_FIRST);
ap_register_provider(p, PROXY_LBMETHOD, "bytraffic", "0", &bytraffic);
ap_register_provider(p, PROXY_LBMETHOD, "byrequests", "0", &byrequests);
}
module AP_MODULE_DECLARE_DATA proxy_balancer_module = {
STANDARD20_MODULE_STUFF,
NULL, /* create per-directory config structure */
NULL, /* merge per-directory config structures */
NULL, /* create per-server config structure */
NULL, /* merge per-server config structures */
NULL, /* command apr_table_t */
ap_proxy_balancer_register_hook /* register hooks */
};