Software: Apache/2.2.3 (CentOS). PHP/5.1.6 uname -a: Linux mx-ll-110-164-51-230.static.3bb.co.th 2.6.18-194.el5PAE #1 SMP Fri Apr 2 15:37:44 uid=48(apache) gid=48(apache) groups=48(apache) Safe-mode: OFF (not secure) /usr/lib/xulrunner-1.9/components/ drwxr-xr-x | |
| Viewing file: Select action/file-type: //@line 37 "/builddir/build/BUILD/xulrunner-1.9.0.18/mozilla/toolkit/components/url-classifier/src/nsUrlClassifierLib.js"
// We wastefully reload the same JS files across components. This puts all
// the common JS files used by safebrowsing and url-classifier into a
// single component.
const Cc = Components.classes;
const Ci = Components.interfaces;
const G_GDEBUG = false;
//@line 36 "/builddir/build/BUILD/xulrunner-1.9.0.18/mozilla/toolkit/components/url-classifier/content/moz/lang.js"
/**
* lang.js - Some missing JavaScript language features
*/
/**
* Partially applies a function to a particular "this object" and zero or
* more arguments. The result is a new function with some arguments of the first
* function pre-filled and the value of |this| "pre-specified".
*
* Remaining arguments specified at call-time are appended to the pre-
* specified ones.
*
* Usage:
* var barMethBound = BindToObject(myFunction, myObj, "arg1", "arg2");
* barMethBound("arg3", "arg4");
*
* @param fn {string} Reference to the function to be bound
*
* @param self {object} Specifies the object which |this| should point to
* when the function is run. If the value is null or undefined, it will default
* to the global object.
*
* @returns {function} A partially-applied form of the speficied function.
*/
function BindToObject(fn, self, opt_args) {
var boundargs = fn.boundArgs_ || [];
boundargs = boundargs.concat(Array.slice(arguments, 2, arguments.length));
if (fn.boundSelf_)
self = fn.boundSelf_;
if (fn.boundFn_)
fn = fn.boundFn_;
var newfn = function() {
// Combine the static args and the new args into one big array
var args = boundargs.concat(Array.slice(arguments));
return fn.apply(self, args);
}
newfn.boundArgs_ = boundargs;
newfn.boundSelf_ = self;
newfn.boundFn_ = fn;
return newfn;
}
/**
* Inherit the prototype methods from one constructor into another.
*
* Usage:
*
* function ParentClass(a, b) { }
* ParentClass.prototype.foo = function(a) { }
*
* function ChildClass(a, b, c) {
* ParentClass.call(this, a, b);
* }
*
* ChildClass.inherits(ParentClass);
*
* var child = new ChildClass("a", "b", "see");
* child.foo(); // works
*
* In addition, a superclass' implementation of a method can be invoked
* as follows:
*
* ChildClass.prototype.foo = function(a) {
* ChildClass.superClass_.foo.call(this, a);
* // other code
* };
*/
Function.prototype.inherits = function(parentCtor) {
var tempCtor = function(){};
tempCtor.prototype = parentCtor.prototype;
this.superClass_ = parentCtor.prototype;
this.prototype = new tempCtor();
}
//@line 36 "/builddir/build/BUILD/xulrunner-1.9.0.18/mozilla/toolkit/components/url-classifier/content/moz/preferences.js"
// Class for manipulating preferences. Aside from wrapping the pref
// service, useful functionality includes:
//
// - abstracting prefobserving so that you can observe preferences
// without implementing nsIObserver
//
// - getters that return a default value when the pref doesn't exist
// (instead of throwing)
//
// - get-and-set getters
//
// Example:
//
// var p = new PROT_Preferences();
// dump(p.getPref("some-true-pref")); // shows true
// dump(p.getPref("no-such-pref", true)); // shows true
// dump(p.getPref("no-such-pref", null)); // shows null
//
// function observe(prefThatChanged) {
// dump("Pref changed: " + prefThatChanged);
// };
//
// p.addObserver("somepref", observe);
// p.setPref("somepref", true); // dumps
// p.removeObserver("somepref", observe);
//
// TODO: should probably have the prefobserver pass in the new and old
// values
// TODO(tc): Maybe remove this class and just call natively since we're no
// longer an extension.
/**
* A class that wraps the preferences service.
*
* @param opt_startPoint A starting point on the prefs tree to resolve
* names passed to setPref and getPref.
*
* @param opt_useDefaultPranch Set to true to work against the default
* preferences tree instead of the profile one.
*
* @constructor
*/
function G_Preferences(opt_startPoint, opt_getDefaultBranch) {
this.debugZone = "prefs";
this.observers_ = {};
this.getDefaultBranch_ = !!opt_getDefaultBranch;
this.startPoint_ = opt_startPoint || null;
}
G_Preferences.setterMap_ = { "string": "setCharPref",
"boolean": "setBoolPref",
"number": "setIntPref" };
G_Preferences.getterMap_ = {};
G_Preferences.getterMap_[Ci.nsIPrefBranch.PREF_STRING] = "getCharPref";
G_Preferences.getterMap_[Ci.nsIPrefBranch.PREF_BOOL] = "getBoolPref";
G_Preferences.getterMap_[Ci.nsIPrefBranch.PREF_INT] = "getIntPref";
G_Preferences.prototype.__defineGetter__('prefs_', function() {
var prefs;
var prefSvc = Cc["@mozilla.org/preferences-service;1"]
.getService(Ci.nsIPrefService);
if (this.getDefaultBranch_) {
prefs = prefSvc.getDefaultBranch(this.startPoint_);
} else {
prefs = prefSvc.getBranch(this.startPoint_);
}
// QI to prefs in case we want to add observers
prefs.QueryInterface(Ci.nsIPrefBranchInternal);
return prefs;
});
/**
* Stores a key/value in a user preference. Valid types for val are string,
* boolean, and number. Complex values are not yet supported (but feel free to
* add them!).
*/
G_Preferences.prototype.setPref = function(key, val) {
var datatype = typeof(val);
if (datatype == "number" && (val % 1 != 0)) {
throw new Error("Cannot store non-integer numbers in preferences.");
}
var meth = G_Preferences.setterMap_[datatype];
if (!meth) {
throw new Error("Pref datatype {" + datatype + "} not supported.");
}
return this.prefs_[meth](key, val);
}
/**
* Retrieves a user preference. Valid types for the value are the same as for
* setPref. If the preference is not found, opt_default will be returned
* instead.
*/
G_Preferences.prototype.getPref = function(key, opt_default) {
var type = this.prefs_.getPrefType(key);
// zero means that the specified pref didn't exist
if (type == Ci.nsIPrefBranch.PREF_INVALID) {
return opt_default;
}
var meth = G_Preferences.getterMap_[type];
if (!meth) {
throw new Error("Pref datatype {" + type + "} not supported.");
}
// If a pref has been cleared, it will have a valid type but won't
// be gettable, so this will throw.
try {
return this.prefs_[meth](key);
} catch(e) {
return opt_default;
}
}
/**
* Delete a preference.
*
* @param which Name of preference to obliterate
*/
G_Preferences.prototype.clearPref = function(which) {
try {
// This throws if the pref doesn't exist, which is fine because a
// non-existent pref is cleared
this.prefs_.clearUserPref(which);
} catch(e) {}
}
/**
* Add an observer for a given pref.
*
* @param which String containing the pref to listen to
* @param callback Function to be called when the pref changes. This
* function will receive a single argument, a string
* holding the preference name that changed
*/
G_Preferences.prototype.addObserver = function(which, callback) {
// Need to store the observer we create so we can eventually unregister it
if (!this.observers_[which])
this.observers_[which] = { callbacks: [], observers: [] };
/* only add an observer if the callback hasn't been registered yet */
if (this.observers_[which].callbacks.indexOf(callback) == -1) {
var observer = new G_PreferenceObserver(callback);
this.observers_[which].callbacks.push(callback);
this.observers_[which].observers.push(observer);
this.prefs_.addObserver(which, observer, false /* strong reference */);
}
}
/**
* Remove an observer for a given pref.
*
* @param which String containing the pref to stop listening to
* @param callback Function to remove as an observer
*/
G_Preferences.prototype.removeObserver = function(which, callback) {
var ix = this.observers_[which].callbacks.indexOf(callback);
G_Assert(this, ix != -1, "Tried to unregister a nonexistant observer");
this.observers_[which].callbacks.splice(ix, 1);
var observer = this.observers_[which].observers.splice(ix, 1)[0];
this.prefs_.removeObserver(which, observer);
}
/**
* Remove all preference observers registered through this object.
*/
G_Preferences.prototype.removeAllObservers = function() {
for (var which in this.observers_) {
for each (var observer in this.observers_[which].observers) {
this.prefs_.removeObserver(which, observer);
}
}
this.observers_ = {};
}
/**
* Helper class that knows how to observe preference changes and
* invoke a callback when they do
*
* @constructor
* @param callback Function to call when the preference changes
*/
function G_PreferenceObserver(callback) {
this.debugZone = "prefobserver";
this.callback_ = callback;
}
/**
* Invoked by the pref system when a preference changes. Passes the
* message along to the callback.
*
* @param subject The nsIPrefBranch that changed
* @param topic String "nsPref:changed" (aka
* NS_PREFBRANCH_PREFCHANGE_OBSERVER_ID -- but where does it
* live???)
* @param data Name of the pref that changed
*/
G_PreferenceObserver.prototype.observe = function(subject, topic, data) {
G_Debug(this, "Observed pref change: " + data);
this.callback_(data);
}
/**
* XPCOM cruft
*
* @param iid Interface id of the interface the caller wants
*/
G_PreferenceObserver.prototype.QueryInterface = function(iid) {
if (iid.equals(Ci.nsISupports) ||
iid.equals(Ci.nsIObserver) ||
iid.equals(Ci.nsISupportsWeakReference))
return this;
throw Components.results.NS_ERROR_NO_INTERFACE;
}
//@line 38 "/builddir/build/BUILD/xulrunner-1.9.0.18/mozilla/toolkit/components/url-classifier/content/moz/debug.js"
//@line 868 "/builddir/build/BUILD/xulrunner-1.9.0.18/mozilla/toolkit/components/url-classifier/content/moz/debug.js"
// Stubs for the debugging aids scattered through this component.
// They will be expanded if you compile yourself a debug build.
function G_Debug(who, msg) { }
function G_Assert(who, condition, msg) { }
function G_Error(who, msg) { }
var G_debugService = { __noSuchMethod__: function() { } };
//@line 36 "/builddir/build/BUILD/xulrunner-1.9.0.18/mozilla/toolkit/components/url-classifier/content/moz/alarm.js"
// An Alarm fires a callback after a certain amount of time, or at
// regular intervals. It's a convenient replacement for
// setTimeout/Interval when you don't want to bind to a specific
// window.
//
// The ConditionalAlarm is an Alarm that cancels itself if its callback
// returns a value that type-converts to true.
//
// Example:
//
// function foo() { dump('hi'); };
// new G_Alarm(foo, 10*1000); // Fire foo in 10 seconds
// new G_Alarm(foo, 10*1000, true /*repeat*/); // Fire foo every 10 seconds
// new G_Alarm(foo, 10*1000, true, 7); // Fire foo every 10 seconds
// // seven times
// new G_ConditionalAlarm(foo, 1000, true); // Fire every sec until foo()==true
//
// // Fire foo every 10 seconds until foo returns true or until it fires seven
// // times, whichever happens first.
// new G_ConditionalAlarm(foo, 10*1000, true /*repeating*/, 7);
//
// TODO: maybe pass an isFinal flag to the callback if they opted to
// set maxTimes and this is the last iteration?
/**
* Set an alarm to fire after a given amount of time, or at specific
* intervals.
*
* @param callback Function to call when the alarm fires
* @param delayMS Number indicating the length of the alarm period in ms
* @param opt_repeating Boolean indicating whether this should fire
* periodically
* @param opt_maxTimes Number indicating a maximum number of times to
* repeat (obviously only useful when opt_repeating==true)
*/
function G_Alarm(callback, delayMS, opt_repeating, opt_maxTimes) {
this.debugZone = "alarm";
this.callback_ = callback;
this.repeating_ = !!opt_repeating;
this.timer_ = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
var type = opt_repeating ?
this.timer_.TYPE_REPEATING_SLACK :
this.timer_.TYPE_ONE_SHOT;
this.maxTimes_ = opt_maxTimes ? opt_maxTimes : null;
this.nTimes_ = 0;
this.observerServiceObserver_ = new G_ObserverServiceObserver(
'xpcom-shutdown',
BindToObject(this.cancel, this));
// Ask the timer to use nsITimerCallback (.notify()) when ready
this.timer_.initWithCallback(this, delayMS, type);
}
/**
* Cancel this timer
*/
G_Alarm.prototype.cancel = function() {
if (!this.timer_) {
return;
}
this.timer_.cancel();
// Break circular reference created between this.timer_ and the G_Alarm
// instance (this)
this.timer_ = null;
this.callback_ = null;
// We don't need the shutdown observer anymore
this.observerServiceObserver_.unregister();
}
/**
* Invoked by the timer when it fires
*
* @param timer Reference to the nsITimer which fired (not currently
* passed along)
*/
G_Alarm.prototype.notify = function(timer) {
// fire callback and save results
var ret = this.callback_();
// If they've given us a max number of times to fire, enforce it
this.nTimes_++;
if (this.repeating_ &&
typeof this.maxTimes_ == "number"
&& this.nTimes_ >= this.maxTimes_) {
this.cancel();
} else if (!this.repeating_) {
// Clear out the callback closure for TYPE_ONE_SHOT timers
this.cancel();
}
// We don't cancel/cleanup timers that repeat forever until either
// xpcom-shutdown occurs or cancel() is called explicitly.
return ret;
}
G_Alarm.prototype.setDelay = function(delay) {
this.timer_.delay = delay;
}
/**
* XPCOM cruft
*/
G_Alarm.prototype.QueryInterface = function(iid) {
if (iid.equals(Components.interfaces.nsISupports) ||
iid.equals(Components.interfaces.nsITimerCallback))
return this;
throw Components.results.NS_ERROR_NO_INTERFACE;
}
/**
* An alarm with the additional property that it cancels itself if its
* callback returns true.
*
* For parameter documentation, see G_Alarm
*/
function G_ConditionalAlarm(callback, delayMS, opt_repeating, opt_maxTimes) {
G_Alarm.call(this, callback, delayMS, opt_repeating, opt_maxTimes);
this.debugZone = "conditionalalarm";
}
G_ConditionalAlarm.inherits(G_Alarm);
/**
* Invoked by the timer when it fires
*
* @param timer Reference to the nsITimer which fired (not currently
* passed along)
*/
G_ConditionalAlarm.prototype.notify = function(timer) {
// Call G_Alarm::notify
var rv = G_Alarm.prototype.notify.call(this, timer);
if (this.repeating_ && rv) {
G_Debug(this, "Callback of a repeating alarm returned true; cancelling.");
this.cancel();
}
}
//@line 36 "/builddir/build/BUILD/xulrunner-1.9.0.18/mozilla/toolkit/components/url-classifier/content/moz/cryptohasher.js"
// A very thin wrapper around nsICryptoHash. It's not strictly
// necessary, but makes the code a bit cleaner and gives us the
// opportunity to verify that our implementations give the results that
// we expect, for example if we have to interoperate with a server.
//
// The digest* methods reset the state of the hasher, so it's
// necessary to call init() explicitly after them.
//
// Works only in Firefox 1.5+.
//
// IMPORTANT NOTE: Due to https://bugzilla.mozilla.org/show_bug.cgi?id=321024
// you cannot use the cryptohasher before app-startup. The symptom of doing
// so is a segfault in NSS.
/**
* Instantiate a new hasher. You must explicitly call init() before use!
*/
function G_CryptoHasher() {
this.debugZone = "cryptohasher";
this.hasher_ = null;
}
G_CryptoHasher.algorithms = {
MD2: Ci.nsICryptoHash.MD2,
MD5: Ci.nsICryptoHash.MD5,
SHA1: Ci.nsICryptoHash.SHA1,
SHA256: Ci.nsICryptoHash.SHA256,
SHA384: Ci.nsICryptoHash.SHA384,
SHA512: Ci.nsICryptoHash.SHA512,
};
/**
* Initialize the hasher. This function must be called after every call
* to one of the digest* methods.
*
* @param algorithm Constant from G_CryptoHasher.algorithms specifying the
* algorithm this hasher will use
*/
G_CryptoHasher.prototype.init = function(algorithm) {
var validAlgorithm = false;
for (var alg in G_CryptoHasher.algorithms)
if (algorithm == G_CryptoHasher.algorithms[alg])
validAlgorithm = true;
if (!validAlgorithm)
throw new Error("Invalid algorithm: " + algorithm);
this.hasher_ = Cc["@mozilla.org/security/hash;1"]
.createInstance(Ci.nsICryptoHash);
this.hasher_.init(algorithm);
}
/**
* Update the hash's internal state with input given in a string. Can be
* called multiple times for incrementeal hash updates.
*
* @param input String containing data to hash.
*/
G_CryptoHasher.prototype.updateFromString = function(input) {
if (!this.hasher_)
throw new Error("You must initialize the hasher first!");
var stream = Cc['@mozilla.org/io/string-input-stream;1']
.createInstance(Ci.nsIStringInputStream);
stream.setData(input, input.length);
this.updateFromStream(stream);
}
/**
* Update the hash's internal state with input given in an array. Can be
* called multiple times for incremental hash updates.
*
* @param input Array containing data to hash.
*/
G_CryptoHasher.prototype.updateFromArray = function(input) {
if (!this.hasher_)
throw new Error("You must initialize the hasher first!");
this.hasher_.update(input, input.length);
}
/**
* Update the hash's internal state with input given in a stream. Can be
* called multiple times from incremental hash updates.
*/
G_CryptoHasher.prototype.updateFromStream = function(stream) {
if (!this.hasher_)
throw new Error("You must initialize the hasher first!");
if (stream.available())
this.hasher_.updateFromStream(stream, stream.available());
}
/**
* @returns The hash value as a string (sequence of 8-bit values)
*/
G_CryptoHasher.prototype.digestRaw = function() {
var digest = this.hasher_.finish(false /* not b64 encoded */);
this.hasher_ = null;
return digest;
}
/**
* @returns The hash value as a base64-encoded string
*/
G_CryptoHasher.prototype.digestBase64 = function() {
var digest = this.hasher_.finish(true /* b64 encoded */);
this.hasher_ = null;
return digest;
}
/**
* @returns The hash value as a hex-encoded string
*/
G_CryptoHasher.prototype.digestHex = function() {
var raw = this.digestRaw();
return this.toHex_(raw);
}
/**
* Converts a sequence of values to a hex-encoded string. The input is a
* a string, so you can stick 16-bit values in each character.
*
* @param str String to conver to hex. (Often this is just a sequence of
* 16-bit values)
*
* @returns String containing the hex representation of the input
*/
G_CryptoHasher.prototype.toHex_ = function(str) {
var hexchars = '0123456789ABCDEF';
var hexrep = new Array(str.length * 2);
for (var i = 0; i < str.length; ++i) {
hexrep[i * 2] = hexchars.charAt((str.charCodeAt(i) >> 4) & 15);
hexrep[i * 2 + 1] = hexchars.charAt(str.charCodeAt(i) & 15);
}
return hexrep.join('');
}
//@line 36 "/builddir/build/BUILD/xulrunner-1.9.0.18/mozilla/toolkit/components/url-classifier/content/moz/observer.js"
// A couple of classes to simplify creating observers.
//
// // Example1:
//
// function doSomething() { ... }
// var observer = new G_ObserverWrapper(topic, doSomething);
// someObj.addObserver(topic, observer);
//
// // Example2:
//
// function doSomething() { ... }
// new G_ObserverServiceObserver("profile-after-change",
// doSomething,
// true /* run only once */);
/**
* This class abstracts the admittedly simple boilerplate required of
* an nsIObserver. It saves you the trouble of implementing the
* indirection of your own observe() function.
*
* @param topic String containing the topic the observer will filter for
*
* @param observeFunction Reference to the function to call when the
* observer fires
*
* @constructor
*/
function G_ObserverWrapper(topic, observeFunction) {
this.debugZone = "observer";
this.topic_ = topic;
this.observeFunction_ = observeFunction;
}
/**
* XPCOM
*/
G_ObserverWrapper.prototype.QueryInterface = function(iid) {
if (iid.equals(Ci.nsISupports) || iid.equals(Ci.nsIObserver))
return this;
throw Components.results.NS_ERROR_NO_INTERFACE;
}
/**
* Invoked by the thingy being observed
*/
G_ObserverWrapper.prototype.observe = function(subject, topic, data) {
if (topic == this.topic_)
this.observeFunction_(subject, topic, data);
}
/**
* This class abstracts the admittedly simple boilerplate required of
* observing an observerservice topic. It implements the indirection
* required, and automatically registers to hear the topic.
*
* @param topic String containing the topic the observer will filter for
*
* @param observeFunction Reference to the function to call when the
* observer fires
*
* @param opt_onlyOnce Boolean indicating if the observer should unregister
* after it has fired
*
* @constructor
*/
function G_ObserverServiceObserver(topic, observeFunction, opt_onlyOnce) {
this.debugZone = "observerserviceobserver";
this.topic_ = topic;
this.observeFunction_ = observeFunction;
this.onlyOnce_ = !!opt_onlyOnce;
this.observer_ = new G_ObserverWrapper(this.topic_,
BindToObject(this.observe_, this));
this.observerService_ = Cc["@mozilla.org/observer-service;1"]
.getService(Ci.nsIObserverService);
this.observerService_.addObserver(this.observer_, this.topic_, false);
}
/**
* Unregister the observer from the observerservice
*/
G_ObserverServiceObserver.prototype.unregister = function() {
this.observerService_.removeObserver(this.observer_, this.topic_);
this.observerService_ = null;
}
/**
* Invoked by the observerservice
*/
G_ObserverServiceObserver.prototype.observe_ = function(subject, topic, data) {
this.observeFunction_(subject, topic, data);
if (this.onlyOnce_)
this.unregister();
}
//@line 36 "/builddir/build/BUILD/xulrunner-1.9.0.18/mozilla/toolkit/components/url-classifier/content/moz/protocol4.js"
// A helper class that knows how to parse from and serialize to
// protocol4. This is a simple, historical format used by some Google
// interfaces, for example the Toolbar (i.e., ancient services).
//
// Protocol4 consists of a newline-separated sequence of name/value
// pairs (strings). Each line consists of the name, the value length,
// and the value itself, all separated by colons. Example:
//
// foo:6:barbaz\n
// fritz:33:issickofdynamicallytypedlanguages\n
/**
* This class knows how to serialize/deserialize maps to/from their
* protocol4 representation.
*
* @constructor
*/
function G_Protocol4Parser() {
this.debugZone = "protocol4";
this.protocol4RegExp_ = new RegExp("([^:]+):\\d+:(.*)$");
this.newlineRegExp_ = new RegExp("(\\r)?\\n");
}
/**
* Create a map from a protocol4 string. Silently skips invalid lines.
*
* @param text String holding the protocol4 representation
*
* @returns Object as an associative array with keys and values
* given in text. The empty object is returned if none
* are parsed.
*/
G_Protocol4Parser.prototype.parse = function(text) {
var response = {};
if (!text)
return response;
// Responses are protocol4: (repeated) name:numcontentbytes:content\n
var lines = text.split(this.newlineRegExp_);
for (var i = 0; i < lines.length; i++)
if (this.protocol4RegExp_.exec(lines[i]))
response[RegExp.$1] = RegExp.$2;
return response;
}
/**
* Create a protocol4 string from a map (object). Throws an error on
* an invalid input.
*
* @param map Object as an associative array with keys and values
* given as strings.
*
* @returns text String holding the protocol4 representation
*/
G_Protocol4Parser.prototype.serialize = function(map) {
if (typeof map != "object")
throw new Error("map must be an object");
var text = "";
for (var key in map) {
if (typeof map[key] != "string")
throw new Error("Keys and values must be strings");
text += key + ":" + map[key].length + ":" + map[key] + "\n";
}
return text;
}
//@line 53 "/builddir/build/BUILD/xulrunner-1.9.0.18/mozilla/toolkit/components/url-classifier/src/nsUrlClassifierLib.js"
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Google Safe Browsing.
*
* The Initial Developer of the Original Code is Google Inc.
* Portions created by the Initial Developer are Copyright (C) 2006
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Tony Chang <tc@google.com> (original author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
// This implements logic for stopping requests if the server starts to return
// too many errors. If we get MAX_ERRORS errors in ERROR_PERIOD minutes, we
// back off for TIMEOUT_INCREMENT minutes. If we get another error
// immediately after we restart, we double the timeout and add
// TIMEOUT_INCREMENT minutes, etc.
//
// This is similar to the logic used by the search suggestion service.
// HTTP responses that count as an error. We also include any 5xx response
// as an error.
const HTTP_FOUND = 302;
const HTTP_SEE_OTHER = 303;
const HTTP_TEMPORARY_REDIRECT = 307;
/**
* @param maxErrors Number of times to request before backing off.
* @param retryIncrement Time (ms) for each retry before backing off.
* @param maxRequests Number the number of requests needed to trigger backoff
* @param requestPeriod Number time (ms) in which maxRequests have to occur to
* trigger the backoff behavior
* @param timeoutIncrement Number time (ms) the starting timeout period
* we double this time for consecutive errors
* @param maxTimeout Number time (ms) maximum timeout period
*/
function RequestBackoff(maxErrors, retryIncrement,
maxRequests, requestPeriod,
timeoutIncrement, maxTimeout) {
this.MAX_ERRORS_ = maxErrors;
this.RETRY_INCREMENT_ = retryIncrement;
this.MAX_REQUESTS_ = maxRequests;
this.REQUEST_PERIOD_ = requestPeriod;
this.TIMEOUT_INCREMENT_ = timeoutIncrement;
this.MAX_TIMEOUT_ = maxTimeout;
// Queue of ints keeping the time of all requests
this.requestTimes_ = [];
this.numErrors_ = 0;
this.errorTimeout_ = 0;
this.nextRequestTime_ = 0;
}
/**
* Reset the object for reuse.
*/
RequestBackoff.prototype.reset = function() {
this.numErrors_ = 0;
this.errorTimeout_ = 0;
this.nextRequestTime_ = 0;
}
/**
* Check to see if we can make a request.
*/
RequestBackoff.prototype.canMakeRequest = function() {
var now = Date.now();
if (now < this.nextRequestTime_) {
return false;
}
return (this.requestTimes_.length < this.MAX_REQUESTS_ ||
(now - this.requestTimes_[0]) > this.REQUEST_PERIOD_);
}
RequestBackoff.prototype.noteRequest = function() {
var now = Date.now();
this.requestTimes_.push(now);
// We only care about keeping track of MAX_REQUESTS
if (this.requestTimes_.length > this.MAX_REQUESTS_)
this.requestTimes_.shift();
}
RequestBackoff.prototype.nextRequestDelay = function() {
return Math.max(0, this.nextRequestTime_ - Date.now());
}
/**
* Notify this object of the last server response. If it's an error,
*/
RequestBackoff.prototype.noteServerResponse = function(status) {
if (this.isErrorStatus(status)) {
this.numErrors_++;
if (this.numErrors_ < this.MAX_ERRORS_)
this.errorTimeout_ = this.RETRY_INCREMENT_;
else if (this.numErrors_ == this.MAX_ERRORS_)
this.errorTimeout_ = this.TIMEOUT_INCREMENT_;
else
this.errorTimeout_ *= 2;
this.errorTimeout_ = Math.min(this.errorTimeout_, this.MAX_TIMEOUT_);
this.nextRequestTime_ = Date.now() + this.errorTimeout_;
} else {
// Reset error timeout, allow requests to go through.
this.reset();
}
}
/**
* We consider 302, 303, 307, 4xx, and 5xx http responses to be errors.
* @param status Number http status
* @return Boolean true if we consider this http status an error
*/
RequestBackoff.prototype.isErrorStatus = function(status) {
return ((400 <= status && status <= 599) ||
HTTP_FOUND == status ||
HTTP_SEE_OTHER == status ||
HTTP_TEMPORARY_REDIRECT == status);
}
//@line 36 "/builddir/build/BUILD/xulrunner-1.9.0.18/mozilla/toolkit/components/url-classifier/content/url-crypto-key-manager.js"
// This file implements the tricky business of managing the keys for our
// URL encryption. The protocol is:
//
// - Server generates secret key K_S
// - Client starts up and requests a new key K_C from the server via HTTPS
// - Server generates K_C and WrappedKey, which is K_C encrypted with K_S
// - Server resonse with K_C and WrappedKey
// - When client wants to encrypt a URL, it encrypts it with K_C and sends
// the encrypted URL along with WrappedKey
// - Server decrypts WrappedKey with K_S to get K_C, and the URL with K_C
//
// This is, however, trickier than it sounds for two reasons. First,
// we want to keep the number of HTTPS requests to an aboslute minimum
// (like 1 or 2 per browser session). Second, the HTTPS request at
// startup might fail, for example the user might be offline or a URL
// fetch might need to be issued before the HTTPS request has
// completed.
//
// We implement the following policy:
//
// - Firefox will issue at most two HTTPS getkey requests per session
// - Firefox will issue one HTTPS getkey request at startup if more than 24
// hours has passed since the last getkey request.
// - Firefox will serialize to disk any key it gets
// - Firefox will fall back on this serialized key until it has a
// fresh key
// - The front-end can respond with a flag in a lookup request that tells
// the client to re-key. Firefox will issue a new HTTPS getkey request
// at this time if it has only issued one before
// We store the user key in this file. The key can be used to verify signed
// server updates.
const kKeyFilename = "urlclassifierkey3.txt";
/**
* A key manager for UrlCrypto. There should be exactly one of these
* per appplication, and all UrlCrypto's should share it. This is
* currently implemented by having the manager attach itself to the
* UrlCrypto's prototype at startup. We could've opted for a global
* instead, but I like this better, even though it is spooky action
* at a distance.
* XXX: Should be an XPCOM service
*
* @param opt_keyFilename String containing the name of the
* file we should serialize keys to/from. Used
* mostly for testing.
*
* @param opt_testing Boolean indicating whether we are testing. If we
* are, then we skip trying to read the old key from
* file and automatically trying to rekey; presumably
* the tester will drive these manually.
*
* @constructor
*/
function PROT_UrlCryptoKeyManager(opt_keyFilename, opt_testing) {
this.debugZone = "urlcryptokeymanager";
this.testing_ = !!opt_testing;
this.clientKey_ = null; // Base64-encoded, as fetched from server
this.clientKeyArray_ = null; // Base64-decoded into an array of numbers
this.wrappedKey_ = null; // Opaque websafe base64-encoded server key
this.rekeyTries_ = 0;
this.updating_ = false;
// Don't do anything until keyUrl_ is set.
this.keyUrl_ = null;
this.keyFilename_ = opt_keyFilename ?
opt_keyFilename : kKeyFilename;
this.onNewKey_ = null;
// Convenience properties
this.MAX_REKEY_TRIES = PROT_UrlCryptoKeyManager.MAX_REKEY_TRIES;
this.CLIENT_KEY_NAME = PROT_UrlCryptoKeyManager.CLIENT_KEY_NAME;
this.WRAPPED_KEY_NAME = PROT_UrlCryptoKeyManager.WRAPPED_KEY_NAME;
if (!this.testing_) {
this.maybeLoadOldKey();
}
}
// Do ***** NOT ***** set this higher; HTTPS is expensive
PROT_UrlCryptoKeyManager.MAX_REKEY_TRIES = 2;
// Base pref for keeping track of when we updated our key.
// We store the time as seconds since the epoch.
PROT_UrlCryptoKeyManager.NEXT_REKEY_PREF = "urlclassifier.keyupdatetime.";
// Once every 30 days (interval in seconds)
PROT_UrlCryptoKeyManager.KEY_MIN_UPDATE_TIME = 30 * 24 * 60 * 60;
// These are the names the server will respond with in protocol4 format
PROT_UrlCryptoKeyManager.CLIENT_KEY_NAME = "clientkey";
PROT_UrlCryptoKeyManager.WRAPPED_KEY_NAME = "wrappedkey";
/**
* Called to get ClientKey
* @returns urlsafe-base64-encoded client key or null if we haven't gotten one.
*/
PROT_UrlCryptoKeyManager.prototype.getClientKey = function() {
return this.clientKey_;
}
/**
* Called by a UrlCrypto to get the current K_C
*
* @returns Array of numbers making up the client key or null if we
* have no key
*/
PROT_UrlCryptoKeyManager.prototype.getClientKeyArray = function() {
return this.clientKeyArray_;
}
/**
* Called by a UrlCrypto to get WrappedKey
*
* @returns Opaque base64-encoded WrappedKey or null if we haven't
* gotten one
*/
PROT_UrlCryptoKeyManager.prototype.getWrappedKey = function() {
return this.wrappedKey_;
}
/**
* Change the key url. When we do this, we go ahead and rekey.
* @param keyUrl String
*/
PROT_UrlCryptoKeyManager.prototype.setKeyUrl = function(keyUrl) {
// If it's the same key url, do nothing.
if (keyUrl == this.keyUrl_)
return;
this.keyUrl_ = keyUrl;
this.rekeyTries_ = 0;
// Check to see if we should make a new getkey request.
var prefs = new G_Preferences(PROT_UrlCryptoKeyManager.NEXT_REKEY_PREF);
var nextRekey = prefs.getPref(this.getPrefName_(this.keyUrl_), 0);
if (nextRekey < parseInt(Date.now() / 1000, 10)) {
this.reKey();
}
}
/**
* Given a url, return the pref value to use (pref contains last update time).
* We basically use the url up until query parameters. This avoids duplicate
* pref entries as version number changes over time.
* @param url String getkey URL
*/
PROT_UrlCryptoKeyManager.prototype.getPrefName_ = function(url) {
var queryParam = url.indexOf("?");
if (queryParam != -1) {
return url.substring(0, queryParam);
}
return url;
}
/**
* Tell the manager to re-key. For safety, this method still obeys the
* max-tries limit. Clients should generally use maybeReKey() if they
* want to try a re-keying: it's an error to call reKey() after we've
* hit max-tries, but not an error to call maybeReKey().
*/
PROT_UrlCryptoKeyManager.prototype.reKey = function() {
if (this.updating_) {
G_Debug(this, "Already re-keying, ignoring this request");
return true;
}
if (this.rekeyTries_ > this.MAX_REKEY_TRIES)
throw new Error("Have already rekeyed " + this.rekeyTries_ + " times");
this.rekeyTries_++;
G_Debug(this, "Attempting to re-key");
// If the keyUrl isn't set, we don't do anything.
if (!this.testing_ && this.keyUrl_) {
(new PROT_XMLFetcher()).get(this.keyUrl_,
BindToObject(this.onGetKeyResponse, this));
this.updating_ = true;
// Calculate the next time we're allowed to re-key.
var prefs = new G_Preferences(PROT_UrlCryptoKeyManager.NEXT_REKEY_PREF);
var nextRekey = parseInt(Date.now() / 1000, 10)
+ PROT_UrlCryptoKeyManager.KEY_MIN_UPDATE_TIME;
prefs.setPref(this.getPrefName_(this.keyUrl_), nextRekey);
}
}
/**
* Try to re-key if we haven't already hit our limit. It's OK to call
* this method multiple times, even if we've already tried to rekey
* more than the max. It will simply refuse to do so.
*
* @returns Boolean indicating if it actually issued a rekey request (that
* is, if we haven' already hit the max)
*/
PROT_UrlCryptoKeyManager.prototype.maybeReKey = function() {
if (this.rekeyTries_ > this.MAX_REKEY_TRIES) {
G_Debug(this, "Not re-keying; already at max");
return false;
}
this.reKey();
return true;
}
/**
* Drop the existing set of keys. Resets the rekeyTries variable to
* allow a rekey to succeed.
*/
PROT_UrlCryptoKeyManager.prototype.dropKey = function() {
this.rekeyTries_ = 0;
this.replaceKey_(null, null);
}
/**
* @returns Boolean indicating if we have a key we can use
*/
PROT_UrlCryptoKeyManager.prototype.hasKey = function() {
return this.clientKey_ != null && this.wrappedKey_ != null;
}
PROT_UrlCryptoKeyManager.prototype.unUrlSafe = function(key)
{
return key.replace("-", "+").replace("_", "/");
}
/**
* Set a new key and serialize it to disk.
*
* @param clientKey String containing the base64-encoded client key
* we wish to use
*
* @param wrappedKey String containing the opaque base64-encoded WrappedKey
* the server gave us (i.e., K_C encrypted with K_S)
*/
PROT_UrlCryptoKeyManager.prototype.replaceKey_ = function(clientKey,
wrappedKey) {
if (this.clientKey_)
G_Debug(this, "Replacing " + this.clientKey_ + " with " + clientKey);
this.clientKey_ = clientKey;
this.clientKeyArray_ = Array.map(atob(this.unUrlSafe(clientKey)),
function(c) { return c.charCodeAt(0); });
this.wrappedKey_ = wrappedKey;
this.serializeKey_(this.clientKey_, this.wrappedKey_);
if (this.onNewKey_) {
this.onNewKey_();
}
}
/**
* Try to write the key to disk so we can fall back on it. Fail
* silently if we cannot. The keys are serialized in protocol4 format.
*
* @returns Boolean indicating whether we succeeded in serializing
*/
PROT_UrlCryptoKeyManager.prototype.serializeKey_ = function() {
var map = {};
map[this.CLIENT_KEY_NAME] = this.clientKey_;
map[this.WRAPPED_KEY_NAME] = this.wrappedKey_;
try {
var keyfile = Cc["@mozilla.org/file/directory_service;1"]
.getService(Ci.nsIProperties)
.get("ProfD", Ci.nsILocalFile); /* profile directory */
keyfile.append(this.keyFilename_);
if (!this.clientKey_ || !this.wrappedKey_) {
keyfile.remove(true);
return;
}
var data = (new G_Protocol4Parser()).serialize(map);
try {
var stream = Cc["@mozilla.org/network/file-output-stream;1"]
.createInstance(Ci.nsIFileOutputStream);
stream.init(keyfile,
0x02 | 0x08 | 0x20 /* PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE */,
-1 /* default perms */, 0 /* no special behavior */);
stream.write(data, data.length);
} finally {
stream.close();
}
return true;
} catch(e) {
G_Error(this, "Failed to serialize new key: " + e);
return false;
}
}
/**
* Invoked when we've received a protocol4 response to our getkey
* request. Try to parse it and set this key as the new one if we can.
*
* @param responseText String containing the protocol4 getkey response
*/
PROT_UrlCryptoKeyManager.prototype.onGetKeyResponse = function(responseText) {
var response = (new G_Protocol4Parser).parse(responseText);
var clientKey = response[this.CLIENT_KEY_NAME];
var wrappedKey = response[this.WRAPPED_KEY_NAME];
this.updating_ = false;
if (response && clientKey && wrappedKey) {
G_Debug(this, "Got new key from: " + responseText);
this.replaceKey_(clientKey, wrappedKey);
} else {
G_Debug(this, "Not a valid response for /newkey");
}
}
/**
* Set the callback to be called whenever we get a new key.
*
* @param callback The callback.
*/
PROT_UrlCryptoKeyManager.prototype.onNewKey = function(callback)
{
this.onNewKey_ = callback;
}
/**
* Attempt to read a key we've previously serialized from disk, so
* that we can fall back on it in case we can't get one from the
* server. If we get a key, only use it if we don't already have one
* (i.e., if our startup HTTPS request died or hasn't yet completed).
*
* This method should be invoked early, like when the user's profile
* becomes available.
*/
PROT_UrlCryptoKeyManager.prototype.maybeLoadOldKey = function() {
var oldKey = null;
try {
var keyfile = Cc["@mozilla.org/file/directory_service;1"]
.getService(Ci.nsIProperties)
.get("ProfD", Ci.nsILocalFile); /* profile directory */
keyfile.append(this.keyFilename_);
if (keyfile.exists()) {
try {
var fis = Cc["@mozilla.org/network/file-input-stream;1"]
.createInstance(Ci.nsIFileInputStream);
fis.init(keyfile, 0x01 /* PR_RDONLY */, 0444, 0);
var stream = Cc["@mozilla.org/scriptableinputstream;1"]
.createInstance(Ci.nsIScriptableInputStream);
stream.init(fis);
oldKey = stream.read(stream.available());
} finally {
if (stream)
stream.close();
}
}
} catch(e) {
G_Debug(this, "Caught " + e + " trying to read keyfile");
return;
}
if (!oldKey) {
G_Debug(this, "Couldn't find old key.");
return;
}
oldKey = (new G_Protocol4Parser).parse(oldKey);
var clientKey = oldKey[this.CLIENT_KEY_NAME];
var wrappedKey = oldKey[this.WRAPPED_KEY_NAME];
if (oldKey && clientKey && wrappedKey && !this.hasKey()) {
G_Debug(this, "Read old key from disk.");
this.replaceKey_(clientKey, wrappedKey);
}
}
//@line 36 "/builddir/build/BUILD/xulrunner-1.9.0.18/mozilla/toolkit/components/url-classifier/content/xml-fetcher.js"
// A simple class that encapsulates a request. You'll notice the
// style here is different from the rest of the extension; that's
// because this was re-used from really old code we had. At some
// point it might be nice to replace this with something better
// (e.g., something that has explicit onerror handler, ability
// to set headers, and so on).
//
// The only interesting thing here is its ability to strip cookies
// from the request.
/**
* Because we might be in a component, we can't just assume that
* XMLHttpRequest exists. So we use this tiny factory function to wrap the
* XPCOM version.
*
* @return XMLHttpRequest object
*/
function PROT_NewXMLHttpRequest() {
var Cc = Components.classes;
var Ci = Components.interfaces;
var request = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
.createInstance(Ci.nsIXMLHttpRequest);
// Need the following so we get onerror/load/progresschange
request.QueryInterface(Ci.nsIJSXMLHttpRequest);
return request;
}
/**
* A helper class that does HTTP GETs and calls back a function with
* the content it receives. Asynchronous, so uses a closure for the
* callback.
*
* @param opt_stripCookies Boolean indicating whether we should strip
* cookies from this request
*
* @constructor
*/
function PROT_XMLFetcher(opt_stripCookies) {
this.debugZone = "xmlfetcher";
this._request = PROT_NewXMLHttpRequest();
this._stripCookies = !!opt_stripCookies;
}
PROT_XMLFetcher.prototype = {
/**
* Function that will be called back upon fetch completion.
*/
_callback: null,
/**
* Fetches some content.
*
* @param page URL to fetch
* @param callback Function to call back when complete.
*/
get: function(page, callback) {
this._request.abort(); // abort() is asynchronous, so
this._request = PROT_NewXMLHttpRequest();
this._callback = callback;
var asynchronous = true;
this._request.open("GET", page, asynchronous);
this._request.channel.notificationCallbacks = this;
if (this._stripCookies)
new PROT_CookieStripper(this._request.channel);
// Create a closure
var self = this;
this._request.onreadystatechange = function() {
self.readyStateChange(self);
}
this._request.send(null);
},
/**
* Called periodically by the request to indicate some state change. 4
* means content has been received.
*/
readyStateChange: function(fetcher) {
if (fetcher._request.readyState != 4)
return;
// If the request fails, on trunk we get status set to
// NS_ERROR_NOT_AVAILABLE. On 1.8.1 branch we get an exception
// forwarded from nsIHttpChannel::GetResponseStatus. To be consistent
// between branch and trunk, we send back NS_ERROR_NOT_AVAILABLE for
// http failures.
var responseText = null;
var status = Components.results.NS_ERROR_NOT_AVAILABLE;
try {
G_Debug(this, "xml fetch status code: \"" +
fetcher._request.status + "\"");
status = fetcher._request.status;
responseText = fetcher._request.responseText;
} catch(e) {
G_Debug(this, "Caught exception trying to read xmlhttprequest " +
"status/response.");
G_Debug(this, e);
}
if (fetcher._callback)
fetcher._callback(responseText, status);
},
// Suppress any certificate errors
notifyCertProblem: function(socketInfo, status, targetSite) {
return true;
},
// Suppress any ssl errors
notifySSLError: function(socketInfo, error, targetSite) {
return true;
},
// nsIInterfaceRequestor
getInterface: function(iid) {
return this.QueryInterface(iid);
},
QueryInterface: function(iid) {
if (!iid.equals(Components.interfaces.nsIBadCertListener2) &&
!iid.equals(Components.interfaces.nsISSLErrorListener) &&
!iid.equals(Components.interfaces.nsIInterfaceRequestor) &&
!iid.equals(Components.interfaces.nsISupports))
throw Components.results.NS_ERROR_NO_INTERFACE;
return this;
}
};
/**
* This class knows how to strip cookies from an HTTP request. It
* listens for http-on-modify-request, and modifies the request
* accordingly. We can't do this using xmlhttprequest.setHeader() or
* nsIChannel.setRequestHeader() before send()ing because the cookie
* service is called after send().
*
* @param channel nsIChannel in which the request is happening
* @constructor
*/
function PROT_CookieStripper(channel) {
this.debugZone = "cookiestripper";
this.topic_ = "http-on-modify-request";
this.channel_ = channel;
var Cc = Components.classes;
var Ci = Components.interfaces;
this.observerService_ = Cc["@mozilla.org/observer-service;1"]
.getService(Ci.nsIObserverService);
this.observerService_.addObserver(this, this.topic_, false);
// If the request doesn't issue, don't hang around forever
var twentySeconds = 20 * 1000;
this.alarm_ = new G_Alarm(BindToObject(this.stopObserving, this),
twentySeconds);
}
/**
* Invoked by the observerservice. See nsIObserve.
*/
PROT_CookieStripper.prototype.observe = function(subject, topic, data) {
if (topic != this.topic_ || subject != this.channel_)
return;
G_Debug(this, "Stripping cookies for channel.");
this.channel_.QueryInterface(Components.interfaces.nsIHttpChannel);
this.channel_.setRequestHeader("Cookie", "", false /* replace, not add */);
this.alarm_.cancel();
this.stopObserving();
}
/**
* Remove us from the observerservice
*/
PROT_CookieStripper.prototype.stopObserving = function() {
G_Debug(this, "Removing observer");
this.observerService_.removeObserver(this, this.topic_);
this.channel_ = this.alarm_ = this.observerService_ = null;
}
/**
* XPCOM cruft
*/
PROT_CookieStripper.prototype.QueryInterface = function(iid) {
var Ci = Components.interfaces;
if (iid.equals(Ci.nsISupports) || iid.equals(Ci.nsIObserve))
return this;
throw Components.results.NS_ERROR_NO_INTERFACE;
}
//@line 57 "/builddir/build/BUILD/xulrunner-1.9.0.18/mozilla/toolkit/components/url-classifier/src/nsUrlClassifierLib.js"
// Expose this whole component.
var lib = this;
function UrlClassifierLib() {
this.wrappedJSObject = lib;
}
// Module object
function UrlClassifierLibMod() {
this.firstTime = true;
this.cid = Components.ID("{26a4a019-2827-4a89-a85c-5931a678823a}");
this.progid = "@mozilla.org/url-classifier/jslib;1";
}
UrlClassifierLibMod.prototype.registerSelf = function(compMgr, fileSpec, loc, type) {
if (this.firstTime) {
this.firstTime = false;
throw Components.results.NS_ERROR_FACTORY_REGISTER_AGAIN;
}
compMgr = compMgr.QueryInterface(Ci.nsIComponentRegistrar);
compMgr.registerFactoryLocation(this.cid,
"UrlClassifier JS Lib",
this.progid,
fileSpec,
loc,
type);
};
UrlClassifierLibMod.prototype.getClassObject = function(compMgr, cid, iid) {
if (!cid.equals(this.cid))
throw Components.results.NS_ERROR_NO_INTERFACE;
if (!iid.equals(Ci.nsIFactory))
throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
return this.factory;
}
UrlClassifierLibMod.prototype.canUnload = function(compMgr) {
return true;
}
UrlClassifierLibMod.prototype.factory = {
createInstance: function(outer, iid) {
if (outer != null)
throw Components.results.NS_ERROR_NO_AGGREGATION;
return new UrlClassifierLib();
}
};
var LibModInst = new UrlClassifierLibMod();
function NSGetModule(compMgr, fileSpec) {
return LibModInst;
}
|
:: Command execute :: | |
:: Shadow's tricks :D :: | |
Useful Commands
|
|
:: Preddy's tricks :D :: | |
Php Safe-Mode Bypass (Read Files)
|
|
--[ c999shell v. 1.0 pre-release build #16 Modded by Shadow & Preddy | RootShell Security Group | r57 c99 shell | Generation time: 0.0075 ]-- |