mod_proxy_balancer.c revision cb87bd3d86e01c8d044b218a34043f335861d817
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce/* Licensed to the Apache Software Foundation (ASF) under one or more
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce * contributor license agreements. See the NOTICE file distributed with
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce * this work for additional information regarding copyright ownership.
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce * The ASF licenses this file to You under the Apache License, Version 2.0
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce * (the "License"); you may not use this file except in compliance with
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce * the License. You may obtain a copy of the License at
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce *
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce * http://www.apache.org/licenses/LICENSE-2.0
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce *
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce * Unless required by applicable law or agreed to in writing, software
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce * distributed under the License is distributed on an "AS IS" BASIS,
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce * See the License for the specific language governing permissions and
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce * limitations under the License.
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce */
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce/* Load balancer module for Apache proxy */
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce#include "mod_proxy.h"
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce#include "scoreboard.h"
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce#include "ap_mpm.h"
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek#include "apr_version.h"
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce#include "apr_hooks.h"
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce#include "apr_uuid.h"
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorcemodule AP_MODULE_DECLARE_DATA proxy_balancer_module;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozekstatic char balancer_nonce[APR_UUID_FORMATTED_LENGTH + 1];
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozekstatic int proxy_balancer_canon(request_rec *r, char *url)
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek{
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek char *host, *path;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek char *search = NULL;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek const char *err;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek apr_port_t port = 0;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek if (strncasecmp(url, "balancer:", 9) == 0) {
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek url += 9;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek }
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce else {
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek return DECLINED;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek }
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek "proxy: BALANCER: canonicalising URL %s", url);
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek
a0d010f488bf15fb3e170ce04092013fa494401fPavel Březina /* do syntatic check.
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek * We break the URL into host, port, path, search
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce */
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce err = ap_proxy_canon_netloc(r->pool, &url, NULL, NULL, &host, &port);
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce if (err) {
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
a0d010f488bf15fb3e170ce04092013fa494401fPavel Březina "error parsing URL %s: %s",
a0d010f488bf15fb3e170ce04092013fa494401fPavel Březina url, err);
a0d010f488bf15fb3e170ce04092013fa494401fPavel Březina return HTTP_BAD_REQUEST;
a0d010f488bf15fb3e170ce04092013fa494401fPavel Březina }
a0d010f488bf15fb3e170ce04092013fa494401fPavel Březina /*
a0d010f488bf15fb3e170ce04092013fa494401fPavel Březina * now parse path/search args, according to rfc1738:
a0d010f488bf15fb3e170ce04092013fa494401fPavel Březina * process the path. With proxy-noncanon set (by
a0d010f488bf15fb3e170ce04092013fa494401fPavel Březina * mod_proxy) we use the raw, unparsed uri
a0d010f488bf15fb3e170ce04092013fa494401fPavel Březina */
a0d010f488bf15fb3e170ce04092013fa494401fPavel Březina if (apr_table_get(r->notes, "proxy-nocanon")) {
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek path = url; /* this is the raw path */
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek }
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce else {
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce path = ap_proxy_canonenc(r->pool, url, strlen(url), enc_path, 0,
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce r->proxyreq);
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce search = r->args;
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce }
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce if (path == NULL)
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce return HTTP_BAD_REQUEST;
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce r->filename = apr_pstrcat(r->pool, "proxy:balancer://", host,
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce "/", path, (search) ? "?" : "", (search) ? search : "", NULL);
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce r->path_info = apr_pstrcat(r->pool, "/", path, NULL);
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek return OK;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek}
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorcestatic int init_balancer_members(proxy_server_conf *conf, server_rec *s,
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce proxy_balancer *balancer)
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce{
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce int i;
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce proxy_worker **workers;
a0d010f488bf15fb3e170ce04092013fa494401fPavel Březina
a0d010f488bf15fb3e170ce04092013fa494401fPavel Březina workers = (proxy_worker **)balancer->workers->elts;
a0d010f488bf15fb3e170ce04092013fa494401fPavel Březina
a0d010f488bf15fb3e170ce04092013fa494401fPavel Březina for (i = 0; i < balancer->workers->nelts; i++) {
a0d010f488bf15fb3e170ce04092013fa494401fPavel Březina int worker_is_initialized;
a0d010f488bf15fb3e170ce04092013fa494401fPavel Březina worker_is_initialized = PROXY_WORKER_IS_INITIALIZED(*workers);
a0d010f488bf15fb3e170ce04092013fa494401fPavel Březina if (!worker_is_initialized) {
a0d010f488bf15fb3e170ce04092013fa494401fPavel Březina proxy_worker_stat *slot;
a0d010f488bf15fb3e170ce04092013fa494401fPavel Březina /*
a0d010f488bf15fb3e170ce04092013fa494401fPavel Březina * If the worker is not initialized check whether its scoreboard
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek * slot is already initialized.
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek */
a0d010f488bf15fb3e170ce04092013fa494401fPavel Březina slot = (proxy_worker_stat *) ap_get_scoreboard_lb((*workers)->id);
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce if (slot) {
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce worker_is_initialized = slot->status & PROXY_WORKER_INITIALIZED;
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce }
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce else {
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce worker_is_initialized = 0;
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce }
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce }
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce ap_proxy_initialize_worker_share(conf, *workers, s);
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek ap_proxy_initialize_worker(*workers, s);
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek if (!worker_is_initialized) {
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce /* Set to the original configuration */
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek (*workers)->s->lbstatus = (*workers)->s->lbfactor =
8e195a545d41647e591c1d06082133cbd25dc0a4Jakub Hrozek ((*workers)->lbfactor ? (*workers)->lbfactor : 1);
8e195a545d41647e591c1d06082133cbd25dc0a4Jakub Hrozek (*workers)->s->lbset = (*workers)->lbset;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek }
a0d010f488bf15fb3e170ce04092013fa494401fPavel Březina ++workers;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek }
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce /* Set default number of attempts to the number of
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce * workers.
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce */
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce if (!balancer->max_attempts_set && balancer->workers->nelts > 1) {
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce balancer->max_attempts = balancer->workers->nelts - 1;
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce balancer->max_attempts_set = 1;
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce }
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce return 0;
a0d010f488bf15fb3e170ce04092013fa494401fPavel Březina}
a0d010f488bf15fb3e170ce04092013fa494401fPavel Březina
a0d010f488bf15fb3e170ce04092013fa494401fPavel Březina/* Retrieve the parameter with the given name
a0d010f488bf15fb3e170ce04092013fa494401fPavel Březina * Something like 'JSESSIONID=12345...N'
a0d010f488bf15fb3e170ce04092013fa494401fPavel Březina */
a0d010f488bf15fb3e170ce04092013fa494401fPavel Březinastatic char *get_path_param(apr_pool_t *pool, char *url,
a0d010f488bf15fb3e170ce04092013fa494401fPavel Březina const char *name, int scolon_sep)
a0d010f488bf15fb3e170ce04092013fa494401fPavel Březina{
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek char *path = NULL;
a0d010f488bf15fb3e170ce04092013fa494401fPavel Březina char *pathdelims = "?&";
a0d010f488bf15fb3e170ce04092013fa494401fPavel Březina
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce if (scolon_sep) {
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce pathdelims = ";?&";
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce }
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce for (path = strstr(url, name); path; path = strstr(path + 1, name)) {
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce path += strlen(name);
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce if (*path == '=') {
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce /*
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce * Session path was found, get it's value
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce */
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek ++path;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek if (strlen(path)) {
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek char *q;
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce path = apr_strtok(apr_pstrdup(pool, path), pathdelims, &q);
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce return path;
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce }
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce }
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce }
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce return NULL;
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce}
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorcestatic char *get_cookie_param(request_rec *r, const char *name)
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce{
a0d010f488bf15fb3e170ce04092013fa494401fPavel Březina const char *cookies;
a0d010f488bf15fb3e170ce04092013fa494401fPavel Březina const char *start_cookie;
a0d010f488bf15fb3e170ce04092013fa494401fPavel Březina
a0d010f488bf15fb3e170ce04092013fa494401fPavel Březina if ((cookies = apr_table_get(r->headers_in, "Cookie"))) {
a0d010f488bf15fb3e170ce04092013fa494401fPavel Březina for (start_cookie = ap_strstr_c(cookies, name); start_cookie;
a0d010f488bf15fb3e170ce04092013fa494401fPavel Březina start_cookie = ap_strstr_c(start_cookie + 1, name)) {
a0d010f488bf15fb3e170ce04092013fa494401fPavel Březina if (start_cookie == cookies ||
a0d010f488bf15fb3e170ce04092013fa494401fPavel Březina start_cookie[-1] == ';' ||
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek start_cookie[-1] == ',' ||
a0d010f488bf15fb3e170ce04092013fa494401fPavel Březina isspace(start_cookie[-1])) {
a0d010f488bf15fb3e170ce04092013fa494401fPavel Březina
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce start_cookie += strlen(name);
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce while(*start_cookie && isspace(*start_cookie))
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce ++start_cookie;
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce if (*start_cookie == '=' && start_cookie[1]) {
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce /*
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce * Session cookie was found, get it's value
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce */
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce char *end_cookie, *cookie;
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce ++start_cookie;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek cookie = apr_pstrdup(r->pool, start_cookie);
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek if ((end_cookie = strchr(cookie, ';')) != NULL)
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek *end_cookie = '\0';
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce if((end_cookie = strchr(cookie, ',')) != NULL)
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce *end_cookie = '\0';
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce return cookie;
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce }
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce }
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce }
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek }
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek return NULL;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek}
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek
115241b0eeedd033d34d9721a896f031140944d7Pavel Březina/* Find the worker that has the 'route' defined
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek */
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozekstatic proxy_worker *find_route_worker(proxy_balancer *balancer,
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek const char *route, request_rec *r)
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek{
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek int i;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek int checking_standby;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek int checked_standby;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek proxy_worker *worker;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek checking_standby = checked_standby = 0;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek while (!checked_standby) {
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek worker = (proxy_worker *)balancer->workers->elts;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek for (i = 0; i < balancer->workers->nelts; i++, worker++) {
115241b0eeedd033d34d9721a896f031140944d7Pavel Březina if ( (checking_standby ? !PROXY_WORKER_IS_STANDBY(worker) : PROXY_WORKER_IS_STANDBY(worker)) )
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek continue;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek if (*(worker->s->route) && strcmp(worker->s->route, route) == 0) {
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek if (worker && PROXY_WORKER_IS_USABLE(worker)) {
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek return worker;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek } else {
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek /*
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek * If the worker is in error state run
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek * retry on that worker. It will be marked as
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek * operational if the retry timeout is elapsed.
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek * The worker might still be unusable, but we try
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek * anyway.
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek */
115241b0eeedd033d34d9721a896f031140944d7Pavel Březina ap_proxy_retry_worker("BALANCER", worker, r->server);
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek if (PROXY_WORKER_IS_USABLE(worker)) {
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek return worker;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek } else {
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek /*
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek * We have a worker that is unusable.
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek * It can be in error or disabled, but in case
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek * it has a redirection set use that redirection worker.
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek * This enables to safely remove the member from the
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek * balancer. Of course you will need some kind of
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek * session replication between those two remote.
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek */
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek if (*worker->s->redirect) {
18f01e63c1968c29bddb9e48c279b583c0444730Jakub Hrozek proxy_worker *rworker = NULL;
18f01e63c1968c29bddb9e48c279b583c0444730Jakub Hrozek rworker = find_route_worker(balancer, worker->s->redirect, r);
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek /* Check if the redirect worker is usable */
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek if (rworker && !PROXY_WORKER_IS_USABLE(rworker)) {
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek /*
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek * If the worker is in error state run
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek * retry on that worker. It will be marked as
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek * operational if the retry timeout is elapsed.
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek * The worker might still be unusable, but we try
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek * anyway.
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek */
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek ap_proxy_retry_worker("BALANCER", rworker, r->server);
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek }
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek if (rworker && PROXY_WORKER_IS_USABLE(rworker))
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek return rworker;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek }
115241b0eeedd033d34d9721a896f031140944d7Pavel Březina }
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek }
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek }
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek }
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek checked_standby = checking_standby++;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek }
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek return NULL;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek}
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozekstatic proxy_worker *find_session_route(proxy_balancer *balancer,
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek request_rec *r,
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek char **route,
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek const char **sticky_used,
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek char **url)
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek{
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek proxy_worker *worker = NULL;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek if (!balancer->sticky)
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek return NULL;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek /* Try to find the sticky route inside url */
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek *route = get_path_param(r->pool, *url, balancer->sticky_path, balancer->scolonsep);
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek if (*route) {
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek "proxy: BALANCER: Found value %s for "
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek "stickysession %s", *route, balancer->sticky_path);
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek *sticky_used = balancer->sticky_path;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek }
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek else {
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek *route = get_cookie_param(r, balancer->sticky);
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek if (*route) {
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek *sticky_used = balancer->sticky;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek "proxy: BALANCER: Found value %s for "
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek "stickysession %s", *route, balancer->sticky);
115241b0eeedd033d34d9721a896f031140944d7Pavel Březina }
115241b0eeedd033d34d9721a896f031140944d7Pavel Březina }
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek /*
115241b0eeedd033d34d9721a896f031140944d7Pavel Březina * If we found a value for sticksession, find the first '.' within.
115241b0eeedd033d34d9721a896f031140944d7Pavel Březina * Everything after '.' (if present) is our route.
115241b0eeedd033d34d9721a896f031140944d7Pavel Březina */
115241b0eeedd033d34d9721a896f031140944d7Pavel Březina if ((*route) && ((*route = strchr(*route, '.')) != NULL ))
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek (*route)++;
a4bf85ccc902490c3b75b44532010fbb32169801Lukas Slebodnik if ((*route) && (**route)) {
18f01e63c1968c29bddb9e48c279b583c0444730Jakub Hrozek ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek "proxy: BALANCER: Found route %s", *route);
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek /* We have a route in path or in cookie
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek * Find the worker that has this route defined.
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek */
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek worker = find_route_worker(balancer, *route, r);
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek if (worker && strcmp(*route, worker->s->route)) {
18f01e63c1968c29bddb9e48c279b583c0444730Jakub Hrozek /*
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek * Notice that the route of the worker chosen is different from
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek * the route supplied by the client.
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek */
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek apr_table_setn(r->subprocess_env, "BALANCER_ROUTE_CHANGED", "1");
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek "proxy: BALANCER: Route changed from %s to %s",
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek *route, worker->s->route);
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek }
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek return worker;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek }
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek else
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek return NULL;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek}
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozekstatic proxy_worker *find_best_worker(proxy_balancer *balancer,
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek request_rec *r)
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek{
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek proxy_worker *candidate = NULL;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek apr_status_t rv;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek if ((rv = PROXY_THREAD_LOCK(balancer)) != APR_SUCCESS) {
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server,
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek "proxy: BALANCER: (%s). Lock failed for find_best_worker()", balancer->name);
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek return NULL;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek }
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek candidate = (*balancer->lbmethod->finder)(balancer, r);
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek if (candidate)
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek candidate->s->elected++;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek/*
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek PROXY_THREAD_UNLOCK(balancer);
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek return NULL;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek*/
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek if ((rv = PROXY_THREAD_UNLOCK(balancer)) != APR_SUCCESS) {
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server,
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek "proxy: BALANCER: (%s). Unlock failed for find_best_worker()", balancer->name);
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek }
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek if (candidate == NULL) {
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek /* All the workers are in error state or disabled.
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek * If the balancer has a timeout sleep for a while
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek * and try again to find the worker. The chances are
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek * that some other thread will release a connection.
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek * By default the timeout is not set, and the server
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek * returns SERVER_BUSY.
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek */
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek#if APR_HAS_THREADS
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek if (balancer->timeout) {
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek /* XXX: This can perhaps be build using some
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek * smarter mechanism, like tread_cond.
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek * But since the statuses can came from
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek * different childs, use the provided algo.
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek */
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek apr_interval_time_t timeout = balancer->timeout;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek apr_interval_time_t step, tval = 0;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek /* Set the timeout to 0 so that we don't
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek * end in infinite loop
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek */
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek balancer->timeout = 0;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek step = timeout / 100;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek while (tval < timeout) {
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek apr_sleep(step);
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek /* Try again */
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek if ((candidate = find_best_worker(balancer, r)))
115241b0eeedd033d34d9721a896f031140944d7Pavel Březina break;
115241b0eeedd033d34d9721a896f031140944d7Pavel Březina tval += step;
115241b0eeedd033d34d9721a896f031140944d7Pavel Březina }
115241b0eeedd033d34d9721a896f031140944d7Pavel Březina /* restore the timeout */
115241b0eeedd033d34d9721a896f031140944d7Pavel Březina balancer->timeout = timeout;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek }
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek#endif
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek }
115241b0eeedd033d34d9721a896f031140944d7Pavel Březina
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek return candidate;
115241b0eeedd033d34d9721a896f031140944d7Pavel Březina
115241b0eeedd033d34d9721a896f031140944d7Pavel Březina}
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozekstatic int rewrite_url(request_rec *r, proxy_worker *worker,
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek char **url)
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek{
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek const char *scheme = strstr(*url, "://");
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek const char *path = NULL;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek if (scheme)
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek path = ap_strchr_c(scheme + 3, '/');
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek /* we break the URL into host, port, uri */
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek if (!worker) {
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek return ap_proxyerror(r, HTTP_BAD_REQUEST, apr_pstrcat(r->pool,
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek "missing worker. URI cannot be parsed: ", *url,
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek NULL));
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek }
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek *url = apr_pstrcat(r->pool, worker->name, path, NULL);
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek return OK;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek}
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozekstatic void force_recovery(proxy_balancer *balancer, server_rec *s)
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek{
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek int i;
115241b0eeedd033d34d9721a896f031140944d7Pavel Březina int ok = 0;
115241b0eeedd033d34d9721a896f031140944d7Pavel Březina proxy_worker **worker;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek worker = (proxy_worker **)balancer->workers->elts;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek for (i = 0; i < balancer->workers->nelts; i++, worker++) {
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek if (!((*worker)->s->status & PROXY_WORKER_IN_ERROR)) {
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek ok = 1;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek break;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek }
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek else {
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek /* Try if we can recover */
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek ap_proxy_retry_worker("BALANCER", *worker, s);
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek if (!((*worker)->s->status & PROXY_WORKER_IN_ERROR)) {
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek ok = 1;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek break;
8e195a545d41647e591c1d06082133cbd25dc0a4Jakub Hrozek }
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek }
115241b0eeedd033d34d9721a896f031140944d7Pavel Březina }
115241b0eeedd033d34d9721a896f031140944d7Pavel Březina if (!ok) {
115241b0eeedd033d34d9721a896f031140944d7Pavel Březina /* If all workers are in error state force the recovery.
115241b0eeedd033d34d9721a896f031140944d7Pavel Březina */
115241b0eeedd033d34d9721a896f031140944d7Pavel Březina worker = (proxy_worker **)balancer->workers->elts;
115241b0eeedd033d34d9721a896f031140944d7Pavel Březina for (i = 0; i < balancer->workers->nelts; i++, worker++) {
115241b0eeedd033d34d9721a896f031140944d7Pavel Březina ++(*worker)->s->retries;
115241b0eeedd033d34d9721a896f031140944d7Pavel Březina (*worker)->s->status &= ~PROXY_WORKER_IN_ERROR;
115241b0eeedd033d34d9721a896f031140944d7Pavel Březina ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
8e195a545d41647e591c1d06082133cbd25dc0a4Jakub Hrozek "proxy: BALANCER: (%s). Forcing recovery for worker (%s)",
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek balancer->name, (*worker)->hostname);
8e195a545d41647e591c1d06082133cbd25dc0a4Jakub Hrozek }
18f01e63c1968c29bddb9e48c279b583c0444730Jakub Hrozek }
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek}
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozekstatic int proxy_balancer_pre_request(proxy_worker **worker,
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek proxy_balancer **balancer,
18f01e63c1968c29bddb9e48c279b583c0444730Jakub Hrozek request_rec *r,
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek proxy_server_conf *conf, char **url)
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek{
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek int access_status;
115241b0eeedd033d34d9721a896f031140944d7Pavel Březina proxy_worker *runtime;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek char *route = NULL;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek const char *sticky = NULL;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek apr_status_t rv;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek *worker = NULL;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek /* Step 1: check if the url is for us
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek * The url we can handle starts with 'balancer://'
0e65abe5cf2abf5d4b431cf6bd161b419f07901dLukas Slebodnik * If balancer is already provided skip the search
8e195a545d41647e591c1d06082133cbd25dc0a4Jakub Hrozek * for balancer, because this is failover attempt.
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek */
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek if (!*balancer &&
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek !(*balancer = ap_proxy_get_balancer(r->pool, conf, *url)))
115241b0eeedd033d34d9721a896f031140944d7Pavel Březina return DECLINED;
115241b0eeedd033d34d9721a896f031140944d7Pavel Březina
115241b0eeedd033d34d9721a896f031140944d7Pavel Březina /* Step 2: Lock the LoadBalancer
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek * XXX: perhaps we need the process lock here
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek */
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek if ((rv = PROXY_THREAD_LOCK(*balancer)) != APR_SUCCESS) {
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server,
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek "proxy: BALANCER: (%s). Lock failed for pre_request",
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek (*balancer)->name);
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek return DECLINED;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek }
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek /* Step 3: force recovery */
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek force_recovery(*balancer, r->server);
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek /* Step 4: find the session route */
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek runtime = find_session_route(*balancer, r, &route, &sticky, url);
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek if (runtime) {
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek int i, total_factor = 0;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek proxy_worker *workers;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek /* We have a sticky load balancer
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek * Update the workers status
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek * so that even session routes get
8e195a545d41647e591c1d06082133cbd25dc0a4Jakub Hrozek * into account.
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek */
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek workers = (proxy_worker *)(*balancer)->workers->elts;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek for (i = 0; i < (*balancer)->workers->nelts; i++) {
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek /* Take into calculation only the workers that are
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek * not in error state or not disabled.
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek *
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek * TODO: Abstract the below, since this is dependent
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek * on the LB implementation
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek */
115241b0eeedd033d34d9721a896f031140944d7Pavel Březina if (PROXY_WORKER_IS_USABLE(workers)) {
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek workers->s->lbstatus += workers->s->lbfactor;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek total_factor += workers->s->lbfactor;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek }
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek workers++;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek }
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek runtime->s->lbstatus -= total_factor;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek runtime->s->elected++;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek
115241b0eeedd033d34d9721a896f031140944d7Pavel Březina *worker = runtime;
115241b0eeedd033d34d9721a896f031140944d7Pavel Březina }
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek else if (route && (*balancer)->sticky_force) {
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek int i, member_of = 0;
115241b0eeedd033d34d9721a896f031140944d7Pavel Březina proxy_worker *workers;
115241b0eeedd033d34d9721a896f031140944d7Pavel Březina /*
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek * We have a route provided that doesn't match the
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek * balancer name. See if the provider route is the
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek * member of the same balancer in which case return 503
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek */
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek workers = (proxy_worker *)(*balancer)->workers->elts;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek for (i = 0; i < (*balancer)->workers->nelts; i++) {
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek if (*(workers->s->route) && strcmp(workers->s->route, route) == 0) {
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce member_of = 1;
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce break;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek }
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek workers++;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek }
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek if (member_of) {
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek "proxy: BALANCER: (%s). All workers are in error state for route (%s)",
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek (*balancer)->name, route);
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek if ((rv = PROXY_THREAD_UNLOCK(*balancer)) != APR_SUCCESS) {
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server,
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek "proxy: BALANCER: (%s). Unlock failed for pre_request",
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek (*balancer)->name);
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek }
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek return HTTP_SERVICE_UNAVAILABLE;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek }
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek }
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek if ((rv = PROXY_THREAD_UNLOCK(*balancer)) != APR_SUCCESS) {
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server,
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek "proxy: BALANCER: (%s). Unlock failed for pre_request",
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek (*balancer)->name);
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek }
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek if (!*worker) {
a4bf85ccc902490c3b75b44532010fbb32169801Lukas Slebodnik runtime = find_best_worker(*balancer, r);
115241b0eeedd033d34d9721a896f031140944d7Pavel Březina if (!runtime) {
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek "proxy: BALANCER: (%s). All workers are in error state",
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek (*balancer)->name);
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek return HTTP_SERVICE_UNAVAILABLE;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek }
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek if ((*balancer)->sticky && runtime) {
115241b0eeedd033d34d9721a896f031140944d7Pavel Březina /*
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek * This balancer has sticky sessions and the client either has not
115241b0eeedd033d34d9721a896f031140944d7Pavel Březina * supplied any routing information or all workers for this route
115241b0eeedd033d34d9721a896f031140944d7Pavel Březina * including possible redirect and hotstandby workers are in error
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek * state, but we have found another working worker for this
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek * balancer where we can send the request. Thus notice that we have
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek * changed the route to the backend.
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek */
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek apr_table_setn(r->subprocess_env, "BALANCER_ROUTE_CHANGED", "1");
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek }
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek *worker = runtime;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek }
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek (*worker)->s->busy++;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek /* Add balancer/worker info to env. */
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek apr_table_setn(r->subprocess_env,
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek "BALANCER_NAME", (*balancer)->name);
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek apr_table_setn(r->subprocess_env,
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek "BALANCER_WORKER_NAME", (*worker)->name);
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek apr_table_setn(r->subprocess_env,
115241b0eeedd033d34d9721a896f031140944d7Pavel Březina "BALANCER_WORKER_ROUTE", (*worker)->s->route);
115241b0eeedd033d34d9721a896f031140944d7Pavel Březina
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek /* Rewrite the url from 'balancer://url'
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek * to the 'worker_scheme://worker_hostname[:worker_port]/url'
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek * This replaces the balancers fictional name with the
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek * real hostname of the elected worker.
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek */
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek access_status = rewrite_url(r, *worker, url);
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek /* Add the session route to request notes if present */
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek if (route) {
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek apr_table_setn(r->notes, "session-sticky", sticky);
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek apr_table_setn(r->notes, "session-route", route);
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek /* Add session info to env. */
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek apr_table_setn(r->subprocess_env,
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek "BALANCER_SESSION_STICKY", sticky);
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek apr_table_setn(r->subprocess_env,
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek "BALANCER_SESSION_ROUTE", route);
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek }
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek "proxy: BALANCER (%s) worker (%s) rewritten to %s",
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek (*balancer)->name, (*worker)->name, *url);
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek return access_status;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek}
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozekstatic int proxy_balancer_post_request(proxy_worker *worker,
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek proxy_balancer *balancer,
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek request_rec *r,
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek proxy_server_conf *conf)
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek{
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek#if 0
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek apr_status_t rv;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek if ((rv = PROXY_THREAD_LOCK(balancer)) != APR_SUCCESS) {
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server,
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek "proxy: BALANCER: (%s). Lock failed for post_request",
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek balancer->name);
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek return HTTP_INTERNAL_SERVER_ERROR;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek }
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek /* TODO: placeholder for post_request actions
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek */
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek if ((rv = PROXY_THREAD_UNLOCK(balancer)) != APR_SUCCESS) {
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server,
115241b0eeedd033d34d9721a896f031140944d7Pavel Březina "proxy: BALANCER: (%s). Unlock failed for post_request",
115241b0eeedd033d34d9721a896f031140944d7Pavel Březina balancer->name);
115241b0eeedd033d34d9721a896f031140944d7Pavel Březina }
115241b0eeedd033d34d9721a896f031140944d7Pavel Březina ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
115241b0eeedd033d34d9721a896f031140944d7Pavel Březina "proxy_balancer_post_request for (%s)", balancer->name);
115241b0eeedd033d34d9721a896f031140944d7Pavel Březina
115241b0eeedd033d34d9721a896f031140944d7Pavel Březina#endif
115241b0eeedd033d34d9721a896f031140944d7Pavel Březina
115241b0eeedd033d34d9721a896f031140944d7Pavel Březina if (worker && worker->s->busy)
115241b0eeedd033d34d9721a896f031140944d7Pavel Březina worker->s->busy--;
115241b0eeedd033d34d9721a896f031140944d7Pavel Březina
115241b0eeedd033d34d9721a896f031140944d7Pavel Březina return OK;
115241b0eeedd033d34d9721a896f031140944d7Pavel Březina
115241b0eeedd033d34d9721a896f031140944d7Pavel Březina}
115241b0eeedd033d34d9721a896f031140944d7Pavel Březina
115241b0eeedd033d34d9721a896f031140944d7Pavel Březinastatic void recalc_factors(proxy_balancer *balancer)
115241b0eeedd033d34d9721a896f031140944d7Pavel Březina{
a4bf85ccc902490c3b75b44532010fbb32169801Lukas Slebodnik int i;
115241b0eeedd033d34d9721a896f031140944d7Pavel Březina proxy_worker *workers;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek /* Recalculate lbfactors */
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek workers = (proxy_worker *)balancer->workers->elts;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek /* Special case if there is only one worker it's
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek * load factor will always be 1
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek */
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek if (balancer->workers->nelts == 1) {
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek workers->s->lbstatus = workers->s->lbfactor = 1;
115241b0eeedd033d34d9721a896f031140944d7Pavel Březina return;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek }
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek for (i = 0; i < balancer->workers->nelts; i++) {
115241b0eeedd033d34d9721a896f031140944d7Pavel Březina /* Update the status entries */
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek workers[i].s->lbstatus = workers[i].s->lbfactor;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek }
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek}
a4bf85ccc902490c3b75b44532010fbb32169801Lukas Slebodnik
18f01e63c1968c29bddb9e48c279b583c0444730Jakub Hrozek/* post_config hook: */
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozekstatic int balancer_init(apr_pool_t *p, apr_pool_t *plog,
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek apr_pool_t *ptemp, server_rec *s)
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek{
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek void *data;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek const char *userdata_key = "mod_proxy_balancer_init";
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek apr_uuid_t uuid;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek /* balancer_init() will be called twice during startup. So, only
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek * set up the static data the second time through. */
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek apr_pool_userdata_get(&data, userdata_key, s->process->pool);
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek if (!data) {
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek apr_pool_userdata_set((const void *)1, userdata_key,
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek apr_pool_cleanup_null, s->process->pool);
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek return OK;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek }
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek /* Retrieve a UUID and store the nonce for the lifetime of
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek * the process. */
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek apr_uuid_get(&uuid);
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek apr_uuid_format(balancer_nonce, &uuid);
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek return OK;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek}
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek/* Manages the loadfactors and member status
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek */
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozekstatic int balancer_handler(request_rec *r)
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek{
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek void *sconf = r->server->module_config;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek proxy_server_conf *conf = (proxy_server_conf *)
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek ap_get_module_config(sconf, &proxy_module);
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek proxy_balancer *balancer, *bsel = NULL;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek proxy_worker *worker, *wsel = NULL;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek apr_table_t *params = apr_table_make(r->pool, 10);
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek int access_status;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek int i, n;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek const char *name;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek /* is this for us? */
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek if (strcmp(r->handler, "balancer-manager"))
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek return DECLINED;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek r->allowed = (AP_METHOD_BIT << M_GET);
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek if (r->method_number != M_GET)
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek return DECLINED;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek if (r->args) {
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek char *args = apr_pstrdup(r->pool, r->args);
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek char *tok, *val;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek while (args && *args) {
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek if ((val = ap_strchr(args, '='))) {
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek *val++ = '\0';
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek if ((tok = ap_strchr(val, '&')))
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek *tok++ = '\0';
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek /*
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek * Special case: workers are allowed path information
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek */
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek if ((access_status = ap_unescape_url(val)) != OK)
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek if (strcmp(args, "w") || (access_status != HTTP_NOT_FOUND))
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek return access_status;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek apr_table_setn(params, args, val);
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek args = tok;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek }
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek else
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek return HTTP_BAD_REQUEST;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek }
18f01e63c1968c29bddb9e48c279b583c0444730Jakub Hrozek }
18f01e63c1968c29bddb9e48c279b583c0444730Jakub Hrozek
18f01e63c1968c29bddb9e48c279b583c0444730Jakub Hrozek /* Check that the supplied nonce matches this server's nonce;
18f01e63c1968c29bddb9e48c279b583c0444730Jakub Hrozek * otherwise ignore all parameters, to prevent a CSRF attack. */
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek if ((name = apr_table_get(params, "nonce")) == NULL
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek || strcmp(balancer_nonce, name) != 0) {
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek apr_table_clear(params);
18f01e63c1968c29bddb9e48c279b583c0444730Jakub Hrozek }
18f01e63c1968c29bddb9e48c279b583c0444730Jakub Hrozek
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek if ((name = apr_table_get(params, "b")))
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek bsel = ap_proxy_get_balancer(r->pool, conf,
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek apr_pstrcat(r->pool, "balancer://", name, NULL));
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek if ((name = apr_table_get(params, "w"))) {
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek proxy_worker *ws;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek ws = ap_proxy_get_worker(r->pool, conf, name);
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek if (bsel && ws) {
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek worker = (proxy_worker *)bsel->workers->elts;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek for (n = 0; n < bsel->workers->nelts; n++) {
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek if (strcasecmp(worker->name, ws->name) == 0) {
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek wsel = worker;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek break;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek }
18f01e63c1968c29bddb9e48c279b583c0444730Jakub Hrozek ++worker;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek }
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek }
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek }
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek /* First set the params */
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek /*
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek * Note that it is not possible set the proxy_balancer because it is not
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek * in shared memory.
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek */
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek if (wsel) {
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek const char *val;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek if ((val = apr_table_get(params, "lf"))) {
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek int ival = atoi(val);
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek if (ival >= 1 && ival <= 100) {
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek wsel->s->lbfactor = ival;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek if (bsel)
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek recalc_factors(bsel);
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek }
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek }
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek if ((val = apr_table_get(params, "wr"))) {
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek if (strlen(val) && strlen(val) < PROXY_WORKER_MAX_ROUTE_SIZ)
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek strcpy(wsel->s->route, val);
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek else
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek *wsel->s->route = '\0';
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek }
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek if ((val = apr_table_get(params, "rr"))) {
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek if (strlen(val) && strlen(val) < PROXY_WORKER_MAX_ROUTE_SIZ)
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek strcpy(wsel->s->redirect, val);
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek else
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek *wsel->s->redirect = '\0';
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek }
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek if ((val = apr_table_get(params, "dw"))) {
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek if (!strcasecmp(val, "Disable"))
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek wsel->s->status |= PROXY_WORKER_DISABLED;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek else if (!strcasecmp(val, "Enable"))
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek wsel->s->status &= ~PROXY_WORKER_DISABLED;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek }
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek if ((val = apr_table_get(params, "ls"))) {
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek int ival = atoi(val);
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek if (ival >= 0 && ival <= 99) {
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek wsel->s->lbset = ival;
8e195a545d41647e591c1d06082133cbd25dc0a4Jakub Hrozek }
8e195a545d41647e591c1d06082133cbd25dc0a4Jakub Hrozek }
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek
18f01e63c1968c29bddb9e48c279b583c0444730Jakub Hrozek }
18f01e63c1968c29bddb9e48c279b583c0444730Jakub Hrozek if (apr_table_get(params, "xml")) {
18f01e63c1968c29bddb9e48c279b583c0444730Jakub Hrozek ap_set_content_type(r, "text/xml");
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek ap_rputs("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n", r);
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek ap_rputs("<httpd:manager xmlns:httpd=\"http://httpd.apache.org\">\n", r);
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek ap_rputs(" <httpd:balancers>\n", r);
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek balancer = (proxy_balancer *)conf->balancers->elts;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek for (i = 0; i < conf->balancers->nelts; i++) {
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek ap_rputs(" <httpd:balancer>\n", r);
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek ap_rvputs(r, " <httpd:name>", balancer->name, "</httpd:name>\n", NULL);
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek ap_rputs(" <httpd:workers>\n", r);
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek worker = (proxy_worker *)balancer->workers->elts;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek for (n = 0; n < balancer->workers->nelts; n++) {
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek ap_rputs(" <httpd:worker>\n", r);
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek ap_rvputs(r, " <httpd:scheme>", worker->scheme,
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek "</httpd:scheme>\n", NULL);
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek ap_rvputs(r, " <httpd:hostname>", worker->hostname,
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek "</httpd:hostname>\n", NULL);
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek ap_rprintf(r, " <httpd:loadfactor>%d</httpd:loadfactor>\n",
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek worker->s->lbfactor);
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek ap_rputs(" </httpd:worker>\n", r);
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek ++worker;
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek }
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek ap_rputs(" </httpd:workers>\n", r);
c0bca1722d6f9dfb654ad78397be70f79ff39af1Jakub Hrozek ap_rputs(" </httpd:balancer>\n", r);
225d845476b6136be9b77f528ed986bba7a7f732Simo Sorce ++balancer;
}
ap_rputs(" </httpd:balancers>\n", r);
ap_rputs("</httpd:manager>", r);
}
else {
ap_set_content_type(r, "text/html; charset=ISO-8859-1");
ap_rputs(DOCTYPE_HTML_3_2
"<html><head><title>Balancer Manager</title></head>\n", r);
ap_rputs("<body><h1>Load Balancer Manager for ", r);
ap_rvputs(r, ap_get_server_name(r), "</h1>\n\n", NULL);
ap_rvputs(r, "<dl><dt>Server Version: ",
ap_get_server_description(), "</dt>\n", NULL);
ap_rvputs(r, "<dt>Server Built: ",
ap_get_server_built(), "\n</dt></dl>\n", NULL);
balancer = (proxy_balancer *)conf->balancers->elts;
for (i = 0; i < conf->balancers->nelts; i++) {
ap_rputs("<hr />\n<h3>LoadBalancer Status for ", r);
ap_rvputs(r, balancer->name, "</h3>\n\n", NULL);
ap_rputs("\n\n<table border=\"0\" style=\"text-align: left;\"><tr>"
"<th>StickySession</th><th>Timeout</th><th>FailoverAttempts</th><th>Method</th>"
"</tr>\n<tr>", r);
if (balancer->sticky) {
if (strcmp(balancer->sticky, balancer->sticky_path)) {
ap_rvputs(r, "<td>", balancer->sticky, " | ",
balancer->sticky_path, NULL);
}
else {
ap_rvputs(r, "<td>", balancer->sticky, NULL);
}
}
else {
ap_rputs("<td> - ", r);
}
ap_rprintf(r, "</td><td>%" APR_TIME_T_FMT "</td>",
apr_time_sec(balancer->timeout));
ap_rprintf(r, "<td>%d</td>\n", balancer->max_attempts);
ap_rprintf(r, "<td>%s</td>\n",
balancer->lbmethod->name);
ap_rputs("</table>\n<br />", r);
ap_rputs("\n\n<table border=\"0\" style=\"text-align: left;\"><tr>"
"<th>Worker URL</th>"
"<th>Route</th><th>RouteRedir</th>"
"<th>Factor</th><th>Set</th><th>Status</th>"
"<th>Elected</th><th>To</th><th>From</th>"
"</tr>\n", r);
worker = (proxy_worker *)balancer->workers->elts;
for (n = 0; n < balancer->workers->nelts; n++) {
char fbuf[50];
ap_rvputs(r, "<tr>\n<td><a href=\"", r->uri, "?b=",
balancer->name + sizeof("balancer://") - 1, "&w=",
ap_escape_uri(r->pool, worker->name),
"&nonce=", balancer_nonce,
"\">", NULL);
ap_rvputs(r, worker->name, "</a></td>", NULL);
ap_rvputs(r, "<td>", ap_escape_html(r->pool, worker->s->route),
NULL);
ap_rvputs(r, "</td><td>",
ap_escape_html(r->pool, worker->s->redirect), NULL);
ap_rprintf(r, "</td><td>%d</td>", worker->s->lbfactor);
ap_rprintf(r, "<td>%d</td><td>", worker->s->lbset);
if (worker->s->status & PROXY_WORKER_DISABLED)
ap_rputs("Dis ", r);
if (worker->s->status & PROXY_WORKER_IN_ERROR)
ap_rputs("Err ", r);
if (worker->s->status & PROXY_WORKER_STOPPED)
ap_rputs("Stop ", r);
if (worker->s->status & PROXY_WORKER_HOT_STANDBY)
ap_rputs("Stby ", r);
if (PROXY_WORKER_IS_USABLE(worker))
ap_rputs("Ok", r);
if (!PROXY_WORKER_IS_INITIALIZED(worker))
ap_rputs("-", r);
ap_rputs("</td>", r);
ap_rprintf(r, "<td>%" APR_SIZE_T_FMT "</td><td>", worker->s->elected);
ap_rputs(apr_strfsize(worker->s->transferred, fbuf), r);
ap_rputs("</td><td>", r);
ap_rputs(apr_strfsize(worker->s->read, fbuf), r);
ap_rputs("</td></tr>\n", r);
++worker;
}
ap_rputs("</table>\n", r);
++balancer;
}
ap_rputs("<hr />\n", r);
if (wsel && bsel) {
ap_rputs("<h3>Edit worker settings for ", r);
ap_rvputs(r, wsel->name, "</h3>\n", NULL);
ap_rvputs(r, "<form method=\"GET\" action=\"", NULL);
ap_rvputs(r, r->uri, "\">\n<dl>", NULL);
ap_rputs("<table><tr><td>Load factor:</td><td><input name=\"lf\" type=text ", r);
ap_rprintf(r, "value=\"%d\"></td></tr>\n", wsel->s->lbfactor);
ap_rputs("<tr><td>LB Set:</td><td><input name=\"ls\" type=text ", r);
ap_rprintf(r, "value=\"%d\"></td></tr>\n", wsel->s->lbset);
ap_rputs("<tr><td>Route:</td><td><input name=\"wr\" type=text ", r);
ap_rvputs(r, "value=\"", ap_escape_html(r->pool, wsel->s->route),
NULL);
ap_rputs("\"></td></tr>\n", r);
ap_rputs("<tr><td>Route Redirect:</td><td><input name=\"rr\" type=text ", r);
ap_rvputs(r, "value=\"", ap_escape_html(r->pool, wsel->s->redirect),
NULL);
ap_rputs("\"></td></tr>\n", r);
ap_rputs("<tr><td>Status:</td><td>Disabled: <input name=\"dw\" value=\"Disable\" type=radio", r);
if (wsel->s->status & PROXY_WORKER_DISABLED)
ap_rputs(" checked", r);
ap_rputs("> | Enabled: <input name=\"dw\" value=\"Enable\" type=radio", r);
if (!(wsel->s->status & PROXY_WORKER_DISABLED))
ap_rputs(" checked", r);
ap_rputs("></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=\"w\" ", NULL);
ap_rvputs(r, "value=\"", ap_escape_uri(r->pool, wsel->name), "\">\n", NULL);
ap_rvputs(r, "<input type=hidden name=\"b\" ", NULL);
ap_rvputs(r, "value=\"", bsel->name + sizeof("balancer://") - 1,
"\">\n", NULL);
ap_rvputs(r, "<input type=hidden name=\"nonce\" value=\"",
balancer_nonce, "\">\n", NULL);
ap_rvputs(r, "</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;
}
}
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
*/
static const char *const aszPred[] = { "mpm_winnt.c", NULL};
/* manager handler */
ap_hook_post_config(balancer_init, NULL, NULL, APR_HOOK_MIDDLE);
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);
}
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 */
};