⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mod_proxy_balancer.c

📁 Apache官方在今天放出产品系列2.2的最新版本2.2.11的源码包 最流行的HTTP服务器软件之一
💻 C
📖 第 1 页 / 共 4 页
字号:
/* Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements.  See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License.  You may obtain a copy of the License at * *     http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. *//* Load balancer module for Apache proxy */#define CORE_PRIVATE#include "mod_proxy.h"#include "scoreboard.h"#include "ap_mpm.h"#include "apr_version.h"#include "apr_hooks.h"#include "apr_uuid.h"module AP_MODULE_DECLARE_DATA proxy_balancer_module;static char balancer_nonce[APR_UUID_FORMATTED_LENGTH + 1];static int proxy_balancer_canon(request_rec *r, char *url){    char *host, *path;    char *search = NULL;    const char *err;    apr_port_t port = 0;    if (strncasecmp(url, "balancer:", 9) == 0) {        url += 9;    }    else {        return DECLINED;    }    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,             "proxy: BALANCER: canonicalising URL %s", url);    /* do syntatic check.     * We break the URL into host, port, path, search     */    err = ap_proxy_canon_netloc(r->pool, &url, NULL, NULL, &host, &port);    if (err) {        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,                      "error parsing URL %s: %s",                      url, err);        return HTTP_BAD_REQUEST;    }    /*     * now parse path/search args, according to rfc1738:     * process the path. With proxy-noncanon set (by     * mod_proxy) we use the raw, unparsed uri     */    if (apr_table_get(r->notes, "proxy-nocanon")) {        path = url;   /* this is the raw path */    }    else {        path = ap_proxy_canonenc(r->pool, url, strlen(url), enc_path, 0,                                 r->proxyreq);        search = r->args;    }    if (path == NULL)        return HTTP_BAD_REQUEST;    r->filename = apr_pstrcat(r->pool, "proxy:balancer://", host,            "/", path, (search) ? "?" : "", (search) ? search : "", NULL);    return OK;}static int init_balancer_members(proxy_server_conf *conf, server_rec *s,                                 proxy_balancer *balancer){    int i;    proxy_worker *workers;    int worker_is_initialized;    proxy_worker_stat *slot;    workers = (proxy_worker *)balancer->workers->elts;    for (i = 0; i < balancer->workers->nelts; i++) {        worker_is_initialized = PROXY_WORKER_IS_INITIALIZED(workers);        if (!worker_is_initialized) {            /*             * If the worker is not initialized check whether its scoreboard             * slot is already initialized.             */            slot = (proxy_worker_stat *) ap_get_scoreboard_lb(workers->id);            if (slot) {                worker_is_initialized = slot->status & PROXY_WORKER_INITIALIZED;            }            else {                worker_is_initialized = 0;            }        }        ap_proxy_initialize_worker_share(conf, workers, s);        ap_proxy_initialize_worker(workers, s);        if (!worker_is_initialized) {            /* Set to the original configuration */            workers->s->lbstatus = workers->s->lbfactor =            (workers->lbfactor ? workers->lbfactor : 1);            workers->s->lbset = workers->lbset;        }        ++workers;    }    /* Set default number of attempts to the number of     * workers.     */    if (!balancer->max_attempts_set && balancer->workers->nelts > 1) {        balancer->max_attempts = balancer->workers->nelts - 1;        balancer->max_attempts_set = 1;    }    return 0;}/* Retrieve the parameter with the given name * Something like 'JSESSIONID=12345...N' */static char *get_path_param(apr_pool_t *pool, char *url,                            const char *name, int scolon_sep){    char *path = NULL;    char *pathdelims = "?&";    if (scolon_sep) {        pathdelims = ";?&";    }    for (path = strstr(url, name); path; path = strstr(path + 1, name)) {        path += strlen(name);        if (*path == '=') {            /*             * Session path was found, get it's value             */            ++path;            if (strlen(path)) {                char *q;                path = apr_strtok(apr_pstrdup(pool, path), pathdelims, &q);                return path;            }        }    }    return NULL;}static char *get_cookie_param(request_rec *r, const char *name){    const char *cookies;    const char *start_cookie;    if ((cookies = apr_table_get(r->headers_in, "Cookie"))) {        for (start_cookie = ap_strstr_c(cookies, name); start_cookie;             start_cookie = ap_strstr_c(start_cookie + 1, name)) {            if (start_cookie == cookies ||                start_cookie[-1] == ';' ||                start_cookie[-1] == ',' ||                isspace(start_cookie[-1])) {                start_cookie += strlen(name);                while(*start_cookie && isspace(*start_cookie))                    ++start_cookie;                if (*start_cookie == '=' && start_cookie[1]) {                    /*                     * Session cookie was found, get it's value                     */                    char *end_cookie, *cookie;                    ++start_cookie;                    cookie = apr_pstrdup(r->pool, start_cookie);                    if ((end_cookie = strchr(cookie, ';')) != NULL)                        *end_cookie = '\0';                    if((end_cookie = strchr(cookie, ',')) != NULL)                        *end_cookie = '\0';                    return cookie;                }            }        }    }    return NULL;}/* Find the worker that has the 'route' defined */static proxy_worker *find_route_worker(proxy_balancer *balancer,                                       const char *route, request_rec *r){    int i;    int checking_standby;    int checked_standby;        proxy_worker *worker;    checking_standby = checked_standby = 0;    while (!checked_standby) {        worker = (proxy_worker *)balancer->workers->elts;        for (i = 0; i < balancer->workers->nelts; i++, worker++) {            if ( (checking_standby ? !PROXY_WORKER_IS_STANDBY(worker) : PROXY_WORKER_IS_STANDBY(worker)) )                continue;            if (*(worker->s->route) && strcmp(worker->s->route, route) == 0) {                if (worker && PROXY_WORKER_IS_USABLE(worker)) {                    return worker;                } else {                    /*                     * If the worker is in error state run                     * retry on that worker. It will be marked as                     * operational if the retry timeout is elapsed.                     * The worker might still be unusable, but we try                     * anyway.                     */                    ap_proxy_retry_worker("BALANCER", worker, r->server);                    if (PROXY_WORKER_IS_USABLE(worker)) {                            return worker;                    } else {                        /*                         * We have a worker that is unusable.                         * It can be in error or disabled, but in case                         * it has a redirection set use that redirection worker.                         * This enables to safely remove the member from the                         * balancer. Of course you will need some kind of                         * session replication between those two remote.                         */                        if (*worker->s->redirect) {                            proxy_worker *rworker = NULL;                            rworker = find_route_worker(balancer, worker->s->redirect, r);                            /* Check if the redirect worker is usable */                            if (rworker && !PROXY_WORKER_IS_USABLE(rworker)) {                                /*                                 * If the worker is in error state run                                 * retry on that worker. It will be marked as                                 * operational if the retry timeout is elapsed.                                 * The worker might still be unusable, but we try                                 * anyway.                                 */                                ap_proxy_retry_worker("BALANCER", rworker, r->server);                            }                            if (rworker && PROXY_WORKER_IS_USABLE(rworker))                                return rworker;                        }                    }                }            }        }        checked_standby = checking_standby++;    }    return NULL;}static proxy_worker *find_session_route(proxy_balancer *balancer,                                        request_rec *r,                                        char **route,                                        char **sticky_used,                                        char **url){    proxy_worker *worker = NULL;    char *sticky, *sticky_path, *path;    if (!balancer->sticky)        return NULL;    sticky = sticky_path = apr_pstrdup(r->pool, balancer->sticky);    if ((path = strchr(sticky, '|'))) {        *path++ = '\0';         sticky_path = path;    }        /* Try to find the sticky route inside url */    *sticky_used = sticky_path;    *route = get_path_param(r->pool, *url, sticky_path, balancer->scolonsep);    if (!*route) {        *route = get_cookie_param(r, sticky);        *sticky_used = sticky;    }    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,                            "proxy: BALANCER: Found value %s for "                            "stickysession %s", *route, balancer->sticky);    /*     * If we found a value for sticksession, find the first '.' within.     * Everything after '.' (if present) is our route.     */    if ((*route) && ((*route = strchr(*route, '.')) != NULL ))        (*route)++;    if ((*route) && (**route)) {        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,                                  "proxy: BALANCER: Found route %s", *route);        /* We have a route in path or in cookie         * Find the worker that has this route defined.         */        worker = find_route_worker(balancer, *route, r);        if (worker && strcmp(*route, worker->s->route)) {            /*             * Notice that the route of the worker chosen is different from             * the route supplied by the client.             */            apr_table_setn(r->subprocess_env, "BALANCER_ROUTE_CHANGED", "1");            ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,                         "proxy: BALANCER: Route changed from %s to %s",                         *route, worker->s->route);        }        return worker;    }    else        return NULL;}static proxy_worker *find_best_worker(proxy_balancer *balancer,                                      request_rec *r){    proxy_worker *candidate = NULL;    apr_status_t rv;    if ((rv = PROXY_THREAD_LOCK(balancer)) != APR_SUCCESS) {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -