mod_proxy_balancer.c revision 842ecd514118c56a88f0b969840775dba2cbc720
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny/* Licensed to the Apache Software Foundation (ASF) under one or more
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny * contributor license agreements. See the NOTICE file distributed with
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny * this work for additional information regarding copyright ownership.
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny * The ASF licenses this file to You under the Apache License, Version 2.0
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny * (the "License"); you may not use this file except in compliance with
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny * the License. You may obtain a copy of the License at
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny * Unless required by applicable law or agreed to in writing, software
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny * distributed under the License is distributed on an "AS IS" BASIS,
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny * See the License for the specific language governing permissions and
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny * limitations under the License.
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny/* Load balancer module for Apache proxy */
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zelenymodule AP_MODULE_DECLARE_DATA proxy_balancer_module;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zelenystatic int proxy_balancer_canon(request_rec *r, char *url)
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny const char *err;
9822d4d468ec74e4e173f5adf0db12d02974cd18Sumit Bose ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
a6cca9c284724fafd670a3163812f248ba53ad97Jakub Hrozek /* do syntatic check.
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny * We break the URL into host, port, path, search
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny err = ap_proxy_canon_netloc(r->pool, &url, NULL, NULL, &host, &port);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny "error parsing URL %s: %s",
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny /* now parse path/search args, according to rfc1738 */
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny /* N.B. if this isn't a true proxy request, then the URL _path_
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny * has already been decoded. True proxy requests have r->uri
aab938c5975f0e3b85c7c79a5d718e5fefed7217Simo Sorce * == r->unparsed_uri, and no others have that property.
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce /* process path */
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce path = ap_proxy_canonenc(r->pool, url, strlen(url), enc_path, 0, r->proxyreq);
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce r->filename = apr_pstrcat(r->pool, "proxy:balancer://", host,
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny "/", path, (search) ? "?" : "", (search) ? search : "", NULL);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny r->path_info = apr_pstrcat(r->pool, "/", path, NULL);
7fe69bb6ec70bce439c6b975a9a0044c98ff502bSimo Sorcestatic int init_balancer_members(proxy_server_conf *conf, server_rec *s,
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny workers = (proxy_worker *)balancer->workers->elts;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny ap_proxy_initialize_worker_share(conf, workers, s);
aab938c5975f0e3b85c7c79a5d718e5fefed7217Simo Sorce workers = (proxy_worker *)balancer->workers->elts;
9822d4d468ec74e4e173f5adf0db12d02974cd18Sumit Bose /* Set to the original configuration */
9822d4d468ec74e4e173f5adf0db12d02974cd18Sumit Bose workers[i].s->lbstatus = workers[i].s->lbfactor =
a6cca9c284724fafd670a3163812f248ba53ad97Jakub Hrozek /* Set default number of attempts to the number of
c5711b0279ea85d69fe3c77dfb194360c346e1d7Sumit Bose if (!balancer->max_attempts_set && balancer->workers->nelts > 1) {
c5711b0279ea85d69fe3c77dfb194360c346e1d7Sumit Bose balancer->max_attempts = balancer->workers->nelts - 1;
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce/* Retrieve the parameter with the given name
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce * Something like 'JSESSIONID=12345...N'
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashovstatic char *get_path_param(apr_pool_t *pool, char *url,
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce const char *name)
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce for (path = strstr(url, name); path; path = strstr(path + 1, name)) {
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce * Session path was found, get it's value
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorcestatic char *get_cookie_param(request_rec *r, const char *name)
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce if ((cookies = apr_table_get(r->headers_in, "Cookie"))) {
9822d4d468ec74e4e173f5adf0db12d02974cd18Sumit Bose for (start_cookie = ap_strstr_c(cookies, name); start_cookie;
9822d4d468ec74e4e173f5adf0db12d02974cd18Sumit Bose start_cookie = ap_strstr_c(start_cookie + 1, name)) {
a6cca9c284724fafd670a3163812f248ba53ad97Jakub Hrozek * Session cookie was found, get it's value
c5711b0279ea85d69fe3c77dfb194360c346e1d7Sumit Bose/* Find the worker that has the 'route' defined
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bosestatic proxy_worker *find_route_worker(proxy_balancer *balancer,
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose worker = (proxy_worker *)balancer->workers->elts;
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose for (i = 0; i < balancer->workers->nelts; i++, worker++) {
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose if ( (checking_standby ? !PROXY_WORKER_IS_STANDBY(worker) : PROXY_WORKER_IS_STANDBY(worker)) )
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose if (*(worker->s->route) && strcmp(worker->s->route, route) == 0) {
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose * If the worker is in error state run
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose * retry on that worker. It will be marked as
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose * operational if the retry timeout is elapsed.
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose * The worker might still be unusable, but we try
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose ap_proxy_retry_worker("BALANCER", worker, r->server);
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce * We have a worker that is unusable.
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce * It can be in error or disabled, but in case
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce * it has a redirection set use that redirection worker.
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce * This enables to safely remove the member from the
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce * balancer. Of course you will need some kind of
a6cca9c284724fafd670a3163812f248ba53ad97Jakub Hrozek * session replication between those two remote.
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce rworker = find_route_worker(balancer, worker->s->redirect, r);
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce /* Check if the redirect worker is usable */
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce if (rworker && !PROXY_WORKER_IS_USABLE(rworker)) {
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny * If the worker is in error state run
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny * retry on that worker. It will be marked as
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny * operational if the retry timeout is elapsed.
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny * The worker might still be unusable, but we try
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny ap_proxy_retry_worker("BALANCER", rworker, r->server);
17195241500e46272018d7897d6e87249870caf2Pavel Reichlstatic proxy_worker *find_session_route(proxy_balancer *balancer,
65393a294e635822c1d7a15fe5853dc457ad8a2aSimo Sorce /* Try to find the sticky route inside url */
65393a294e635822c1d7a15fe5853dc457ad8a2aSimo Sorce *route = get_path_param(r->pool, *url, balancer->sticky);
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny "proxy: BALANCER: Found value %s for "
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny * If we found a value for sticksession, find the first '.' within.
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny * Everything after '.' (if present) is our route.
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny if ((*route) && ((*route = strchr(*route, '.')) != NULL ))
cb388d52f49f54963379cc20a25e14d17fe6e9a3Simo Sorce ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
cb388d52f49f54963379cc20a25e14d17fe6e9a3Simo Sorce /* We have a route in path or in cookie
cb388d52f49f54963379cc20a25e14d17fe6e9a3Simo Sorce * Find the worker that has this route defined.
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov worker = find_route_worker(balancer, *route, r);
204cfc89a076fd32bf34f2abb3f809304aaa88abSimo Sorcestatic proxy_worker *find_best_worker(proxy_balancer *balancer,
204cfc89a076fd32bf34f2abb3f809304aaa88abSimo Sorce candidate = (*balancer->lbmethod->finder)(balancer, r);
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny PROXY_THREAD_UNLOCK(balancer);
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny return NULL;
65393a294e635822c1d7a15fe5853dc457ad8a2aSimo Sorce /* All the workers are in error state or disabled.
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny * If the balancer has a timeout sleep for a while
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny * and try again to find the worker. The chances are
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny * that some other thread will release a connection.
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny * By default the timeout is not set, and the server
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny * returns SERVER_BUSY.
65393a294e635822c1d7a15fe5853dc457ad8a2aSimo Sorce /* XXX: This can perhaps be build using some
65393a294e635822c1d7a15fe5853dc457ad8a2aSimo Sorce * smarter mechanism, like tread_cond.
65393a294e635822c1d7a15fe5853dc457ad8a2aSimo Sorce * But since the statuses can came from
65393a294e635822c1d7a15fe5853dc457ad8a2aSimo Sorce * different childs, use the provided algo.
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny /* Set the timeout to 0 so that we don't
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny * end in infinite loop
17195241500e46272018d7897d6e87249870caf2Pavel Reichl /* Try again */
17195241500e46272018d7897d6e87249870caf2Pavel Reichl if ((candidate = find_best_worker(balancer, r)))
17195241500e46272018d7897d6e87249870caf2Pavel Reichl /* restore the timeout */
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bosestatic int rewrite_url(request_rec *r, proxy_worker *worker,
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose /* we break the URL into host, port, uri */
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose return ap_proxyerror(r, HTTP_BAD_REQUEST, apr_pstrcat(r->pool,
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose *url = apr_pstrcat(r->pool, worker->name, path, NULL);
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bosestatic int proxy_balancer_pre_request(proxy_worker **worker,
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose /* Step 1: check if the url is for us
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose * The url we can handle starts with 'balancer://'
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose * If balancer is already provided skip the search
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose * for balancer, because this is failover attempt.
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose !(*balancer = ap_proxy_get_balancer(r->pool, conf, *url)))
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose /* Step 2: find the session route */
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose runtime = find_session_route(*balancer, r, &route, url);
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose /* Lock the LoadBalancer
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose * XXX: perhaps we need the process lock here
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose if ((rv = PROXY_THREAD_LOCK(*balancer)) != APR_SUCCESS) {
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server,
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose "proxy: BALANCER: lock");
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose /* We have a sticky load balancer
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose * Update the workers status
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose * so that even session routes get
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose * into account.
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose workers = (proxy_worker *)(*balancer)->workers->elts;
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose for (i = 0; i < (*balancer)->workers->nelts; i++) {
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose /* Take into calculation only the workers that are
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose * not in error state or not disabled.
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose * TODO: Abstract the below, since this is dependent
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose * on the LB implementation
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose "proxy: BALANCER: (%s). All workers are in error state for route (%s)",
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny "proxy: BALANCER: (%s). All workers are in error state",
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny /* Add balancer/worker info to env. */
0754ff886f909f0404038eb9c99dd61be1acf5b9Simo Sorce /* Rewrite the url from 'balancer://url'
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny * to the 'worker_scheme://worker_hostname[:worker_port]/url'
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny * This replaces the balancers fictional name with the
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny * real hostname of the elected worker.
3912262270a6449ebe1d3e92c27c217b4044f894Simo Sorce /* Add the session route to request notes if present */
7fe69bb6ec70bce439c6b975a9a0044c98ff502bSimo Sorce apr_table_setn(r->notes, "session-sticky", (*balancer)->sticky);
7fe69bb6ec70bce439c6b975a9a0044c98ff502bSimo Sorce apr_table_setn(r->notes, "session-route", route);
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny /* Add session info to env. */
c03b28a38b14fdb59f74864ae4dc56affe256508Simo Sorce ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny "proxy: BALANCER (%s) worker (%s) rewritten to %s",
3912262270a6449ebe1d3e92c27c217b4044f894Simo Sorcestatic int proxy_balancer_post_request(proxy_worker *worker,
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny if ((rv = PROXY_THREAD_LOCK(balancer)) != APR_SUCCESS) {
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server,
3912262270a6449ebe1d3e92c27c217b4044f894Simo Sorce "proxy: BALANCER: lock");
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny /* TODO: calculate the bytes transferred
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny * This will enable to elect the worker that has
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny * the lowest load.
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny * The bytes transferred depends on the protocol
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny * used, so each protocol handler should keep the
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny * track on that.
17195241500e46272018d7897d6e87249870caf2Pavel Reichl ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
17195241500e46272018d7897d6e87249870caf2Pavel Reichl "proxy_balancer_post_request for (%s)", balancer->name);
17195241500e46272018d7897d6e87249870caf2Pavel Reichlstatic void recalc_factors(proxy_balancer *balancer)
17195241500e46272018d7897d6e87249870caf2Pavel Reichl /* Recalculate lbfactors */
17195241500e46272018d7897d6e87249870caf2Pavel Reichl workers = (proxy_worker *)balancer->workers->elts;
17195241500e46272018d7897d6e87249870caf2Pavel Reichl /* Special case if there is only one worker it's
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny * load factor will always be 1
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov /* Update the status entries */
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny/* Manages the loadfactors and member status
3b0e0352d8076909608d04750d3ea6b0d9ba33f6Jakub Hrozek proxy_server_conf *conf = (proxy_server_conf *)
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny apr_table_t *params = apr_table_make(r->pool, 10);
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny const char *name;
3912262270a6449ebe1d3e92c27c217b4044f894Simo Sorce /* is this for us? */
c5711b0279ea85d69fe3c77dfb194360c346e1d7Sumit Bose * Special case: workers are allowed path information
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce if ((access_status = ap_unescape_url(val)) != OK)
09d7c105839bfc7447ea0f766413ed86675ca075Sumit Bose if (strcmp(args, "w") || (access_status != HTTP_NOT_FOUND))
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny apr_pstrcat(r->pool, "balancer://", name, NULL));
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce /* First set the params */
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce const char *val;
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce provider = ap_lookup_provider(PROXY_LBMETHOD, val, "0");
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce const char *val;
09d7c105839bfc7447ea0f766413ed86675ca075Sumit Bose if (strlen(val) && strlen(val) < PROXY_WORKER_MAX_ROUTE_SIZ)
b3458bbb5315b05d7ac1abc58f1c380761756603Jakub Hrozek if (strlen(val) && strlen(val) < PROXY_WORKER_MAX_ROUTE_SIZ)
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce ap_rputs("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n", r);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny ap_rputs("<httpd:manager xmlns:httpd=\"http://httpd.apache.org\">\n", r);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny balancer = (proxy_balancer *)conf->balancers->elts;
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce ap_rvputs(r, " <httpd:name>", balancer->name, "</httpd:name>\n", NULL);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny worker = (proxy_worker *)balancer->workers->elts;
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce ap_rvputs(r, " <httpd:hostname>", worker->hostname,
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce ap_rprintf(r, " <httpd:loadfactor>%d</httpd:loadfactor>\n",
204cfc89a076fd32bf34f2abb3f809304aaa88abSimo Sorce "<html><head><title>Balancer Manager</title></head>\n", r);
204cfc89a076fd32bf34f2abb3f809304aaa88abSimo Sorce ap_rputs("<body><h1>Load Balancer Manager for ", r);
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce ap_rvputs(r, ap_get_server_name(r), "</h1>\n\n", NULL);
204cfc89a076fd32bf34f2abb3f809304aaa88abSimo Sorce balancer = (proxy_balancer *)conf->balancers->elts;
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce ap_rputs("<hr />\n<h3>LoadBalancer Status for ", r);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny ap_rvputs(r, balancer->name, "</a></h3>\n\n", NULL);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny ap_rputs("\n\n<table border=\"0\" style=\"text-align: left;\"><tr>"
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce "<th>StickySession</th><th>Timeout</th><th>FailoverAttempts</th><th>Method</th>"
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny "</tr>\n<tr>", r);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny ap_rprintf(r, "</td><td>%" APR_TIME_T_FMT "</td>",
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny ap_rprintf(r, "<td>%d</td>\n", balancer->max_attempts);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny ap_rputs("\n\n<table border=\"0\" style=\"text-align: left;\"><tr>"
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny "<th>Worker URL</th>"
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny "<th>Route</th><th>RouteRedir</th>"
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny "<th>Factor</th><th>Status</th>"
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny "<th>Elected</th><th>To</th><th>From</th>"
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce "</tr>\n", r);
c03b28a38b14fdb59f74864ae4dc56affe256508Simo Sorce worker = (proxy_worker *)balancer->workers->elts;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny ap_rvputs(r, "<tr>\n<td><a href=\"", r->uri, "?b=",
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny balancer->name + sizeof("balancer://") - 1, "&w=",
09d7c105839bfc7447ea0f766413ed86675ca075Sumit Bose ap_rvputs(r, "</td><td>", worker->s->redirect, NULL);
09d7c105839bfc7447ea0f766413ed86675ca075Sumit Bose ap_rprintf(r, "</td><td>%d</td><td>", worker->s->lbfactor);
09d7c105839bfc7447ea0f766413ed86675ca075Sumit Bose if (worker->s->status & PROXY_WORKER_HOT_STANDBY)
b3458bbb5315b05d7ac1abc58f1c380761756603Jakub Hrozek ap_rprintf(r, "<td>%" APR_SIZE_T_FMT "</td>", worker->s->elected);
b3458bbb5315b05d7ac1abc58f1c380761756603Jakub Hrozek ap_rprintf(r, "<td>%" APR_OFF_T_FMT "</td>", worker->s->transferred);
b3458bbb5315b05d7ac1abc58f1c380761756603Jakub Hrozek ap_rprintf(r, "<td>%" APR_OFF_T_FMT "</td>", worker->s->read);
c5711b0279ea85d69fe3c77dfb194360c346e1d7Sumit Bose ap_rvputs(r, "<form method=\"GET\" action=\"", NULL);
c5711b0279ea85d69fe3c77dfb194360c346e1d7Sumit Bose ap_rputs("<table><tr><td>Load factor:</td><td><input name=\"lf\" type=text ", r);
c5711b0279ea85d69fe3c77dfb194360c346e1d7Sumit Bose ap_rprintf(r, "value=\"%d\"></td><tr>\n", wsel->s->lbfactor);
c5711b0279ea85d69fe3c77dfb194360c346e1d7Sumit Bose ap_rputs("<tr><td>Route:</td><td><input name=\"wr\" type=text ", r);
c5711b0279ea85d69fe3c77dfb194360c346e1d7Sumit Bose ap_rputs("<tr><td>Route Redirect:</td><td><input name=\"rr\" type=text ", r);
c5711b0279ea85d69fe3c77dfb194360c346e1d7Sumit Bose ap_rputs("<tr><td>Status:</td><td>Disabled: <input name=\"dw\" value=\"Disable\" type=radio", r);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny ap_rputs("> | Enabled: <input name=\"dw\" value=\"Enable\" type=radio", r);
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov if (!(wsel->s->status & PROXY_WORKER_DISABLED))
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny ap_rputs("<tr><td colspan=2><input type=submit value=\"Submit\"></td></tr>\n", r);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny ap_rvputs(r, "</table>\n<input type=hidden name=\"w\" ", NULL);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny ap_rvputs(r, "value=\"", ap_escape_uri(r->pool, wsel->name), "\">\n", NULL);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny ap_rvputs(r, "<input type=hidden name=\"b\" ", NULL);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny ap_rvputs(r, "value=\"", bsel->name + sizeof("balancer://") - 1,
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny ap_rvputs(r, "<form method=\"GET\" action=\"", NULL);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny ap_rputs("<table><tr><td>StickySession Identifier:</td><td><input name=\"ss\" type=text ", r);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny ap_rvputs(r, "value=\"", bsel->sticky, "\"", NULL);
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce ap_rputs("></td><tr>\n<tr><td>Timeout:</td><td><input name=\"tm\" type=text ", r);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny ap_rprintf(r, "value=\"%" APR_TIME_T_FMT "\"></td></tr>\n",
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny ap_rputs("<tr><td>Failover Attempts:</td><td><input name=\"fa\" type=text ", r);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny ap_rputs("<tr><td>LB Method:</td><td><select name=\"lm\">", r);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny methods = ap_list_provider_names(r->pool, PROXY_LBMETHOD, "0");
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny method = (ap_list_provider_names_t *)methods->elts;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny ap_rprintf(r, "<option value=\"%s\" %s>%s</option>", method->provider_name,
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce (!strcasecmp(bsel->lbmethod->name, method->provider_name)) ? "selected" : "",
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny ap_rputs("<tr><td colspan=2><input type=submit value=\"Submit\"></td></tr>\n", r);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny ap_rvputs(r, "</table>\n<input type=hidden name=\"b\" ", NULL);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny ap_rvputs(r, "value=\"", bsel->name + sizeof("balancer://") - 1,
return OK;
balancer++;
s = s->next;
request_rec *r)
int total_factor = 0;
int checking_standby = 0;
int checked_standby = 0;
if (mycandidate) {
return mycandidate;
request_rec *r)
int checking_standby = 0;
int checked_standby = 0;
if (mycandidate) {
return mycandidate;