📄 mod_proxy.c
字号:
#define FIX_15207
/* Copyright 1999-2004 The Apache Software Foundation
*
* 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.
*/
#define CORE_PRIVATE
#include "mod_proxy.h"
#include "mod_core.h"
#include "apr_optional.h"
#include "mod_status.h"
#if (MODULE_MAGIC_NUMBER_MAJOR > 20020903)
#include "mod_ssl.h"
#else
APR_DECLARE_OPTIONAL_FN(int, ssl_proxy_enable, (conn_rec *));
APR_DECLARE_OPTIONAL_FN(int, ssl_engine_disable, (conn_rec *));
#endif
#ifndef MAX
#define MAX(x,y) ((x) >= (y) ? (x) : (y))
#endif
/*
* A Web proxy module. Stages:
*
* translate_name: set filename to proxy:<URL>
* map_to_storage: run proxy_walk (rather than directory_walk/file_walk)
* can't trust directory_walk/file_walk since these are
* not in our filesystem. Prevents mod_http from serving
* the TRACE request we will set aside to handle later.
* type_checker: set type to PROXY_MAGIC_TYPE if filename begins proxy:
* fix_ups: convert the URL stored in the filename to the
* canonical form.
* handler: handle proxy requests
*/
/* -------------------------------------------------------------- */
/* Translate the URL into a 'filename' */
#ifdef FIX_15207
/* XXX: EBCDIC safe? --nd */
#define x2c(x) (((x >= '0') && (x <= '9')) \
? (x - '0') \
: (((x >= 'a') && (x <= 'f')) \
? (10 + x - 'a') \
: ((x >= 'A') && (x <='F')) \
? (10 + x - 'A') \
: 0 \
) \
)
static unsigned char hex2c(const char* p) {
const char c1 = p[1];
const char c2 = p[1] ? p[2]: '\0';
int i1 = c1 ? x2c(c1) : 0;
int i2 = c2 ? x2c(c2) : 0;
unsigned char ret = (i1 << 4) | i2;
return ret;
}
#endif
#define PROXY_COPY_CONF_PARAMS(w, c) \
do { \
(w)->timeout = (c)->timeout; \
(w)->timeout_set = (c)->timeout_set; \
(w)->recv_buffer_size = (c)->recv_buffer_size; \
(w)->recv_buffer_size_set = (c)->recv_buffer_size_set; \
(w)->io_buffer_size = (c)->io_buffer_size; \
(w)->io_buffer_size_set = (c)->io_buffer_size_set; \
} while (0)
static const char *set_worker_param(apr_pool_t *p,
proxy_worker *worker,
const char *key,
const char *val)
{
int ival;
if (!strcasecmp(key, "loadfactor")) {
worker->lbfactor = atoi(val);
if (worker->lbfactor < 1 || worker->lbfactor > 100)
return "LoadFactor must be number between 1..100";
}
else if (!strcasecmp(key, "retry")) {
ival = atoi(val);
if (ival < 1)
return "Retry must be at least one second";
worker->retry = apr_time_from_sec(ival);
}
else if (!strcasecmp(key, "ttl")) {
ival = atoi(val);
if (ival < 1)
return "TTL must be at least one second";
worker->ttl = apr_time_from_sec(ival);
}
else if (!strcasecmp(key, "min")) {
ival = atoi(val);
if (ival < 0)
return "Min must be a positive number";
worker->min = ival;
}
else if (!strcasecmp(key, "max")) {
ival = atoi(val);
if (ival < 0)
return "Max must be a positive number";
worker->hmax = ival;
}
/* XXX: More inteligent naming needed */
else if (!strcasecmp(key, "smax")) {
ival = atoi(val);
if (ival < 0)
return "Smax must be a positive number";
worker->smax = ival;
}
else if (!strcasecmp(key, "acquire")) {
ival = atoi(val);
if (ival < 1)
return "Acquire must be at least one mili second";
worker->acquire = apr_time_make(0, ival * 1000);
worker->acquire_set = 1;
}
else if (!strcasecmp(key, "timeout")) {
ival = atoi(val);
if (ival < 1)
return "Timeout must be at least one second";
worker->timeout = apr_time_from_sec(ival);
worker->timeout_set = 1;
}
else if (!strcasecmp(key, "iobuffersize")) {
long s = atol(val);
worker->io_buffer_size = ((s > AP_IOBUFSIZE) ? s : AP_IOBUFSIZE);
worker->io_buffer_size_set = 1;
}
else if (!strcasecmp(key, "receivebuffersize")) {
ival = atoi(val);
if (ival < 512 && ival != 0) {
return "ReceiveBufferSize must be >= 512 bytes, or 0 for system default.";
}
worker->recv_buffer_size = ival;
worker->recv_buffer_size_set = 1;
}
else if (!strcasecmp(key, "keepalive")) {
if (!strcasecmp(val, "on"))
worker->keepalive = 1;
else if (!strcasecmp(val, "off"))
worker->keepalive = 0;
else
return "KeepAlive must be On|Off";
worker->keepalive_set = 1;
}
else if (!strcasecmp(key, "route")) {
worker->route = apr_pstrdup(p, val);
}
else if (!strcasecmp(key, "redirect")) {
worker->redirect = apr_pstrdup(p, val);
}
else {
return "unknown parameter";
}
return NULL;
}
static const char *set_balancer_param(apr_pool_t *p,
proxy_balancer *balancer,
const char *key,
const char *val)
{
int ival;
if (!strcasecmp(key, "stickysession")) {
balancer->sticky = apr_pstrdup(p, val);
}
else if (!strcasecmp(key, "nofailover")) {
if (!strcasecmp(val, "on"))
balancer->sticky_force = 1;
else if (!strcasecmp(val, "off"))
balancer->sticky_force = 0;
else
return "failover must be On|Off";
}
else if (!strcasecmp(key, "timeout")) {
ival = atoi(val);
if (ival < 1)
return "timeout must be at least one second";
balancer->timeout = apr_time_from_sec(ival);
}
else {
return "unknown parameter";
}
return NULL;
}
static int alias_match(const char *uri, const char *alias_fakename)
{
const char *end_fakename = alias_fakename + strlen(alias_fakename);
const char *aliasp = alias_fakename, *urip = uri;
const char *end_uri = uri + strlen(uri);
unsigned char uric, aliasc;
while (aliasp < end_fakename && urip < end_uri) {
if (*aliasp == '/') {
/* any number of '/' in the alias matches any number in
* the supplied URI, but there must be at least one...
*/
if (*urip != '/')
return 0;
while (*aliasp == '/')
++aliasp;
while (*urip == '/')
++urip;
}
else {
#ifndef FIX_15207
/* Other characters are compared literally */
if (*urip++ != *aliasp++)
return 0;
#else
/* Other characters are canonicalised and compared literally */
if (*urip == '%') {
uric = hex2c(urip);
urip += 3;
} else {
uric = (unsigned char)*urip++;
}
if (*aliasp == '%') {
aliasc = hex2c(aliasp);
aliasp += 3;
} else {
aliasc = (unsigned char)*aliasp++;
}
if (uric != aliasc) {
return 0;
}
#endif
}
}
/* fixup badly encoded stuff (e.g. % as last character) */
if (aliasp > end_fakename) {
aliasp = end_fakename;
}
if (urip > end_uri) {
urip = end_uri;
}
/* Check last alias path component matched all the way */
if (aliasp[-1] != '/' && *urip != '\0' && *urip != '/')
return 0;
/* Return number of characters from URI which matched (may be
* greater than length of alias, since we may have matched
* doubled slashes)
*/
return urip - uri;
}
/* Detect if an absoluteURI should be proxied or not. Note that we
* have to do this during this phase because later phases are
* "short-circuiting"... i.e. translate_names will end when the first
* module returns OK. So for example, if the request is something like:
*
* GET http://othervhost/cgi-bin/printenv HTTP/1.0
*
* mod_alias will notice the /cgi-bin part and ScriptAlias it and
* short-circuit the proxy... just because of the ordering in the
* configuration file.
*/
static int proxy_detect(request_rec *r)
{
void *sconf = r->server->module_config;
proxy_server_conf *conf =
(proxy_server_conf *) ap_get_module_config(sconf, &proxy_module);
#ifdef FIX_15207
int i, len;
struct proxy_alias *ent = (struct proxy_alias *)conf->aliases->elts;
#endif
/* Ick... msvc (perhaps others) promotes ternary short results to int */
if (conf->req && r->parsed_uri.scheme) {
/* but it might be something vhosted */
if (!(r->parsed_uri.hostname
&& !strcasecmp(r->parsed_uri.scheme, ap_http_method(r))
&& ap_matches_request_vhost(r, r->parsed_uri.hostname,
(apr_port_t)(r->parsed_uri.port_str ? r->parsed_uri.port
: ap_default_port(r))))) {
r->proxyreq = PROXYREQ_PROXY;
r->uri = r->unparsed_uri;
r->filename = apr_pstrcat(r->pool, "proxy:", r->uri, NULL);
r->handler = "proxy-server";
}
}
/* We need special treatment for CONNECT proxying: it has no scheme part */
else if (conf->req && r->method_number == M_CONNECT
&& r->parsed_uri.hostname
&& r->parsed_uri.port_str) {
r->proxyreq = PROXYREQ_PROXY;
r->uri = r->unparsed_uri;
r->filename = apr_pstrcat(r->pool, "proxy:", r->uri, NULL);
r->handler = "proxy-server";
#ifdef FIX_15207
} else {
/* test for a ProxyPass */
for (i = 0; i < conf->aliases->nelts; i++) {
len = alias_match(r->unparsed_uri, ent[i].fake);
if (len > 0) {
r->filename = apr_pstrcat(r->pool, "proxy:", ent[i].real,
r->unparsed_uri + len, NULL);
r->handler = "proxy-server";
r->proxyreq = PROXYREQ_REVERSE;
r->uri = r->unparsed_uri;
break;
}
}
#endif
}
return DECLINED;
}
static int proxy_trans(request_rec *r)
{
#ifndef FIX_15207
void *sconf = r->server->module_config;
proxy_server_conf *conf =
(proxy_server_conf *) ap_get_module_config(sconf, &proxy_module);
int i, len;
struct proxy_alias *ent = (struct proxy_alias *) conf->aliases->elts;
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -