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

📄 mod_proxy.c

📁 apache简化版
💻 C
📖 第 1 页 / 共 2 页
字号:
/* ==================================================================== * Copyright (c) 1996-1998 The Apache Group.  All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer.  * * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in *    the documentation and/or other materials provided with the *    distribution. * * 3. All advertising materials mentioning features or use of this *    software must display the following acknowledgment: *    "This product includes software developed by the Apache Group *    for use in the Apache HTTP server project (http://www.apache.org/)." * * 4. The names "Apache Server" and "Apache Group" must not be used to *    endorse or promote products derived from this software without *    prior written permission. For written permission, please contact *    apache@apache.org. * * 5. Products derived from this software may not be called "Apache" *    nor may "Apache" appear in their names without prior written *    permission of the Apache Group. * * 6. Redistributions of any form whatsoever must retain the following *    acknowledgment: *    "This product includes software developed by the Apache Group *    for use in the Apache HTTP server project (http://www.apache.org/)." * * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE APACHE GROUP OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Group and was originally based * on public domain software written at the National Center for * Supercomputing Applications, University of Illinois, Urbana-Champaign. * For more information on the Apache Group and the Apache HTTP server * project, please see <http://www.apache.org/>. * */#include "mod_proxy.h"#define CORE_PRIVATE#include "http_log.h"#include "http_vhost.h"#include "http_request.h"/* Some WWW schemes and their default ports; this is basically /etc/services *//* This will become global when the protocol abstraction comes */static struct proxy_services defports[] ={    {"http", DEFAULT_HTTP_PORT},    {"ftp", DEFAULT_FTP_PORT},    {"https", DEFAULT_HTTPS_PORT},    {"gopher", DEFAULT_GOPHER_PORT},    {"nntp", DEFAULT_NNTP_PORT},    {"wais", DEFAULT_WAIS_PORT},    {"snews", DEFAULT_SNEWS_PORT},    {"prospero", DEFAULT_PROSPERO_PORT},    {NULL, -1}			/* unknown port */};/* * A Web proxy module. Stages: * *  translate_name: set filename to proxy:<URL> *  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' */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;    while (aliasp < end_fakename) {	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 {	    /* Other characters are compared literally */	    if (*urip++ != *aliasp++)		return 0;	}    }    /* 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;    conf = (proxy_server_conf *) ap_get_module_config(sconf, &proxy_module);    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,               r->parsed_uri.port_str ? r->parsed_uri.port : ap_default_port(r)))) {	    r->proxyreq = 1;	    r->uri = r->unparsed_uri;	    r->filename = ap_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 = 1;	    r->uri = r->unparsed_uri;	    r->filename = ap_pstrcat(r->pool, "proxy:", r->uri, NULL);	    r->handler = "proxy-server";    }    return DECLINED;}static int proxy_trans(request_rec *r){    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;    if (r->proxyreq) {	/* someone has already set up the proxy, it was possibly ourselves	 * in proxy_detect	 */	return OK;    }    /* XXX: since r->uri has been manipulated already we're not really     * compliant with RFC1945 at this point.  But this probably isn't     * an issue because this is a hybrid proxy/origin server.     */    for (i = 0; i < conf->aliases->nelts; i++) {        len = alias_match(r->uri, ent[i].fake);	           if (len > 0) {           r->filename = ap_pstrcat(r->pool, "proxy:", ent[i].real,                                 r->uri + len, NULL);           r->handler = "proxy-server";           r->proxyreq = 1;           return OK;	}    }    return DECLINED;}/* -------------------------------------------------------------- *//* Fixup the filename *//* * Canonicalise the URL */static int proxy_fixup(request_rec *r){    char *url, *p;    if (!r->proxyreq || strncmp(r->filename, "proxy:", 6) != 0)	return DECLINED;    url = &r->filename[6];/* canonicalise each specific scheme */    if (strncasecmp(url, "http:", 5) == 0)	return ap_proxy_http_canon(r, url + 5, "http", DEFAULT_HTTP_PORT);    else if (strncasecmp(url, "ftp:", 4) == 0)	return ap_proxy_ftp_canon(r, url + 4);    p = strchr(url, ':');    if (p == NULL || p == url)	return HTTP_BAD_REQUEST;    return OK;		/* otherwise; we've done the best we can */}static void proxy_init(server_rec *r, pool *p){    ap_proxy_garbage_init(r, p);}/* Send a redirection if the request contains a hostname which is not *//* fully qualified, i.e. doesn't have a domain name appended. Some proxy *//* servers like Netscape's allow this and access hosts from the local *//* domain in this case. I think it is better to redirect to a FQDN, since *//* these will later be found in the bookmarks files. *//* The "ProxyDomain" directive determines what domain will be appended */static int proxy_needsdomain(request_rec *r, const char *url, const char *domain){    char *nuri;    const char *ref;    /* We only want to worry about GETs */    if (!r->proxyreq || r->method_number != M_GET || !r->parsed_uri.hostname)	return DECLINED;    /* If host does contain a dot already, or it is "localhost", decline */    if (strchr(r->parsed_uri.hostname, '.') != NULL     || strcasecmp(r->parsed_uri.hostname, "localhost") == 0)	return DECLINED;	/* host name has a dot already */    ref = ap_table_get(r->headers_in, "Referer");    /* Reassemble the request, but insert the domain after the host name */    /* Note that the domain name always starts with a dot */    r->parsed_uri.hostname = ap_pstrcat(r->pool, r->parsed_uri.hostname,				     domain, NULL);    nuri = ap_unparse_uri_components(r->pool,				  &r->parsed_uri,				  UNP_REVEALPASSWORD);    ap_table_set(r->headers_out, "Location", nuri);    ap_log_rerror(APLOG_MARK, APLOG_INFO|APLOG_NOERRNO, r,		"Domain missing: %s sent to %s%s%s", r->uri,		ap_unparse_uri_components(r->pool, &r->parsed_uri,		      UNP_OMITUSERINFO),		ref ? " from " : "", ref ? ref : "");    return HTTP_MOVED_PERMANENTLY;}/* -------------------------------------------------------------- *//* Invoke handler */static int proxy_handler(request_rec *r){    char *url, *scheme, *p;    void *sconf = r->server->module_config;    proxy_server_conf *conf =    (proxy_server_conf *) ap_get_module_config(sconf, &proxy_module);    array_header *proxies = conf->proxies;    struct proxy_remote *ents = (struct proxy_remote *) proxies->elts;    int i, rc;    cache_req *cr;    int direct_connect = 0;    const char *maxfwd_str;    if (!r->proxyreq || strncmp(r->filename, "proxy:", 6) != 0)	return DECLINED;    if (r->method_number == M_TRACE &&	(maxfwd_str = ap_table_get(r->headers_in, "Max-Forwards")) != NULL) {	int maxfwd = strtol(maxfwd_str, NULL, 10);	if (maxfwd < 1) {	    int access_status;	    r->proxyreq = 0;	    if ((access_status = ap_send_http_trace(r)))		ap_die(access_status, r);	    else		ap_finalize_request_protocol(r);	    return OK;	}	ap_table_setn(r->headers_in, "Max-Forwards", 		      ap_psprintf(r->pool, "%d", (maxfwd > 0) ? maxfwd-1 : 0));    }    if ((rc = ap_setup_client_block(r, REQUEST_CHUNKED_ERROR)))	return rc;    url = r->filename + 6;    p = strchr(url, ':');    if (p == NULL)	return HTTP_BAD_REQUEST;    rc = ap_proxy_cache_check(r, url, &conf->cache, &cr);    if (rc != DECLINED)	return rc;    /* If the host doesn't have a domain name, add one and redirect. */    if (conf->domain != NULL) {	rc = proxy_needsdomain(r, url, conf->domain);	if (ap_is_HTTP_REDIRECT(rc))	    return HTTP_MOVED_PERMANENTLY;    }    *p = '\0';    scheme = ap_pstrdup(r->pool, url);    *p = ':';    /* Check URI's destination host against NoProxy hosts */    /* Bypass ProxyRemote server lookup if configured as NoProxy */    /* we only know how to handle communication to a proxy via http */    /*if (strcasecmp(scheme, "http") == 0) */    {	int ii;	struct dirconn_entry *list = (struct dirconn_entry *) conf->dirconn->elts;	for (direct_connect = ii = 0; ii < conf->dirconn->nelts && !direct_connect; ii++) {	    direct_connect = list[ii].matcher(&list[ii], r);	}#if DEBUGGING	ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, r,		     (direct_connect) ? "NoProxy for %s" : "UseProxy for %s",		     r->uri);#endif    }/* firstly, try a proxy, unless a NoProxy directive is active */    if (!direct_connect)	for (i = 0; i < proxies->nelts; i++) {	    p = strchr(ents[i].scheme, ':');	/* is it a partial URL? */	    if (strcmp(ents[i].scheme, "*") == 0 ||		(p == NULL && strcasecmp(scheme, ents[i].scheme) == 0) ||		(p != NULL &&	       strncasecmp(url, ents[i].scheme, strlen(ents[i].scheme)) == 0)) {		/* CONNECT is a special method that bypasses the normal		 * proxy code.		 */		if (r->method_number == M_CONNECT)		    rc = ap_proxy_connect_handler(r, cr, url, ents[i].hostname,					       ents[i].port);/* we only know how to handle communication to a proxy via http */		else if (strcasecmp(ents[i].protocol, "http") == 0)		    rc = ap_proxy_http_handler(r, cr, url, ents[i].hostname,					    ents[i].port);		else		    rc = DECLINED;		/* an error or success */		if (rc != DECLINED && rc != HTTP_BAD_GATEWAY)		    return rc;		/* we failed to talk to the upstream proxy */	    }	}/* otherwise, try it direct *//* N.B. what if we're behind a firewall, where we must use a proxy or * give up?? */    /* handle the scheme */    if (r->method_number == M_CONNECT)	return ap_proxy_connect_handler(r, cr, url, NULL, 0);    if (strcasecmp(scheme, "http") == 0)	return ap_proxy_http_handler(r, cr, url, NULL, 0);    if (strcasecmp(scheme, "ftp") == 0)	return ap_proxy_ftp_handler(r, cr, url);    else	return NOT_IMPLEMENTED;}/* -------------------------------------------------------------- *//* Setup configurable data */static void *     create_proxy_config(pool *p, server_rec *s){    proxy_server_conf *ps = ap_pcalloc(p, sizeof(proxy_server_conf));    ps->proxies = ap_make_array(p, 10, sizeof(struct proxy_remote));    ps->aliases = ap_make_array(p, 10, sizeof(struct proxy_alias));    ps->raliases = ap_make_array(p, 10, sizeof(struct proxy_alias));    ps->noproxies = ap_make_array(p, 10, sizeof(struct noproxy_entry));    ps->dirconn = ap_make_array(p, 10, sizeof(struct dirconn_entry));    ps->nocaches = ap_make_array(p, 10, sizeof(struct nocache_entry));    ps->allowed_connect_ports = ap_make_array(p, 10, sizeof(int));    ps->domain = NULL;    ps->viaopt = via_off; /* initially backward compatible with 1.3.1 */    ps->req = 0;    ps->cache.root = NULL;    ps->cache.space = DEFAULT_CACHE_SPACE;    ps->cache.maxexpire = DEFAULT_CACHE_MAXEXPIRE;    ps->cache.defaultexpire = DEFAULT_CACHE_EXPIRE;    ps->cache.lmfactor = DEFAULT_CACHE_LMFACTOR;    ps->cache.gcinterval = -1;    /* at these levels, the cache can have 2^18 directories (256,000)  */    ps->cache.dirlevels = 3;    ps->cache.dirlength = 1;    ps->cache.cache_completion = DEFAULT_CACHE_COMPLETION;    return ps;}static const char *     add_proxy(cmd_parms *cmd, void *dummy, char *f, char *r){    server_rec *s = cmd->server;    proxy_server_conf *conf =    (proxy_server_conf *) ap_get_module_config(s->module_config, &proxy_module);    struct proxy_remote *new;    char *p, *q;    int port;    p = strchr(r, ':');    if (p == NULL || p[1] != '/' || p[2] != '/' || p[3] == '\0')	return "ProxyRemote: Bad syntax for a remote proxy server";    q = strchr(p + 3, ':');    if (q != NULL) {

⌨️ 快捷键说明

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