proxydispatcher.java

来自「很棒的web服务器源代码」· Java 代码 · 共 346 行

JAVA
346
字号
// ProxyDispatcher.java// $Id: ProxyDispatcher.java,v 1.31 2000/08/16 21:38:05 ylafon Exp $// (c) COPYRIGHT MIT and INRIA, 1996.// please first read the full copyright statement in file COPYRIGHT.HTMLpackage org.w3c.www.protocol.http.proxy ;import java.io.BufferedInputStream;import java.io.File;import java.io.FileInputStream;import java.io.IOException;import java.io.InputStream;import java.io.PrintStream;import java.net.URL;import java.net.URLConnection;import org.w3c.util.ObservableProperties;import org.w3c.util.PropertyMonitoring;import org.w3c.www.protocol.http.HttpException;import org.w3c.www.protocol.http.HttpManager;import org.w3c.www.protocol.http.PropRequestFilter;import org.w3c.www.protocol.http.Reply;import org.w3c.www.protocol.http.Request;import org.w3c.www.http.HttpRequestMessage;/** * The proxy dispatcher applies some <em>rules</em> to a request. * The goal of that filter is to allow special pre-processing of requests * based, on their target host, before sending them off the net. * <p>The filter is configured through a <em>rule file</em> whose format * is described by the following BNF: * <code> * rule-file=(<em>record</em>)*<br> * record=<strong>EOL</strong>|<em>comment</em>|<em>rule</em><br> * comment=<strong>#</strong>(<strong>^EOL</strong>)*<strong>EOL</strong><br> * rule=<em>rule-lhs</em>(<strong>SPACE</strong>)*<em>rule-rhs</em><br> * rule-lhs=(<strong>token</strong>) *  |(<strong>token</strong> (<strong>.</strong> <strog>token</strong>)*<br> * rule-lhr=<em>forbid</em>|<em>direct</em>|<em>redirect</em> *          |<em>proxy</em>|<em>authorization</em>|<em>proxyauth</em><br> * forbid=<strong>FORBID</strong>|<strong>forbid</strong><br> * direct=<strong>DIRECT</strong>|<strong>direct</strong><br> * redirect=(<strong>REDIRECT</strong>|<strong>proxy</strong>) <em>url</em><br> * proxy=(<strong>PROXY</strong>|<strong>proxy</strong>) <em>url</em><br> * url=<strong>any valid URL</strong></br> * authorization=(<strong>AUTHORIZATION</strong>|<strong>authorization</strong> *  <em>user</em> <em>password</em><br> * proxyauth=(<strong>PROXYAUTH</strong>|<strong>proxyauth</strong> *  <em>user</em> <em>password</em> <em>url</em><br> * </code> * <p>A sample rule file looks like this: * <code> * # Some comments *  * edu proxy http://class.w3.org:8001/ * org proxy http://class.w3.org:8001/ * fr  direct * www.evilsite.com redirect http://www.goodsite.com/warning.html * www.w3.org direct * 138.96.24 direct * www.playboy.com forbid * default proxy http://cache.inria.fr:8080/ * </code> * <p>The algorithm used to lookup rules is the following:  * <ul> * <li>Split all rules <em>left hand side</em> into its components, eg  * H1.H2.H3 is splitted into { H1, H2, H3 }, then reverse the components and  * map that to the rule. In our example above, { org, w3, www} would be mapped * to <em>direct</em>. * <li>Split the fully qualified host name into its components, eg, A.B.C is * splitted into { A, B, C } and reverse it. * <li>Find the longest match in the mapping table of rules, and get * apply the given rule. * </ul> * <p>In our example, a request to <strong>www.isi.edu</strong> would match * the <em>edu</em> rule, and a request for <strong>www.w3.org</strong> * would match the <em>direct</em> rule, for example. * <p>Three rules are defined: * <dl> * <dt>direct<dd>Run that request directly against the target host. * <dt>forbid<dd>Emit a forbid message, indicating that the user is not * allowed to contact this host. * <dt>proxy<dd>Run that request through the given <em>proxy</em>. * <dt>proxyauth<dd>Run that request through a proxy with the right proxy * credentials. * </dl> * <p>For numeric IP addresses, the most significant part is the beginning, * so {A, B, C} are deducted directly. In the example { 138, 96, 24 } is mapped * to direct. * <p>If no rules are applied, then the default rule (root rule) is applied. * See the example. */public class ProxyDispatcher    implements PropRequestFilter, PropertyMonitoring {    /**     * Name of the property giving the rule file URL.     */    public static final     String RULE_P = "org.w3c.www.protocol.http.proxy.rules";    /**     * Name of the property turning that filter in debug mode.     */    public static final    String DEBUG_P = "org.w3c.www.protocol.http.proxy.debug";    /**     * Name of the property turning that filter in debug mode.     */    public static final	String CHECK_RULES_LAST_MODIFIED_P = 	"org.w3c.www.protocol.http.proxy.rules.check.lastmodified";    /**     * The properties we initialized ourself from.     */    protected ObservableProperties props = null;      /**     * The current set of rules to apply.     */    protected RuleNode rules = null;    /**     * Are we in debug mode ?     */    protected boolean debug = false;    protected boolean check_rules = false;    protected static final String disabled = "disabled";    protected long lastParsingTime = -1;    /**     * Parse the given input stream as a rule file.     * @param in The input stream to parse.     * @exception IOException if an IO error occurs.     * @exception RuleParserException if parsing failed.     */    protected void parseRules(InputStream in)	throws IOException, RuleParserException    {	RuleParser parser = new RuleParser(in);	RuleNode   nroot  = parser.parse();	rules = nroot;	lastParsingTime = System.currentTimeMillis();    }    /**     * Parse the default set of rules.     * <p>IOf the rules cannot be parsed, the filter emits an error     * message to standard error, and turn itself into transparent mode.     */    protected void parseRules() {	if ( debug )	    System.out.println("PARSING RULES...");	String ruleurl = props.getString(RULE_P, null);	InputStream in = null;	// Try opening the rule file as a URL:	try {	    URL url = new URL(ruleurl);	    in = url.openStream();	} catch (Exception ex) {	// If this fails, it may be just a file name:	    try {		in = (new BufferedInputStream		      (new FileInputStream		       (new File(ruleurl))));	    } catch (Exception nex) {		System.err.println("* ProxyDispatcher: unable to open rule "				   + "file \"" + ruleurl + "\"");		rules = null;		return;	    }	} 	// Parse that input stream as a rule file:	try {	    parseRules(in);	} catch (Exception ex) {	    System.err.println("Error parsing rules from: "+ruleurl);	    ex.printStackTrace();	    rules = null;	    	} finally {	    if ( in != null ) {		try {		    in.close();		} catch (IOException ex) {		}	    }	}	if ( debug )	    System.out.println("DONE.");    }    protected boolean needsParsing() {	if (rules == null) 	    return true;	if (! check_rules)	    return false;	long rulesStamp = -1;	String ruleurl  = props.getString(RULE_P, null);	try {	    URL url = new URL(ruleurl);	    if (url.getProtocol().equalsIgnoreCase("file")) {		File file = new File(url.getFile());		rulesStamp = file.lastModified();	    } else {		URLConnection con = url.openConnection();		rulesStamp = con.getLastModified();	    }	} catch (Exception ex) {	    File file = new File(ruleurl);	    rulesStamp = file.lastModified();	}	System.out.println("rulesStamp : "+rulesStamp);	return (lastParsingTime < rulesStamp);    }    /**     * Filter requests before they are emitted.     * Look for a matching rule, and if found apply it before continuing     * the process. If a forbid rule was apply, this method will return     * with a <em>forbidden</em> message.     * @param request The request to filter.     * @return A Reply instance, if processing is not to be continued,     * <strong>false</strong>otherwise.     */    public Reply ingoingFilter(Request request) {	if (needsParsing())	    parseRules();	if ( rules != null ) {	    URL    url  = request.getURL();	    String host = url.getHost();	    Rule   rule = rules.lookupRule(host);	    if ( rule != null ) {		if ( debug ) {		    String args = rule.getRuleArgs();		    if (args == null) {			args = "";		    } else {			args = " "+args;		    }		    System.out.println("["+ getClass().getName() +				       "]: applying rule <"+rule.getRuleName()+				       args +"> to " + request.getURL());		}		return rule.apply(request);	    }	}	return null;    }    /**     * Filter requests when an error occurs during the process.     * This filter tries to do a direct connection if it is needed     * @param reques The request to filter.     * @param reply It's associated reply.     * @return Always <strong>null</strong>.     */    public boolean exceptionFilter(Request request, HttpException ex) {	// if it was a proxy connection, try a direct one	// add test for exception here	if(request.hasProxy()) {	    Reply reply       = null;	    HttpManager hm    = HttpManager.getManager();	    request.setProxy(null);	    if ( debug )		System.out.println("["+getClass().getName()+"]: direct fetch "				   +"for " + request.getURL());	    return true;	}	return false;    }    /**     * Filter requests after processing.     * This filter doesn't do any post-processing.     * @param reques The request to filter.     * @param reply It's associated reply.     * @return Always <strong>null</strong>.     */    public Reply outgoingFilter(Request request, Reply reply) {	return null;    }   /**     * PropertyMonitoring implementation - Commit property changes.     * @param name The name of the property that has changed.     * @return A boolean <strong>true</strong> if change was commited,      * <strong>false</strong> otherwise.     */    public boolean propertyChanged(String name) {	if(name.equals(RULE_P)) {	    try {		parseRules();	    } catch (Exception ex) {		ex.printStackTrace();		return false;	    }	} else if (name.equals(DEBUG_P)) {	    debug = props.getBoolean(DEBUG_P, false);	} else if (name.equals(CHECK_RULES_LAST_MODIFIED_P)) {	    check_rules = props.getBoolean(CHECK_RULES_LAST_MODIFIED_P, false);	}	return true;    }    public void initialize(HttpManager manager) {	// Prepare empty entry list:	props = manager.getProperties();	props.registerObserver(this);	// Initialize from properties:	parseRules();	if (debug = props.getBoolean(DEBUG_P, false)) 	    System.out.println("["+getClass().getName()+": debuging on.");	check_rules = props.getBoolean(CHECK_RULES_LAST_MODIFIED_P, false);	// Install ourself	manager.setFilter(this);    }    /**     * We don't maintain cached infos.     */    public void sync() {    }    /**     * Empty constructor, for dynamic instantiation.     */    public ProxyDispatcher() {	super();    }}

⌨️ 快捷键说明

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