mod_proxy.c revision 75b0a6a06ca1f4de80e3dd2a09c9f0c7d0a56089
0f6bc9e2c8229996a73fb57ec6c45841346ebcb1pctony/* Copyright 1999-2004 The Apache Software Foundation
fd9abdda70912b99b24e3bf1a38f26fde908a74cnd * Licensed under the Apache License, Version 2.0 (the "License");
fd9abdda70912b99b24e3bf1a38f26fde908a74cnd * you may not use this file except in compliance with the License.
0f6bc9e2c8229996a73fb57ec6c45841346ebcb1pctony * You may obtain a copy of the License at
96ad5d81ee4a2cc66a4ae19893efc8aa6d06fae7jailletc * Unless required by applicable law or agreed to in writing, software
0f6bc9e2c8229996a73fb57ec6c45841346ebcb1pctony * distributed under the License is distributed on an "AS IS" BASIS,
0f6bc9e2c8229996a73fb57ec6c45841346ebcb1pctony * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
d29d9ab4614ff992b0e8de6e2b88d52b6f1f153erbowen * See the License for the specific language governing permissions and
2e545ce2450a9953665f701bb05350f0d3f26275nd * limitations under the License.
0f6bc9e2c8229996a73fb57ec6c45841346ebcb1pctonyAPR_DECLARE_OPTIONAL_FN(int, ssl_proxy_enable, (conn_rec *));
0f6bc9e2c8229996a73fb57ec6c45841346ebcb1pctonyAPR_DECLARE_OPTIONAL_FN(int, ssl_engine_disable, (conn_rec *));
f086b4b402fa9a2fefc7dda85de2a3cc1cd0a654rjung#define MAX(x,y) ((x) >= (y) ? (x) : (y))
0f6bc9e2c8229996a73fb57ec6c45841346ebcb1pctony * A Web proxy module. Stages:
0f6bc9e2c8229996a73fb57ec6c45841346ebcb1pctony * translate_name: set filename to proxy:<URL>
94cfb5d816f18c39adb74a03b6502ab73e35a73bnilgun * map_to_storage: run proxy_walk (rather than directory_walk/file_walk)
94cfb5d816f18c39adb74a03b6502ab73e35a73bnilgun * can't trust directory_walk/file_walk since these are
94cfb5d816f18c39adb74a03b6502ab73e35a73bnilgun * not in our filesystem. Prevents mod_http from serving
94cfb5d816f18c39adb74a03b6502ab73e35a73bnilgun * the TRACE request we will set aside to handle later.
0f6bc9e2c8229996a73fb57ec6c45841346ebcb1pctony * type_checker: set type to PROXY_MAGIC_TYPE if filename begins proxy:
94cfb5d816f18c39adb74a03b6502ab73e35a73bnilgun * fix_ups: convert the URL stored in the filename to the
94cfb5d816f18c39adb74a03b6502ab73e35a73bnilgun * canonical form.
94cfb5d816f18c39adb74a03b6502ab73e35a73bnilgun * handler: handle proxy requests
0f6bc9e2c8229996a73fb57ec6c45841346ebcb1pctony/* -------------------------------------------------------------- */
0f6bc9e2c8229996a73fb57ec6c45841346ebcb1pctony/* Translate the URL into a 'filename' */
0f6bc9e2c8229996a73fb57ec6c45841346ebcb1pctony/* XXX: EBCDIC safe? --nd */
0f6bc9e2c8229996a73fb57ec6c45841346ebcb1pctony ? (x - '0') \
30471a4650391f57975f60bbb6e4a90be7b284bfhumbedoohstatic unsigned char hex2c(const char* p) {
0f6bc9e2c8229996a73fb57ec6c45841346ebcb1pctonystatic const char *set_worker_param(proxy_worker *worker,
0f6bc9e2c8229996a73fb57ec6c45841346ebcb1pctony const char *key,
0f6bc9e2c8229996a73fb57ec6c45841346ebcb1pctony const char *val)
0f6bc9e2c8229996a73fb57ec6c45841346ebcb1pctony return "loadfactor must be number between 1..100";
0f6bc9e2c8229996a73fb57ec6c45841346ebcb1pctony return "retry must be al least one second";
0f6bc9e2c8229996a73fb57ec6c45841346ebcb1pctony return "ttl must be al least one second";
0f6bc9e2c8229996a73fb57ec6c45841346ebcb1pctony return "min must be a positive number";
0f6bc9e2c8229996a73fb57ec6c45841346ebcb1pctony return "max must be a positive number";
0f6bc9e2c8229996a73fb57ec6c45841346ebcb1pctony /* XXX: More inteligent naming needed */
0f6bc9e2c8229996a73fb57ec6c45841346ebcb1pctony return "smax must be a positive number";
0f6bc9e2c8229996a73fb57ec6c45841346ebcb1pctony return "unknown parameter";
0f6bc9e2c8229996a73fb57ec6c45841346ebcb1pctonystatic const char *set_balancer_param(struct proxy_balancer *balancer,
0f6bc9e2c8229996a73fb57ec6c45841346ebcb1pctony const char *key,
0f6bc9e2c8229996a73fb57ec6c45841346ebcb1pctony const char *val)
b2a930a0c94e9fd25f8d2b3a2c53573235db3f06nilgun return "failover must be On|Off";
b2a930a0c94e9fd25f8d2b3a2c53573235db3f06nilgun return "timeout must be al least one second";
b2a930a0c94e9fd25f8d2b3a2c53573235db3f06nilgun return "unknown parameter";
b2a930a0c94e9fd25f8d2b3a2c53573235db3f06nilgunstatic int alias_match(const char *uri, const char *alias_fakename)
b2a930a0c94e9fd25f8d2b3a2c53573235db3f06nilgun const char *end_fakename = alias_fakename + strlen(alias_fakename);
94cfb5d816f18c39adb74a03b6502ab73e35a73bnilgun /* any number of '/' in the alias matches any number in
94cfb5d816f18c39adb74a03b6502ab73e35a73bnilgun * the supplied URI, but there must be at least one...
0f6bc9e2c8229996a73fb57ec6c45841346ebcb1pctony /* Other characters are compared literally */
0f6bc9e2c8229996a73fb57ec6c45841346ebcb1pctony /* Other characters are canonicalised and compared literally */
0f6bc9e2c8229996a73fb57ec6c45841346ebcb1pctony /* fixup badly encoded stuff (e.g. % as last character) */
0f6bc9e2c8229996a73fb57ec6c45841346ebcb1pctony /* Check last alias path component matched all the way */
0f6bc9e2c8229996a73fb57ec6c45841346ebcb1pctony if (aliasp[-1] != '/' && *urip != '\0' && *urip != '/')
0f6bc9e2c8229996a73fb57ec6c45841346ebcb1pctony /* Return number of characters from URI which matched (may be
0f6bc9e2c8229996a73fb57ec6c45841346ebcb1pctony * greater than length of alias, since we may have matched
0f6bc9e2c8229996a73fb57ec6c45841346ebcb1pctony * doubled slashes)
0f6bc9e2c8229996a73fb57ec6c45841346ebcb1pctony/* Detect if an absoluteURI should be proxied or not. Note that we
94cfb5d816f18c39adb74a03b6502ab73e35a73bnilgun * have to do this during this phase because later phases are
0f6bc9e2c8229996a73fb57ec6c45841346ebcb1pctony * "short-circuiting"... i.e. translate_names will end when the first
0f6bc9e2c8229996a73fb57ec6c45841346ebcb1pctony * module returns OK. So for example, if the request is something like:
0f6bc9e2c8229996a73fb57ec6c45841346ebcb1pctony * mod_alias will notice the /cgi-bin part and ScriptAlias it and
0f6bc9e2c8229996a73fb57ec6c45841346ebcb1pctony * short-circuit the proxy... just because of the ordering in the
0f6bc9e2c8229996a73fb57ec6c45841346ebcb1pctony * configuration file.
0f6bc9e2c8229996a73fb57ec6c45841346ebcb1pctony (proxy_server_conf *) ap_get_module_config(sconf, &proxy_module);
0f6bc9e2c8229996a73fb57ec6c45841346ebcb1pctony struct proxy_alias *ent = (struct proxy_alias *)conf->aliases->elts;
0f6bc9e2c8229996a73fb57ec6c45841346ebcb1pctony /* Ick... msvc (perhaps others) promotes ternary short results to int */
0f6bc9e2c8229996a73fb57ec6c45841346ebcb1pctony /* but it might be something vhosted */
0f6bc9e2c8229996a73fb57ec6c45841346ebcb1pctony && !strcasecmp(r->parsed_uri.scheme, ap_http_method(r))
0f6bc9e2c8229996a73fb57ec6c45841346ebcb1pctony && ap_matches_request_vhost(r, r->parsed_uri.hostname,
0f6bc9e2c8229996a73fb57ec6c45841346ebcb1pctony (apr_port_t)(r->parsed_uri.port_str ? r->parsed_uri.port
0f6bc9e2c8229996a73fb57ec6c45841346ebcb1pctony r->filename = apr_pstrcat(r->pool, "proxy:", r->uri, NULL);
0f6bc9e2c8229996a73fb57ec6c45841346ebcb1pctony /* We need special treatment for CONNECT proxying: it has no scheme part */
94cfb5d816f18c39adb74a03b6502ab73e35a73bnilgun r->filename = apr_pstrcat(r->pool, "proxy:", r->uri, NULL);
94cfb5d816f18c39adb74a03b6502ab73e35a73bnilgun /* test for a ProxyPass */
0f6bc9e2c8229996a73fb57ec6c45841346ebcb1pctony r->filename = apr_pstrcat(r->pool, "proxy:", ent[i].real,
0f6bc9e2c8229996a73fb57ec6c45841346ebcb1pctony (proxy_server_conf *) ap_get_module_config(sconf, &proxy_module);
94cfb5d816f18c39adb74a03b6502ab73e35a73bnilgun struct proxy_alias *ent = (struct proxy_alias *) conf->aliases->elts;
0f6bc9e2c8229996a73fb57ec6c45841346ebcb1pctony /* someone has already set up the proxy, it was possibly ourselves
0f6bc9e2c8229996a73fb57ec6c45841346ebcb1pctony * in proxy_detect
0f6bc9e2c8229996a73fb57ec6c45841346ebcb1pctony /* XXX: since r->uri has been manipulated already we're not really
0f6bc9e2c8229996a73fb57ec6c45841346ebcb1pctony * compliant with RFC1945 at this point. But this probably isn't
0f6bc9e2c8229996a73fb57ec6c45841346ebcb1pctony * an issue because this is a hybrid proxy/origin server.
0f6bc9e2c8229996a73fb57ec6c45841346ebcb1pctony if ((ent[i].real[0] == '!') && (ent[i].real[1] == 0)) {
0f6bc9e2c8229996a73fb57ec6c45841346ebcb1pctony r->filename = apr_pstrcat(r->pool, "proxy:", ent[i].real,
0f6bc9e2c8229996a73fb57ec6c45841346ebcb1pctony proxy_server_conf *sconf = ap_get_module_config(r->server->module_config,
0f6bc9e2c8229996a73fb57ec6c45841346ebcb1pctony ap_conf_vector_t *per_dir_defaults = r->server->lookup_defaults;
0f6bc9e2c8229996a73fb57ec6c45841346ebcb1pctony ap_conf_vector_t **sec_proxy = (ap_conf_vector_t **) sconf->sec_proxy->elts;
0f6bc9e2c8229996a73fb57ec6c45841346ebcb1pctony /* XXX: shouldn't we use URI here? Canonicalize it first?
0f6bc9e2c8229996a73fb57ec6c45841346ebcb1pctony * Pass over "proxy:" prefix
0f6bc9e2c8229996a73fb57ec6c45841346ebcb1pctony for (j = 0; j < num_sec; ++j)
0f6bc9e2c8229996a73fb57ec6c45841346ebcb1pctony entry_proxy = ap_get_module_config(entry_config, &proxy_module);
0f6bc9e2c8229996a73fb57ec6c45841346ebcb1pctony /* XXX: What about case insensitive matching ???
0f6bc9e2c8229996a73fb57ec6c45841346ebcb1pctony * Compare regex, fnmatch or string as appropriate
0f6bc9e2c8229996a73fb57ec6c45841346ebcb1pctony * If the entry doesn't relate, then continue
0f6bc9e2c8229996a73fb57ec6c45841346ebcb1pctony per_dir_defaults = ap_merge_per_dir_configs(r->pool, per_dir_defaults,
0f6bc9e2c8229996a73fb57ec6c45841346ebcb1pctony if (!r->proxyreq || !r->filename || strncmp(r->filename, "proxy:", 6) != 0)
0f6bc9e2c8229996a73fb57ec6c45841346ebcb1pctony /* Don't let the core or mod_http map_to_storage hooks handle this,
0f6bc9e2c8229996a73fb57ec6c45841346ebcb1pctony * We don't need directory/file_walk, and we want to TRACE on our own.
0f6bc9e2c8229996a73fb57ec6c45841346ebcb1pctony/* -------------------------------------------------------------- */
0f6bc9e2c8229996a73fb57ec6c45841346ebcb1pctony/* Fixup the filename */
0f6bc9e2c8229996a73fb57ec6c45841346ebcb1pctony * Canonicalise the URL
0f6bc9e2c8229996a73fb57ec6c45841346ebcb1pctony if (!r->proxyreq || !r->filename || strncmp(r->filename, "proxy:", 6) != 0)
0f6bc9e2c8229996a73fb57ec6c45841346ebcb1pctony/* We definitely shouldn't canonicalize a proxy_pass.
0f6bc9e2c8229996a73fb57ec6c45841346ebcb1pctony * But should we really canonicalize a STD_PROXY??? -- Fahree
0f6bc9e2c8229996a73fb57ec6c45841346ebcb1pctony /* XXX: Shouldn't we try this before we run the proxy_walk? */
0f6bc9e2c8229996a73fb57ec6c45841346ebcb1pctony /* canonicalise each specific scheme */
0f6bc9e2c8229996a73fb57ec6c45841346ebcb1pctony if ((access_status = proxy_run_canon_handler(r, url))) {
94cfb5d816f18c39adb74a03b6502ab73e35a73bnilgun return OK; /* otherwise; we've done the best we can */
94cfb5d816f18c39adb74a03b6502ab73e35a73bnilgun/* Send a redirection if the request contains a hostname which is not */
94cfb5d816f18c39adb74a03b6502ab73e35a73bnilgun/* fully qualified, i.e. doesn't have a domain name appended. Some proxy */
94cfb5d816f18c39adb74a03b6502ab73e35a73bnilgun/* servers like Netscape's allow this and access hosts from the local */
94cfb5d816f18c39adb74a03b6502ab73e35a73bnilgun/* domain in this case. I think it is better to redirect to a FQDN, since */
94cfb5d816f18c39adb74a03b6502ab73e35a73bnilgun/* these will later be found in the bookmarks files. */
94cfb5d816f18c39adb74a03b6502ab73e35a73bnilgun/* The "ProxyDomain" directive determines what domain will be appended */
94cfb5d816f18c39adb74a03b6502ab73e35a73bnilgunstatic int proxy_needsdomain(request_rec *r, const char *url, const char *domain)
94cfb5d816f18c39adb74a03b6502ab73e35a73bnilgun const char *ref;
94cfb5d816f18c39adb74a03b6502ab73e35a73bnilgun /* We only want to worry about GETs */
0f6bc9e2c8229996a73fb57ec6c45841346ebcb1pctony if (!r->proxyreq || r->method_number != M_GET || !r->parsed_uri.hostname)
0f6bc9e2c8229996a73fb57ec6c45841346ebcb1pctony /* If host does contain a dot already, or it is "localhost", decline */
0f6bc9e2c8229996a73fb57ec6c45841346ebcb1pctony || strcasecmp(r->parsed_uri.hostname, "localhost") == 0)
0d0ba3a410038e179b695446bb149cce6264e0abnd /* Reassemble the request, but insert the domain after the host name */
727872d18412fc021f03969b8641810d8896820bhumbedooh /* Note that the domain name always starts with a dot */
cc7e1025de9ac63bd4db6fe7f71c158b2cf09fe4humbedooh r->parsed_uri.hostname = apr_pstrcat(r->pool, r->parsed_uri.hostname,
af33a4994ae2ff15bc67d19ff1a7feb906745bf8rbowen/* -------------------------------------------------------------- */
0d0ba3a410038e179b695446bb149cce6264e0abnd/* Invoke handler */
const char *p2;
int direct_connect = 0;
const char *str;
long maxfwd;
return DECLINED;
switch (r->method_number) {
case M_TRACE: {
int access_status;
return OK;
case M_OPTIONS: {
int access_status;
return OK;
if (p == NULL)
return HTTP_BAD_REQUEST;
return HTTP_MOVED_PERMANENTLY;
int ii;
#if DEBUGGING
r->uri);
return access_status;
if (!direct_connect) {
return access_status;
return HTTP_FORBIDDEN;
return access_status;
return ps;
ps->allowed_connect_ports = apr_array_append(p, base->allowed_connect_ports, overrides->allowed_connect_ports);
ps->recv_buffer_size = (overrides->recv_buffer_size_set == 0) ? base->recv_buffer_size : overrides->recv_buffer_size;
ps->io_buffer_size = (overrides->io_buffer_size_set == 0) ? base->io_buffer_size : overrides->io_buffer_size;
ps->error_override = (overrides->error_override_set == 0) ? base->error_override : overrides->error_override;
ps->preserve_host = (overrides->preserve_host_set == 0) ? base->preserve_host : overrides->preserve_host;
return ps;
return (void *) new;
return new;
char *r, *f, *scheme;
int port;
if (regex)
scheme[p-r] = 0;
if (q != NULL) {
if (regex)
if (regex) {
if (!reg)
return NULL;
char *r = NULL;
char *word;
while (*arg) {
f = word;
r = word;
if (!val) {
if (r == NULL)
if (!balancer) {
conf, r);
if (err)
if (err)
if (!worker) {
if (err)
if (err)
return NULL;
&proxy_module);
if ( r == NULL)
return NULL;
&proxy_module);
return NULL;
&proxy_module);
return NULL;
int found = 0;
if (!found) {
return NULL;
int *New;
return NULL;
int found = 0;
if (!found) {
#if DEBUGGING
#if DEBUGGING
#if DEBUGGING
#if DEBUGGING
return NULL;
return NULL;
return NULL;
return NULL;
return NULL;
return NULL;
return NULL;
return NULL;
int timeout;
return NULL;
return NULL;
return NULL;
char *word;
while (*arg) {
if (!path)
else if (!name)
if (!val)
if (!path)
if (!name)
if (!worker) {
const char *err;
if (err)
if (!balancer) {
if (err)
return NULL;
name = f;
sticky = r;
sticky = f;
if (r == NULL)
if (!balancer)
return NULL;
&proxy_module);
const char *errmsg;
return err;
if (!arg) {
return errmsg;
conf->r = r;
return NULL;
{NULL}
if (proxy_ssl_enable) {
if (proxy_ssl_disable) {
return proxy_ssl_disable(c);
return OK;
#ifndef FIX_15207
#ifndef FIX_15207
request_rec *r,
request_rec *r,
(request_rec *r), (r),