📄 mod_proxy.c
字号:
const char *endp = ap_strrchr_c(arg, '>');
int old_overrides = cmd->override;
char *old_path = cmd->path;
proxy_dir_conf *conf;
ap_conf_vector_t *new_dir_conf = ap_create_per_dir_config(cmd->pool);
regex_t *r = NULL;
const command_rec *thiscmd = cmd->cmd;
const char *err = ap_check_cmd_context(cmd,
NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
if (err != NULL) {
return err;
}
if (endp == NULL) {
return apr_pstrcat(cmd->pool, cmd->cmd->name,
"> directive missing closing '>'", NULL);
}
arg=apr_pstrndup(cmd->pool, arg, endp-arg);
if (!arg) {
if (thiscmd->cmd_data)
return "<ProxyMatch > block must specify a path";
else
return "<Proxy > block must specify a path";
}
cmd->path = ap_getword_conf(cmd->pool, &arg);
cmd->override = OR_ALL|ACCESS_CONF;
if (!strncasecmp(cmd->path, "proxy:", 6))
cmd->path += 6;
/* XXX Ignore case? What if we proxy a case-insensitive server?!?
* While we are at it, shouldn't we also canonicalize the entire
* scheme? See proxy_fixup()
*/
if (thiscmd->cmd_data) { /* <ProxyMatch> */
r = ap_pregcomp(cmd->pool, cmd->path, REG_EXTENDED);
if (!r) {
return "Regex could not be compiled";
}
}
else if (!strcmp(cmd->path, "~")) {
cmd->path = ap_getword_conf(cmd->pool, &arg);
if (!cmd->path)
return "<Proxy ~ > block must specify a path";
if (strncasecmp(cmd->path, "proxy:", 6))
cmd->path += 6;
r = ap_pregcomp(cmd->pool, cmd->path, REG_EXTENDED);
if (!r) {
return "Regex could not be compiled";
}
}
/* initialize our config and fetch it */
conf = ap_set_config_vectors(cmd->server, new_dir_conf, cmd->path,
&proxy_module, cmd->pool);
errmsg = ap_walk_config(cmd->directive->first_child, cmd, new_dir_conf);
if (errmsg != NULL)
return errmsg;
conf->r = r;
conf->p = cmd->path;
conf->p_is_fnmatch = apr_fnmatch_test(conf->p);
ap_add_per_proxy_conf(cmd->server, new_dir_conf);
if (*arg != '\0') {
return apr_pstrcat(cmd->pool, "Multiple ", thiscmd->name,
"> arguments not (yet) supported.", NULL);
}
cmd->path = old_path;
cmd->override = old_overrides;
return NULL;
}
static const command_rec proxy_cmds[] =
{
AP_INIT_RAW_ARGS("<Proxy", proxysection, NULL, RSRC_CONF,
"Container for directives affecting resources located in the proxied "
"location"),
AP_INIT_RAW_ARGS("<ProxyMatch", proxysection, (void*)1, RSRC_CONF,
"Container for directives affecting resources located in the proxied "
"location, in regular expression syntax"),
AP_INIT_FLAG("ProxyRequests", set_proxy_req, NULL, RSRC_CONF,
"on if the true proxy requests should be accepted"),
AP_INIT_TAKE2("ProxyRemote", add_proxy_noregex, NULL, RSRC_CONF,
"a scheme, partial URL or '*' and a proxy server"),
AP_INIT_TAKE2("ProxyRemoteMatch", add_proxy_regex, NULL, RSRC_CONF,
"a regex pattern and a proxy server"),
AP_INIT_RAW_ARGS("ProxyPass", add_pass, NULL, RSRC_CONF|ACCESS_CONF,
"a virtual path and a URL"),
AP_INIT_TAKE12("ProxyPassReverse", add_pass_reverse, NULL, RSRC_CONF|ACCESS_CONF,
"a virtual path and a URL for reverse proxy behaviour"),
AP_INIT_TAKE2("ProxyPassReverseCookiePath", cookie_path, NULL,
RSRC_CONF|ACCESS_CONF, "Path rewrite rule for proxying cookies"),
AP_INIT_TAKE2("ProxyPassReverseCookieDomain", cookie_domain, NULL,
RSRC_CONF|ACCESS_CONF, "Domain rewrite rule for proxying cookies"),
AP_INIT_ITERATE("ProxyBlock", set_proxy_exclude, NULL, RSRC_CONF,
"A list of names, hosts or domains to which the proxy will not connect"),
AP_INIT_TAKE1("ProxyReceiveBufferSize", set_recv_buffer_size, NULL, RSRC_CONF,
"Receive buffer size for outgoing HTTP and FTP connections in bytes"),
AP_INIT_TAKE1("ProxyIOBufferSize", set_io_buffer_size, NULL, RSRC_CONF,
"IO buffer size for outgoing HTTP and FTP connections in bytes"),
AP_INIT_TAKE1("ProxyMaxForwards", set_max_forwards, NULL, RSRC_CONF,
"The maximum number of proxies a request may be forwarded through."),
AP_INIT_ITERATE("NoProxy", set_proxy_dirconn, NULL, RSRC_CONF,
"A list of domains, hosts, or subnets to which the proxy will connect directly"),
AP_INIT_TAKE1("ProxyDomain", set_proxy_domain, NULL, RSRC_CONF,
"The default intranet domain name (in absence of a domain in the URL)"),
AP_INIT_ITERATE("AllowCONNECT", set_allowed_ports, NULL, RSRC_CONF,
"A list of ports which CONNECT may connect to"),
AP_INIT_TAKE1("ProxyVia", set_via_opt, NULL, RSRC_CONF,
"Configure Via: proxy header header to one of: on | off | block | full"),
AP_INIT_FLAG("ProxyErrorOverride", set_proxy_error_override, NULL, RSRC_CONF,
"use our error handling pages instead of the servers' we are proxying"),
AP_INIT_FLAG("ProxyPreserveHost", set_preserve_host, NULL, RSRC_CONF,
"on if we should preserve host header while proxying"),
AP_INIT_TAKE1("ProxyTimeout", set_proxy_timeout, NULL, RSRC_CONF,
"Set the timeout (in seconds) for a proxied connection. "
"This overrides the server timeout"),
AP_INIT_TAKE1("ProxyBadHeader", set_bad_opt, NULL, RSRC_CONF,
"How to handle bad header line in response: IsError | Ignore | StartBody"),
AP_INIT_RAW_ARGS("BalancerMember", add_member, NULL, RSRC_CONF|ACCESS_CONF,
"A balancer name and scheme with list of params"),
AP_INIT_TAKE12("BalancerStickySession", set_sticky_session, NULL, RSRC_CONF|ACCESS_CONF,
"A balancer and sticky session name"),
AP_INIT_TAKE1("ProxyStatus", set_status_opt, NULL, RSRC_CONF,
"Configure Status: proxy status to one of: on | off | full"),
{NULL}
};
static APR_OPTIONAL_FN_TYPE(ssl_proxy_enable) *proxy_ssl_enable = NULL;
static APR_OPTIONAL_FN_TYPE(ssl_engine_disable) *proxy_ssl_disable = NULL;
PROXY_DECLARE(int) ap_proxy_ssl_enable(conn_rec *c)
{
/*
* if c == NULL just check if the optional function was imported
* else run the optional function so ssl filters are inserted
*/
if (proxy_ssl_enable) {
return c ? proxy_ssl_enable(c) : 1;
}
return 0;
}
PROXY_DECLARE(int) ap_proxy_ssl_disable(conn_rec *c)
{
if (proxy_ssl_disable) {
return proxy_ssl_disable(c);
}
return 0;
}
static int proxy_post_config(apr_pool_t *pconf, apr_pool_t *plog,
apr_pool_t *ptemp, server_rec *s)
{
proxy_ssl_enable = APR_RETRIEVE_OPTIONAL_FN(ssl_proxy_enable);
proxy_ssl_disable = APR_RETRIEVE_OPTIONAL_FN(ssl_engine_disable);
return OK;
}
#define KBYTE 1024
#define MBYTE 1048576L
#define GBYTE 1073741824L
/* Format the number of bytes nicely */
static void format_byte_out(request_rec *r, apr_off_t bytes)
{
if (bytes < (5 * KBYTE))
ap_rprintf(r, "%d B", (int) bytes);
else if (bytes < (MBYTE / 2))
ap_rprintf(r, "%.1f kB", (float) bytes / KBYTE);
else if (bytes < (GBYTE / 2))
ap_rprintf(r, "%.1f MB", (float) bytes / MBYTE);
else
ap_rprintf(r, "%.1f GB", (float) bytes / GBYTE);
}
/*
* proxy Extension to mod_status
*/
static int proxy_status_hook(request_rec *r, int flags)
{
int i, n;
void *sconf = r->server->module_config;
proxy_server_conf *conf = (proxy_server_conf *)
ap_get_module_config(sconf, &proxy_module);
proxy_balancer *balancer = NULL;
proxy_runtime_worker *worker = NULL;
if (flags & AP_STATUS_SHORT || conf->balancers->nelts == 0 ||
conf->proxy_status == status_off)
return OK;
balancer = (proxy_balancer *)conf->balancers->elts;
for (i = 0; i < conf->balancers->nelts; i++) {
ap_rputs("<hr />\n<h1>Proxy LoadBalancer Status for ", r);
ap_rvputs(r, balancer->name, "</h1>\n\n", NULL);
ap_rputs("\n\n<table border=\"0\"><tr>"
"<th>SSes</th><th>Timeout</th>"
"</tr>\n<tr>", r);
ap_rvputs(r, "<td>", balancer->sticky, NULL);
ap_rprintf(r, "</td><td>%d</td>\n",
apr_time_sec(balancer->timeout));
ap_rputs("</table>\n", r);
ap_rputs("\n\n<table border=\"0\"><tr>"
"<th>Sch</th><th>Host</th>"
"<th>Route</th><th>Redir</th>"
"<th>F</th><th>Acc</th><th>Wr</th><th>Rd</th>"
"</tr>\n", r);
worker = (proxy_runtime_worker *)balancer->workers->elts;
for (n = 0; n < balancer->workers->nelts; n++) {
ap_rvputs(r, "<tr>\n<td>", worker->w->scheme, "</td>", NULL);
ap_rvputs(r, "<td>", worker->w->hostname, "</td>", NULL);
ap_rvputs(r, "<td>", worker->w->route, NULL);
ap_rvputs(r, "</td><td>", worker->w->redirect, NULL);
ap_rprintf(r, "</td><td>%.2f</td>", worker->s->lbfactor);
ap_rprintf(r, "<td>%d</td><td>", (int)(worker->s->elected));
format_byte_out(r, worker->s->transfered);
ap_rputs("</td><td>", r);
format_byte_out(r, worker->s->transfered);
ap_rputs("</td>\n", r);
/* TODO: Add the rest of dynamic worker data */
ap_rputs("</tr>\n", r);
++worker;
}
ap_rputs("</table>\n", r);
++balancer;
}
ap_rputs("<hr /><table>\n"
"<tr><th>SSes</th><td>Sticky session name</td></tr>\n"
"<tr><th>Timeout</th><td>Balancer Timeout</td></tr>\n"
"<tr><th>Sch</th><td>Connection scheme</td></tr>\n"
"<tr><th>Host</th><td>Backend Hostname</td></tr>\n"
"<tr><th>Route</th><td>Session Route</td></tr>\n"
"<tr><th>Redir</th><td>Session Route Redirection</td></tr>\n"
"<tr><th>F</th><td>Load Balancer Factor in %</td></tr>\n"
"<tr><th>Acc</th><td>Number of requests</td></tr>\n"
"<tr><th>Wr</th><td>Number of bytes transfered</td></tr>\n"
"<tr><th>Rd</th><td>Number of bytes readed</td></tr>\n"
"</table>", r);
return OK;
}
/*
* This routine is called before the server processes the configuration
* files. There is no return value.
*/
static int proxy_pre_config(apr_pool_t *pconf, apr_pool_t *plog,
apr_pool_t *ptemp)
{
APR_OPTIONAL_HOOK(ap, status_hook, proxy_status_hook, NULL, NULL,
APR_HOOK_MIDDLE);
return OK;
}
static void register_hooks(apr_pool_t *p)
{
/* fixup before mod_rewrite, so that the proxied url will not
* escaped accidentally by our fixup.
*/
#ifndef FIX_15207
static const char * const aszSucc[]={ "mod_rewrite.c", NULL };
#endif
/* handler */
ap_hook_handler(proxy_handler, NULL, NULL, APR_HOOK_FIRST);
/* filename-to-URI translation */
ap_hook_translate_name(proxy_trans, NULL, NULL, APR_HOOK_FIRST);
/* walk <Proxy > entries and suppress default TRACE behavior */
ap_hook_map_to_storage(proxy_map_location, NULL,NULL, APR_HOOK_FIRST);
#ifndef FIX_15207
/* fixups */
ap_hook_fixups(proxy_fixup, NULL, aszSucc, APR_HOOK_FIRST);
#endif
/* post read_request handling */
ap_hook_post_read_request(proxy_detect, NULL, NULL, APR_HOOK_FIRST);
/* pre config handling */
ap_hook_pre_config(proxy_pre_config, NULL, NULL, APR_HOOK_MIDDLE);
/* post config handling */
ap_hook_post_config(proxy_post_config, NULL, NULL, APR_HOOK_MIDDLE);
}
module AP_MODULE_DECLARE_DATA proxy_module =
{
STANDARD20_MODULE_STUFF,
create_proxy_dir_config, /* create per-directory config structure */
merge_proxy_dir_config, /* merge per-directory config structures */
create_proxy_config, /* create per-server config structure */
merge_proxy_config, /* merge per-server config structures */
proxy_cmds, /* command table */
register_hooks
};
APR_HOOK_STRUCT(
APR_HOOK_LINK(scheme_handler)
APR_HOOK_LINK(canon_handler)
APR_HOOK_LINK(pre_request)
APR_HOOK_LINK(post_request)
)
APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(proxy, PROXY, int, scheme_handler,
(request_rec *r, proxy_worker *worker,
proxy_server_conf *conf,
char *url, const char *proxyhost,
apr_port_t proxyport),(r,worker,conf,
url,proxyhost,proxyport),DECLINED)
APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(proxy, PROXY, int, canon_handler,
(request_rec *r, char *url),(r,
url),DECLINED)
APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(proxy, PROXY, int, pre_request, (
proxy_worker **worker,
proxy_balancer **balancer,
request_rec *r,
proxy_server_conf *conf,
char **url),(worker,balancer,
r,conf,url),DECLINED)
APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(proxy, PROXY, int, post_request,
(proxy_worker *worker,
proxy_balancer *balancer,
request_rec *r,
proxy_server_conf *conf),(worker,
balancer,r,conf),DECLINED)
APR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL(proxy, PROXY, int, fixups,
(request_rec *r), (r),
OK, DECLINED)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -