📄 mod_proxy_balancer.c
字号:
/* Copyright 1999-2005 The Apache Software Foundation or its licensors, as * applicable. * * Licensed 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 "ap_mpm.h"#include "apr_version.h"#include "apr_hooks.h"module AP_MODULE_DECLARE_DATA proxy_balancer_module;static int proxy_balancer_canon(request_rec *r, char *url){ char *host, *path, *search; 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 */ /* N.B. if this isn't a true proxy request, then the URL _path_ * has already been decoded. True proxy requests have r->uri * == r->unparsed_uri, and no others have that property. */ if (r->uri == r->unparsed_uri) { search = strchr(url, '?'); if (search != NULL) *(search++) = '\0'; } else search = r->args; /* process path */ path = ap_proxy_canonenc(r->pool, url, strlen(url), enc_path, 0, r->proxyreq); 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; workers = (proxy_worker *)balancer->workers->elts; for (i = 0; i < balancer->workers->nelts; i++) { ap_proxy_initialize_worker_share(conf, workers, s); ap_proxy_initialize_worker(workers, s); ++workers; } workers = (proxy_worker *)balancer->workers->elts; for (i = 0; i < balancer->workers->nelts; i++) { /* Set to the original configuration */ workers[i].s->lbstatus = workers[i].s->lbfactor = (workers[i].lbfactor ? workers[i].lbfactor : 1); } /* 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){ char *path = NULL; 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_pstrdup(pool, path); if ((q = strchr(path, '?'))) *q = '\0'; 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){ int i; proxy_worker *worker = (proxy_worker *)balancer->workers->elts; for (i = 0; i < balancer->workers->nelts; i++) { if (*(worker->s->route) && strcmp(worker->s->route, route) == 0) { return worker; } worker++; } return NULL;}static proxy_worker *find_session_route(proxy_balancer *balancer, request_rec *r, char **route, char **url){ proxy_worker *worker = NULL; if (!balancer->sticky) return NULL; /* Try to find the sticky route inside url */ *route = get_path_param(r->pool, *url, balancer->sticky); if (!*route) *route = get_cookie_param(r, balancer->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); if (worker && !PROXY_WORKER_IS_USABLE(worker)) { /* 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 a some kind of * session replication between those two remote. */ if (*worker->s->redirect) worker = find_route_worker(balancer, worker->s->redirect); /* Check if the redirect worker is usable */ if (worker && !PROXY_WORKER_IS_USABLE(worker)) worker = NULL; } return worker; } else return NULL;}static proxy_worker *find_best_worker(proxy_balancer *balancer, request_rec *r){ proxy_worker *candidate = NULL; if (PROXY_THREAD_LOCK(balancer) != APR_SUCCESS) return NULL; candidate = (*balancer->lbmethod->finder)(balancer, r);/* PROXY_THREAD_UNLOCK(balancer); return NULL;*/ PROXY_THREAD_UNLOCK(balancer); if (candidate == NULL) { /* All the workers are in error state or disabled. * If the balancer has a timeout sleep for a while * and try again to find the worker. The chances are * that some other thread will release a connection. * By default the timeout is not set, and the server * returns SERVER_BUSY. */#if APR_HAS_THREADS if (balancer->timeout) { /* XXX: This can perhaps be build using some * smarter mechanism, like tread_cond. * But since the statuses can came from * different childs, use the provided algo. */ apr_interval_time_t timeout = balancer->timeout; apr_interval_time_t step, tval = 0; /* Set the timeout to 0 so that we don't * end in infinite loop */ balancer->timeout = 0; step = timeout / 100; while (tval < timeout) { apr_sleep(step); /* Try again */ if ((candidate = find_best_worker(balancer, r))) break; tval += step; } /* restore the timeout */ balancer->timeout = timeout; }#endif } return candidate;}static int rewrite_url(request_rec *r, proxy_worker *worker, char **url){ const char *scheme = strstr(*url, "://"); const char *path = NULL; if (scheme) path = ap_strchr_c(scheme + 3, '/'); /* we break the URL into host, port, uri */ if (!worker) { return ap_proxyerror(r, HTTP_BAD_REQUEST, apr_pstrcat(r->pool, "missing worker. URI cannot be parsed: ", *url, NULL)); } *url = apr_pstrcat(r->pool, worker->name, path, NULL); return OK;}static int proxy_balancer_pre_request(proxy_worker **worker, proxy_balancer **balancer, request_rec *r, proxy_server_conf *conf, char **url){ int access_status; proxy_worker *runtime;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -