<commit_before>/*
    ***** BEGIN LICENSE BLOCK *****
    
    Copyright © 2009 Center for History and New Media
                     George Mason University, Fairfax, Virginia, USA
                     http://zotero.org
    
    This file is part of Zotero.
    
    Zotero is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.
    
    Zotero is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.
    
    You should have received a copy of the GNU Affero General Public License
    along with Zotero.  If not, see <http://www.gnu.org/licenses/>.
    
    ***** END LICENSE BLOCK *****
*/

/**
 * A singleton to handle URL rewriting proxies
 * @namespace
 * @property transparent {Boolean} Whether transparent proxy functionality is enabled
 * @property proxies {Zotero.Proxy[]} All loaded proxies
 * @property hosts {Zotero.Proxy{}} Object mapping hosts to proxies
 */
Zotero.Proxies = new function() {
	this.proxies = false;
	this.transparent = false;
	this.hosts = {};
	
	var ioService = Components.classes["@mozilla.org/network/io-service;1"]
							  .getService(Components.interfaces.nsIIOService);
	var windowMediator = Components.classes["@mozilla.org/appshell/window-mediator;1"]
							       .getService(Components.interfaces.nsIWindowMediator);
	var myHostName = null;
	var myCanonicalHostName = null;
	
	/**
	 * Initializes http-on-examine-response observer to intercept page loads and gets preferences
	 */
	this.init = function() {
		if(!this.proxies) {
			var me = this;
			Zotero.MIMETypeHandler.addObserver(function(ch) { me.observe(ch) });
			
			var rows = Zotero.DB.query("SELECT * FROM proxies");
			Zotero.Proxies.proxies = [new Zotero.Proxy(row) for each(row in rows)];
			
			for each(var proxy in Zotero.Proxies.proxies) {
				for each(var host in proxy.hosts) {
					Zotero.Proxies.hosts[host] = proxy;
				}
			}
		}
		
		Zotero.Proxies.transparent = !Zotero.isConnector && Zotero.Prefs.get("proxies.transparent");
		Zotero.Proxies.autoRecognize = Zotero.Proxies.transparent && Zotero.Prefs.get("proxies.autoRecognize");
		
		var disableByDomainPref = Zotero.Prefs.get("proxies.disableByDomain");
		Zotero.Proxies.disableByDomain = (Zotero.Proxies.transparent && disableByDomainPref ? Zotero.Prefs.get("proxies.disableByDomainString") : null);
		
		Zotero.Proxies.lastIPCheck = 0;
		Zotero.Proxies.lastIPs = "";
		Zotero.Proxies.disabledByDomain = false;
	}
	
	/**
	 * Observe method to capture page loads and determine if they're going through an EZProxy.
	 *
	 * @param {nsIChannel} channel
	 */
	this.observe = function(channel) {
		// try to detect a proxy
		channel.QueryInterface(Components.interfaces.nsIHttpChannel);
		var url = channel.URI.spec;

		// see if there is a proxy we already know
		var m = false;
		var proxy;
		for each(proxy in Zotero.Proxies.proxies) {
			if(proxy.proxyID && proxy.regexp && proxy.multiHost) {
				m = proxy.regexp.exec(url);
				if(m) break;
			}
		}
		
		if(m) {
			var host = m[proxy.parameters.indexOf("%h")+1];
			// add this host if we know a proxy
			if(proxy.autoAssociate							// if autoAssociate is on
				&& channel.responseStatus < 400				// and query was successful
				&& !Zotero.Proxies.hosts[host]				// and host is not saved
				&& proxy.hosts.indexOf(host) === -1
				&& !_isBlacklisted(host)					// and host is not blacklisted
			) {	
				proxy.hosts.push(host);
				proxy.save(true);
				
				var bw = _getBrowserAndWindow(channel.notificationCallbacks);
				if(!bw) return;
				_showNotification(bw,
					Zotero.getString('proxies.notification.associated.label', [host, channel.URI.hostPort]),
					"settings", function() { _prefsOpenCallback(bw[1]) });
			}
		} else {
			// otherwise, try to detect a proxy
			var proxy = false;
			for(var detectorName in Zotero.Proxies.Detectors) {
				var detector = Zotero.Proxies.Detectors[detectorName];
				try {
					proxy = detector(channel);
				} catch(e) {
					Zotero.logError(e);
				}
				
				if(!proxy) continue;
				Zotero.debug("Proxies: Detected "+detectorName+" proxy "+proxy.scheme+
					(proxy.multiHost ? " (multi-host)" : " for "+proxy.hosts[0]));
				
				var bw = _getBrowserAndWindow(channel.notificationCallbacks);
				if(!bw) return;
				
				var savedTransparent = false;
				if(Zotero.Proxies.autoRecognize) {
					// Ask to save only if automatic proxy recognition is on
					savedTransparent = _showNotification(bw,
						Zotero.getString('proxies.notification.recognized.label', [proxy.hosts[0], channel.URI.hostPort]),
						"enable", function() { _showDialog(proxy.hosts[0], channel.URI.hostPort, proxy) });
				}
				
				proxy.save();
				
				break;
			}
		}
		
		// try to get an applicable proxy
		var webNav = null;
		var docShell = null;
		try {
			webNav = channel.notificationCallbacks.QueryInterface(Components.interfaces.nsIWebNavigation);
			docShell = channel.notificationCallbacks.QueryInterface(Components.interfaces.nsIDocShell);
		} catch(e) {}
		
		if(!docShell.allowMetaRedirects) return;
		
		// check that proxy redirection is actually enabled<commit_msg>Don't try to detect a proxy on documents with no docShell/webNav<commit_after>/*
    ***** BEGIN LICENSE BLOCK *****
    
    Copyright © 2009 Center for History and New Media
                     George Mason University, Fairfax, Virginia, USA
                     http://zotero.org
    
    This file is part of Zotero.
    
    Zotero is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.
    
    Zotero is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.
    
    You should have received a copy of the GNU Affero General Public License
    along with Zotero.  If not, see <http://www.gnu.org/licenses/>.
    
    ***** END LICENSE BLOCK *****
*/

/**
 * A singleton to handle URL rewriting proxies
 * @namespace
 * @property transparent {Boolean} Whether transparent proxy functionality is enabled
 * @property proxies {Zotero.Proxy[]} All loaded proxies
 * @property hosts {Zotero.Proxy{}} Object mapping hosts to proxies
 */
Zotero.Proxies = new function() {
	this.proxies = false;
	this.transparent = false;
	this.hosts = {};
	
	var ioService = Components.classes["@mozilla.org/network/io-service;1"]
							  .getService(Components.interfaces.nsIIOService);
	var windowMediator = Components.classes["@mozilla.org/appshell/window-mediator;1"]
							       .getService(Components.interfaces.nsIWindowMediator);
	var myHostName = null;
	var myCanonicalHostName = null;
	
	/**
	 * Initializes http-on-examine-response observer to intercept page loads and gets preferences
	 */
	this.init = function() {
		if(!this.proxies) {
			var me = this;
			Zotero.MIMETypeHandler.addObserver(function(ch) { me.observe(ch) });
			
			var rows = Zotero.DB.query("SELECT * FROM proxies");
			Zotero.Proxies.proxies = [new Zotero.Proxy(row) for each(row in rows)];
			
			for each(var proxy in Zotero.Proxies.proxies) {
				for each(var host in proxy.hosts) {
					Zotero.Proxies.hosts[host] = proxy;
				}
			}
		}
		
		Zotero.Proxies.transparent = !Zotero.isConnector && Zotero.Prefs.get("proxies.transparent");
		Zotero.Proxies.autoRecognize = Zotero.Proxies.transparent && Zotero.Prefs.get("proxies.autoRecognize");
		
		var disableByDomainPref = Zotero.Prefs.get("proxies.disableByDomain");
		Zotero.Proxies.disableByDomain = (Zotero.Proxies.transparent && disableByDomainPref ? Zotero.Prefs.get("proxies.disableByDomainString") : null);
		
		Zotero.Proxies.lastIPCheck = 0;
		Zotero.Proxies.lastIPs = "";
		Zotero.Proxies.disabledByDomain = false;
	}
	
	/**
	 * Observe method to capture page loads and determine if they're going through an EZProxy.
	 *
	 * @param {nsIChannel} channel
	 */
	this.observe = function(channel) {
		// try to detect a proxy
		channel.QueryInterface(Components.interfaces.nsIHttpChannel);
		var url = channel.URI.spec;

		// see if there is a proxy we already know
		var m = false;
		var proxy;
		for each(proxy in Zotero.Proxies.proxies) {
			if(proxy.proxyID && proxy.regexp && proxy.multiHost) {
				m = proxy.regexp.exec(url);
				if(m) break;
			}
		}
		
		if(m) {
			var host = m[proxy.parameters.indexOf("%h")+1];
			// add this host if we know a proxy
			if(proxy.autoAssociate							// if autoAssociate is on
				&& channel.responseStatus < 400				// and query was successful
				&& !Zotero.Proxies.hosts[host]				// and host is not saved
				&& proxy.hosts.indexOf(host) === -1
				&& !_isBlacklisted(host)					// and host is not blacklisted
			) {	
				proxy.hosts.push(host);
				proxy.save(true);
				
				var bw = _getBrowserAndWindow(channel.notificationCallbacks);
				if(!bw) return;
				_showNotification(bw,
					Zotero.getString('proxies.notification.associated.label', [host, channel.URI.hostPort]),
					"settings", function() { _prefsOpenCallback(bw[1]) });
			}
		} else {
			// otherwise, try to detect a proxy
			var proxy = false;
			for(var detectorName in Zotero.Proxies.Detectors) {
				var detector = Zotero.Proxies.Detectors[detectorName];
				try {
					proxy = detector(channel);
				} catch(e) {
					Zotero.logError(e);
				}
				
				if(!proxy) continue;
				Zotero.debug("Proxies: Detected "+detectorName+" proxy "+proxy.scheme+
					(proxy.multiHost ? " (multi-host)" : " for "+proxy.hosts[0]));
				
				var bw = _getBrowserAndWindow(channel.notificationCallbacks);
				if(!bw) return;
				
				var savedTransparent = false;
				if(Zotero.Proxies.autoRecognize) {
					// Ask to save only if automatic proxy recognition is on
					savedTransparent = _showNotification(bw,
						Zotero.getString('proxies.notification.recognized.label', [proxy.hosts[0], channel.URI.hostPort]),
						"enable", function() { _showDialog(proxy.hosts[0], channel.URI.hostPort, proxy) });
				}
				
				proxy.save();
				
				break;
			}
		}
		
		// try to get an applicable proxy
		var webNav = null;
		var docShell = null;
		try {
			webNav = channel.notificationCallbacks.QueryInterface(Components.interfaces.nsIWebNavigation);
			docShell = channel.notificationCallbacks.QueryInterface(Components.interfaces.nsIDocShell);
		} catch(e) {
			return;
		}
		
		if(!docShell.allowMetaRedirects) return;
		
		// check that proxy redirection is actually enabled
{'fraction_non_alphanumeric': 0.11327157663028524, 'fraction_numerical': 0.003118407777675869, 'mean_word_length': 3.2411513029949437, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3294223', 'n_tokens_mistral': 4043, 'n_tokens_neox': 3396, 'n_words': 884}