summaryrefslogtreecommitdiff
path: root/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/url_handler
diff options
context:
space:
mode:
Diffstat (limited to 'data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/url_handler')
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/url_handler/node_punycode.js219
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/url_handler/node_querystring.js187
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/url_handler/node_url.js611
-rw-r--r--data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/url_handler/url_handler.js120
4 files changed, 1137 insertions, 0 deletions
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/url_handler/node_punycode.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/url_handler/node_punycode.js
new file mode 100644
index 0000000..64d8c61
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/url_handler/node_punycode.js
@@ -0,0 +1,219 @@
+// Copyright (C) 2011 by Ben Noordhuis <info@bnoordhuis.nl>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+exports.encode = encode;
+exports.decode = decode;
+
+var TMIN = 1;
+var TMAX = 26;
+var BASE = 36;
+var SKEW = 38;
+var DAMP = 700; // initial bias scaler
+var INITIAL_N = 128;
+var INITIAL_BIAS = 72;
+var MAX_INTEGER = Math.pow(2, 53);
+
+function adapt_bias(delta, n_points, is_first) {
+ // scale back, then increase delta
+ delta /= is_first ? DAMP : 2;
+ delta += ~~(delta / n_points);
+
+ var s = (BASE - TMIN);
+ var t = ~~((s * TMAX) / 2); // threshold=455
+
+ for (var k = 0; delta > t; k += BASE) {
+ delta = ~~(delta / s);
+ }
+
+ var a = (BASE - TMIN + 1) * delta;
+ var b = (delta + SKEW);
+
+ return k + ~~(a / b);
+}
+
+function next_smallest_codepoint(codepoints, n) {
+ var m = 0x110000; // unicode upper bound + 1
+
+ for (var i = 0, len = codepoints.length; i < len; ++i) {
+ var c = codepoints[i];
+ if (c >= n && c < m) {
+ m = c;
+ }
+ }
+
+ // sanity check - should not happen
+ if (m >= 0x110000) {
+ throw new Error('Next smallest code point not found.');
+ }
+
+ return m;
+}
+
+function encode_digit(d) {
+ return d + (d < 26 ? 97 : 22);
+}
+
+function decode_digit(d) {
+ if (d >= 48 && d <= 57) {
+ return d - 22; // 0..9
+ }
+ if (d >= 65 && d <= 90) {
+ return d - 65; // A..Z
+ }
+ if (d >= 97 && d <= 122) {
+ return d - 97; // a..z
+ }
+ throw new Error('Illegal digit #' + d);
+}
+
+function threshold(k, bias) {
+ if (k <= bias + TMIN) {
+ return TMIN;
+ }
+ if (k >= bias + TMAX) {
+ return TMAX;
+ }
+ return k - bias;
+}
+
+function encode_int(bias, delta) {
+ var result = [];
+
+ for (var k = BASE, q = delta;; k += BASE) {
+ var t = threshold(k, bias);
+ if (q < t) {
+ result.push(encode_digit(q));
+ break;
+ }
+ else {
+ result.push(encode_digit(t + ((q - t) % (BASE - t))));
+ q = ~~((q - t) / (BASE - t));
+ }
+ }
+
+ return result;
+}
+
+function encode(input) {
+ if (typeof input != 'string') {
+ throw new Error('Argument must be a string.');
+ }
+
+ input = input.split('').map(function(c) {
+ return c.charCodeAt(0);
+ });
+
+ var output = [];
+ var non_basic = [];
+
+ for (var i = 0, len = input.length; i < len; ++i) {
+ var c = input[i];
+ if (c < 128) {
+ output.push(c);
+ }
+ else {
+ non_basic.push(c);
+ }
+ }
+
+ var b, h;
+ b = h = output.length;
+
+ if (b) {
+ output.push(45); // delimiter '-'
+ }
+
+ var n = INITIAL_N;
+ var bias = INITIAL_BIAS;
+ var delta = 0;
+
+ for (var len = input.length; h < len; ++n, ++delta) {
+ var m = next_smallest_codepoint(non_basic, n);
+ delta += (m - n) * (h + 1);
+ n = m;
+
+ for (var i = 0; i < len; ++i) {
+ var c = input[i];
+ if (c < n) {
+ if (++delta == MAX_INTEGER) {
+ throw new Error('Delta overflow.');
+ }
+ }
+ else if (c == n) {
+ // TODO append in-place?
+ // i.e. -> output.push.apply(output, encode_int(bias, delta));
+ output = output.concat(encode_int(bias, delta));
+ bias = adapt_bias(delta, h + 1, b == h);
+ delta = 0;
+ h++;
+ }
+ }
+ }
+
+ return String.fromCharCode.apply(String, output);
+}
+
+function decode(input) {
+ if (typeof input != 'string') {
+ throw new Error('Argument must be a string.');
+ }
+
+ // find basic code points/delta separator
+ var b = 1 + input.lastIndexOf('-');
+
+ input = input.split('').map(function(c) {
+ return c.charCodeAt(0);
+ });
+
+ // start with a copy of the basic code points
+ var output = input.slice(0, b ? (b - 1) : 0);
+
+ var n = INITIAL_N;
+ var bias = INITIAL_BIAS;
+
+ for (var i = 0, len = input.length; b < len; ++i) {
+ var org_i = i;
+
+ for (var k = BASE, w = 1;; k += BASE) {
+ var d = decode_digit(input[b++]);
+
+ // TODO overflow check
+ i += d * w;
+
+ var t = threshold(k, bias);
+ if (d < t) {
+ break;
+ }
+
+ // TODO overflow check
+ w *= BASE - t;
+ }
+
+ var x = 1 + output.length;
+ bias = adapt_bias(i - org_i, x, org_i == 0);
+ // TODO overflow check
+ n += ~~(i / x);
+ i %= x;
+
+ output.splice(i, 0, n);
+ }
+
+ return String.fromCharCode.apply(String, output);
+}
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/url_handler/node_querystring.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/url_handler/node_querystring.js
new file mode 100644
index 0000000..3314061
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/url_handler/node_querystring.js
@@ -0,0 +1,187 @@
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+// Query String Utilities
+
+var QueryString = exports;
+//var urlDecode = process.binding('http_parser').urlDecode;
+
+
+// If obj.hasOwnProperty has been overridden, then calling
+// obj.hasOwnProperty(prop) will break.
+// See: https://github.com/joyent/node/issues/1707
+function hasOwnProperty(obj, prop) {
+ return Object.prototype.hasOwnProperty.call(obj, prop);
+}
+
+
+function charCode(c) {
+ return c.charCodeAt(0);
+}
+
+
+// a safe fast alternative to decodeURIComponent
+QueryString.unescapeBuffer = function(s, decodeSpaces) {
+ var out = new Buffer(s.length);
+ var state = 'CHAR'; // states: CHAR, HEX0, HEX1
+ var n, m, hexchar;
+
+ for (var inIndex = 0, outIndex = 0; inIndex <= s.length; inIndex++) {
+ var c = s.charCodeAt(inIndex);
+ switch (state) {
+ case 'CHAR':
+ switch (c) {
+ case charCode('%'):
+ n = 0;
+ m = 0;
+ state = 'HEX0';
+ break;
+ case charCode('+'):
+ if (decodeSpaces) c = charCode(' ');
+ // pass thru
+ default:
+ out[outIndex++] = c;
+ break;
+ }
+ break;
+
+ case 'HEX0':
+ state = 'HEX1';
+ hexchar = c;
+ if (charCode('0') <= c && c <= charCode('9')) {
+ n = c - charCode('0');
+ } else if (charCode('a') <= c && c <= charCode('f')) {
+ n = c - charCode('a') + 10;
+ } else if (charCode('A') <= c && c <= charCode('F')) {
+ n = c - charCode('A') + 10;
+ } else {
+ out[outIndex++] = charCode('%');
+ out[outIndex++] = c;
+ state = 'CHAR';
+ break;
+ }
+ break;
+
+ case 'HEX1':
+ state = 'CHAR';
+ if (charCode('0') <= c && c <= charCode('9')) {
+ m = c - charCode('0');
+ } else if (charCode('a') <= c && c <= charCode('f')) {
+ m = c - charCode('a') + 10;
+ } else if (charCode('A') <= c && c <= charCode('F')) {
+ m = c - charCode('A') + 10;
+ } else {
+ out[outIndex++] = charCode('%');
+ out[outIndex++] = hexchar;
+ out[outIndex++] = c;
+ break;
+ }
+ out[outIndex++] = 16 * n + m;
+ break;
+ }
+ }
+
+ // TODO support returning arbitrary buffers.
+
+ return out.slice(0, outIndex - 1);
+};
+
+
+QueryString.unescape = function(s, decodeSpaces) {
+ return QueryString.unescapeBuffer(s, decodeSpaces).toString();
+};
+
+
+QueryString.escape = function(str) {
+ return encodeURIComponent(str);
+};
+
+var stringifyPrimitive = function(v) {
+ switch (typeof v) {
+ case 'string':
+ return v;
+
+ case 'boolean':
+ return v ? 'true' : 'false';
+
+ case 'number':
+ return isFinite(v) ? v : '';
+
+ default:
+ return '';
+ }
+};
+
+
+QueryString.stringify = QueryString.encode = function(obj, sep, eq, name) {
+ sep = sep || '&';
+ eq = eq || '=';
+ obj = (obj === null) ? undefined : obj;
+
+ switch (typeof obj) {
+ case 'object':
+ return Object.keys(obj).map(function(k) {
+ if (Array.isArray(obj[k])) {
+ return obj[k].map(function(v) {
+ return QueryString.escape(stringifyPrimitive(k)) +
+ eq +
+ QueryString.escape(stringifyPrimitive(v));
+ }).join(sep);
+ } else {
+ return QueryString.escape(stringifyPrimitive(k)) +
+ eq +
+ QueryString.escape(stringifyPrimitive(obj[k]));
+ }
+ }).join(sep);
+
+ default:
+ if (!name) return '';
+ return QueryString.escape(stringifyPrimitive(name)) + eq +
+ QueryString.escape(stringifyPrimitive(obj));
+ }
+};
+
+// Parse a key=val string.
+QueryString.parse = QueryString.decode = function(qs, sep, eq) {
+ sep = sep || '&';
+ eq = eq || '=';
+ var obj = {};
+
+ if (typeof qs !== 'string' || qs.length === 0) {
+ return obj;
+ }
+
+ qs.split(sep).forEach(function(kvp) {
+ var x = kvp.split(eq);
+ var k = QueryString.unescape(x[0], true);
+ var v = QueryString.unescape(x.slice(1).join(eq), true);
+
+ if (!hasOwnProperty(obj, k)) {
+ obj[k] = v;
+ } else if (!Array.isArray(obj[k])) {
+ obj[k] = [obj[k], v];
+ } else {
+ obj[k].push(v);
+ }
+ });
+
+ return obj;
+};
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/url_handler/node_url.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/url_handler/node_url.js
new file mode 100644
index 0000000..6b4940f
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/url_handler/node_url.js
@@ -0,0 +1,611 @@
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+var punycode = require('url_handler/node_punycode');
+
+exports.parse = urlParse;
+exports.resolve = urlResolve;
+exports.resolveObject = urlResolveObject;
+exports.format = urlFormat;
+
+// Reference: RFC 3986, RFC 1808, RFC 2396
+
+// define these here so at least they only have to be
+// compiled once on the first module load.
+var protocolPattern = /^([a-z0-9.+-]+:)/i,
+ portPattern = /:[0-9]+$/,
+ // RFC 2396: characters reserved for delimiting URLs.
+ delims = ['<', '>', '"', '`', ' ', '\r', '\n', '\t'],
+ // RFC 2396: characters not allowed for various reasons.
+ unwise = ['{', '}', '|', '\\', '^', '~', '[', ']', '`'].concat(delims),
+ // Allowed by RFCs, but cause of XSS attacks. Always escape these.
+ autoEscape = ['\''],
+ // Characters that are never ever allowed in a hostname.
+ // Note that any invalid chars are also handled, but these
+ // are the ones that are *expected* to be seen, so we fast-path
+ // them.
+ nonHostChars = ['%', '/', '?', ';', '#']
+ .concat(unwise).concat(autoEscape),
+ nonAuthChars = ['/', '@', '?', '#'].concat(delims),
+ hostnameMaxLen = 255,
+ hostnamePartPattern = /^[a-zA-Z0-9][a-z0-9A-Z_-]{0,62}$/,
+ hostnamePartStart = /^([a-zA-Z0-9][a-z0-9A-Z_-]{0,62})(.*)$/,
+ // protocols that can allow "unsafe" and "unwise" chars.
+ unsafeProtocol = {
+ 'javascript': true,
+ 'javascript:': true
+ },
+ // protocols that never have a hostname.
+ hostlessProtocol = {
+ 'javascript': true,
+ 'javascript:': true
+ },
+ // protocols that always have a path component.
+ pathedProtocol = {
+ 'http': true,
+ 'https': true,
+ 'ftp': true,
+ 'gopher': true,
+ 'file': true,
+ 'http:': true,
+ 'ftp:': true,
+ 'gopher:': true,
+ 'file:': true
+ },
+ // protocols that always contain a // bit.
+ slashedProtocol = {
+ 'http': true,
+ 'https': true,
+ 'ftp': true,
+ 'gopher': true,
+ 'file': true,
+ 'http:': true,
+ 'https:': true,
+ 'ftp:': true,
+ 'gopher:': true,
+ 'file:': true
+ },
+ querystring = require('url_handler/node_querystring');
+
+function urlParse(url, parseQueryString, slashesDenoteHost) {
+ if (url && typeof(url) === 'object' && url.href) return url;
+
+ if (typeof url !== 'string') {
+ throw new TypeError("Parameter 'url' must be a string, not " + typeof url);
+ }
+
+ var out = {},
+ rest = url;
+ out.href = "";
+ // cut off any delimiters.
+ // This is to support parse stuff like "<http://foo.com>"
+ for (var i = 0, l = rest.length; i < l; i++) {
+ if (delims.indexOf(rest.charAt(i)) === -1) break;
+ }
+ if (i !== 0) rest = rest.substr(i);
+
+
+ var proto = protocolPattern.exec(rest);
+ if (proto) {
+ proto = proto[0];
+ var lowerProto = proto.toLowerCase();
+ out.protocol = lowerProto;
+ rest = rest.substr(proto.length);
+ }
+
+ // figure out if it's got a host
+ // user@server is *always* interpreted as a hostname, and url
+ // resolution will treat //foo/bar as host=foo,path=bar because that's
+ // how the browser resolves relative URLs.
+ if (slashesDenoteHost || proto || rest.match(/^\/\/[^@\/]+@[^@\/]+/)) {
+ var slashes = rest.substr(0, 2) === '//';
+ if (slashes && !(proto && hostlessProtocol[proto])) {
+ rest = rest.substr(2);
+ out.slashes = true;
+ }
+ }
+
+ if (!hostlessProtocol[proto] &&
+ (slashes || (proto && !slashedProtocol[proto]))) {
+ // there's a hostname.
+ // the first instance of /, ?, ;, or # ends the host.
+ // don't enforce full RFC correctness, just be unstupid about it.
+
+ // If there is an @ in the hostname, then non-host chars *are* allowed
+ // to the left of the first @ sign, unless some non-auth character
+ // comes *before* the @-sign.
+ // URLs are obnoxious.
+ var atSign = rest.indexOf('@');
+ if (atSign !== -1) {
+ // there *may be* an auth
+ var hasAuth = true;
+ for (var i = 0, l = nonAuthChars.length; i < l; i++) {
+ var index = rest.indexOf(nonAuthChars[i]);
+ if (index !== -1 && index < atSign) {
+ // not a valid auth. Something like http://foo.com/bar@baz/
+ hasAuth = false;
+ break;
+ }
+ }
+ if (hasAuth) {
+ // pluck off the auth portion.
+ out.auth = rest.substr(0, atSign);
+ rest = rest.substr(atSign + 1);
+ }
+ }
+
+ var firstNonHost = -1;
+ for (var i = 0, l = nonHostChars.length; i < l; i++) {
+ var index = rest.indexOf(nonHostChars[i]);
+ if (index !== -1 &&
+ (firstNonHost < 0 || index < firstNonHost)) firstNonHost = index;
+ }
+
+ if (firstNonHost !== -1) {
+ out.host = rest.substr(0, firstNonHost);
+ rest = rest.substr(firstNonHost);
+ } else {
+ out.host = rest;
+ rest = '';
+ }
+
+ // pull out port.
+ var p = parseHost(out.host);
+ var keys = Object.keys(p);
+ for (var i = 0, l = keys.length; i < l; i++) {
+ var key = keys[i];
+ out[key] = p[key];
+ }
+
+ // we've indicated that there is a hostname,
+ // so even if it's empty, it has to be present.
+ out.hostname = out.hostname || '';
+
+ // validate a little.
+ if (out.hostname.length > hostnameMaxLen) {
+ out.hostname = '';
+ } else {
+ var hostparts = out.hostname.split(/\./);
+ for (var i = 0, l = hostparts.length; i < l; i++) {
+ var part = hostparts[i];
+ if (!part) continue;
+ if (!part.match(hostnamePartPattern)) {
+ var newpart = '';
+ for (var j = 0, k = part.length; j < k; j++) {
+ if (part.charCodeAt(j) > 127) {
+ // we replace non-ASCII char with a temporary placeholder
+ // we need this to make sure size of hostname is not
+ // broken by replacing non-ASCII by nothing
+ newpart += 'x';
+ } else {
+ newpart += part[j];
+ }
+ }
+ // we test again with ASCII char only
+ if (!newpart.match(hostnamePartPattern)) {
+ var validParts = hostparts.slice(0, i);
+ var notHost = hostparts.slice(i + 1);
+ var bit = part.match(hostnamePartStart);
+ if (bit) {
+ validParts.push(bit[1]);
+ notHost.unshift(bit[2]);
+ }
+ if (notHost.length) {
+ rest = '/' + notHost.join('.') + rest;
+ }
+ out.hostname = validParts.join('.');
+ break;
+ }
+ }
+ }
+ }
+
+ // hostnames are always lower case.
+ out.hostname = out.hostname.toLowerCase();
+
+ // IDNA Support: Returns a puny coded representation of "domain".
+ // It only converts the part of the domain name that
+ // has non ASCII characters. I.e. it dosent matter if
+ // you call it with a domain that already is in ASCII.
+ var domainArray = out.hostname.split('.');
+ var newOut = [];
+ for (var i = 0; i < domainArray.length; ++i) {
+ var s = domainArray[i];
+ newOut.push(s.match(/[^A-Za-z0-9_-]/) ?
+ 'xn--' + punycode.encode(s) : s);
+ }
+ out.hostname = newOut.join('.');
+
+ out.host = (out.hostname || '') +
+ ((out.port) ? ':' + out.port : '');
+ out.href += out.host;
+ }
+
+ // now rest is set to the post-host stuff.
+ // chop off any delim chars.
+ if (!unsafeProtocol[lowerProto]) {
+
+ // First, make 100% sure that any "autoEscape" chars get
+ // escaped, even if encodeURIComponent doesn't think they
+ // need to be.
+ for (var i = 0, l = autoEscape.length; i < l; i++) {
+ var ae = autoEscape[i];
+ var esc = encodeURIComponent(ae);
+ if (esc === ae) {
+ esc = escape(ae);
+ }
+ rest = rest.split(ae).join(esc);
+ }
+
+ // Now make sure that delims never appear in a url.
+ var chop = rest.length;
+ for (var i = 0, l = delims.length; i < l; i++) {
+ var c = rest.indexOf(delims[i]);
+ if (c !== -1) {
+ chop = Math.min(c, chop);
+ }
+ }
+ rest = rest.substr(0, chop);
+ }
+
+
+ // chop off from the tail first.
+ var hash = rest.indexOf('#');
+ if (hash !== -1) {
+ // got a fragment string.
+ out.hash = rest.substr(hash);
+ rest = rest.slice(0, hash);
+ }
+ var qm = rest.indexOf('?');
+ if (qm !== -1) {
+ out.search = rest.substr(qm);
+ out.query = rest.substr(qm + 1);
+ if (parseQueryString) {
+ out.query = querystring.parse(out.query);
+ }
+ rest = rest.slice(0, qm);
+ } else if (parseQueryString) {
+ // no query string, but parseQueryString still requested
+ out.search = '';
+ out.query = {};
+ }
+ if (rest) out.pathname = rest;
+ if (slashedProtocol[proto] &&
+ out.hostname && !out.pathname) {
+ out.pathname = '/';
+ }
+
+ //to support http.request
+ if (out.pathname || out.search) {
+ out.path = (out.pathname ? out.pathname : '') +
+ (out.search ? out.search : '');
+ }
+
+ // finally, reconstruct the href based on what has been validated.
+ out.href = urlFormat(out);
+ return out;
+}
+
+// format a parsed object into a url string
+function urlFormat(obj) {
+ // ensure it's an object, and not a string url.
+ // If it's an obj, this is a no-op.
+ // this way, you can call url_format() on strings
+ // to clean up potentially wonky urls.
+ if (typeof(obj) === 'string') obj = urlParse(obj);
+
+ var auth = obj.auth || '';
+ if (auth) {
+ auth = auth.split('@').join('%40');
+ for (var i = 0, l = nonAuthChars.length; i < l; i++) {
+ var nAC = nonAuthChars[i];
+ auth = auth.split(nAC).join(encodeURIComponent(nAC));
+ }
+ auth += '@';
+ }
+
+ var protocol = obj.protocol || '',
+ host = (obj.host !== undefined) ? auth + obj.host :
+ obj.hostname !== undefined ? (
+ auth + obj.hostname +
+ (obj.port ? ':' + obj.port : '')
+ ) :
+ false,
+ pathname = obj.pathname || '',
+ query = obj.query &&
+ ((typeof obj.query === 'object' &&
+ Object.keys(obj.query).length) ?
+ querystring.stringify(obj.query) :
+ '') || '',
+ search = obj.search || (query && ('?' + query)) || '',
+ hash = obj.hash || '';
+
+ if (protocol && protocol.substr(-1) !== ':') protocol += ':';
+
+ // only the slashedProtocols get the //. Not mailto:, xmpp:, etc.
+ // unless they had them to begin with.
+ if (obj.slashes ||
+ (!protocol || slashedProtocol[protocol]) && host !== false) {
+ host = '//' + (host || '');
+ if (pathname && pathname.charAt(0) !== '/') pathname = '/' + pathname;
+ } else if (!host) {
+ host = '';
+ }
+
+ if (hash && hash.charAt(0) !== '#') hash = '#' + hash;
+ if (search && search.charAt(0) !== '?') search = '?' + search;
+
+ return protocol + host + pathname + search + hash;
+}
+
+function urlResolve(source, relative) {
+ return urlFormat(urlResolveObject(source, relative));
+}
+
+function urlResolveObject(source, relative) {
+ if (!source) return relative;
+
+ source = urlParse(urlFormat(source), false, true);
+ relative = urlParse(urlFormat(relative), false, true);
+
+ // hash is always overridden, no matter what.
+ source.hash = relative.hash;
+
+ if (relative.href === '') {
+ source.href = urlFormat(source);
+ return source;
+ }
+
+ // hrefs like //foo/bar always cut to the protocol.
+ if (relative.slashes && !relative.protocol) {
+ relative.protocol = source.protocol;
+ //urlParse appends trailing / to urls like http://www.example.com
+ if (slashedProtocol[relative.protocol] &&
+ relative.hostname && !relative.pathname) {
+ relative.path = relative.pathname = '/';
+ }
+ relative.href = urlFormat(relative);
+ return relative;
+ }
+
+ if (relative.protocol && relative.protocol !== source.protocol) {
+ // if it's a known url protocol, then changing
+ // the protocol does weird things
+ // first, if it's not file:, then we MUST have a host,
+ // and if there was a path
+ // to begin with, then we MUST have a path.
+ // if it is file:, then the host is dropped,
+ // because that's known to be hostless.
+ // anything else is assumed to be absolute.
+ if (!slashedProtocol[relative.protocol]) {
+ relative.href = urlFormat(relative);
+ return relative;
+ }
+ source.protocol = relative.protocol;
+ if (!relative.host && !hostlessProtocol[relative.protocol]) {
+ var relPath = (relative.pathname || '').split('/');
+ while (relPath.length && !(relative.host = relPath.shift()));
+ if (!relative.host) relative.host = '';
+ if (!relative.hostname) relative.hostname = '';
+ if (relPath[0] !== '') relPath.unshift('');
+ if (relPath.length < 2) relPath.unshift('');
+ relative.pathname = relPath.join('/');
+ }
+ source.pathname = relative.pathname;
+ source.search = relative.search;
+ source.query = relative.query;
+ source.host = relative.host || '';
+ source.auth = relative.auth;
+ source.hostname = relative.hostname || relative.host;
+ source.port = relative.port;
+ //to support http.request
+ if (source.pathname !== undefined || source.search !== undefined) {
+ source.path = (source.pathname ? source.pathname : '') +
+ (source.search ? source.search : '');
+ }
+ source.slashes = source.slashes || relative.slashes;
+ source.href = urlFormat(source);
+ return source;
+ }
+
+ var isSourceAbs = (source.pathname && source.pathname.charAt(0) === '/'),
+ isRelAbs = (
+ relative.host !== undefined ||
+ relative.pathname && relative.pathname.charAt(0) === '/'
+ ),
+ mustEndAbs = (isRelAbs || isSourceAbs ||
+ (source.host && relative.pathname)),
+ removeAllDots = mustEndAbs,
+ srcPath = source.pathname && source.pathname.split('/') || [],
+ relPath = relative.pathname && relative.pathname.split('/') || [],
+ psychotic = source.protocol &&
+ !slashedProtocol[source.protocol];
+
+ // if the url is a non-slashed url, then relative
+ // links like ../.. should be able
+ // to crawl up to the hostname, as well. This is strange.
+ // source.protocol has already been set by now.
+ // Later on, put the first path part into the host field.
+ if (psychotic) {
+
+ delete source.hostname;
+ delete source.port;
+ if (source.host) {
+ if (srcPath[0] === '') srcPath[0] = source.host;
+ else srcPath.unshift(source.host);
+ }
+ delete source.host;
+ if (relative.protocol) {
+ delete relative.hostname;
+ delete relative.port;
+ if (relative.host) {
+ if (relPath[0] === '') relPath[0] = relative.host;
+ else relPath.unshift(relative.host);
+ }
+ delete relative.host;
+ }
+ mustEndAbs = mustEndAbs && (relPath[0] === '' || srcPath[0] === '');
+ }
+
+ if (isRelAbs) {
+ // it's absolute.
+ source.host = (relative.host || relative.host === '') ?
+ relative.host : source.host;
+ source.hostname = (relative.hostname || relative.hostname === '') ?
+ relative.hostname : source.hostname;
+ source.search = relative.search;
+ source.query = relative.query;
+ srcPath = relPath;
+ // fall through to the dot-handling below.
+ } else if (relPath.length) {
+ // it's relative
+ // throw away the existing file, and take the new path instead.
+ if (!srcPath) srcPath = [];
+ srcPath.pop();
+ srcPath = srcPath.concat(relPath);
+ source.search = relative.search;
+ source.query = relative.query;
+ } else if ('search' in relative) {
+ // just pull out the search.
+ // like href='?foo'.
+ // Put this after the other two cases because it simplifies the booleans
+ if (psychotic) {
+ source.hostname = source.host = srcPath.shift();
+ //occationaly the auth can get stuck only in host
+ //this especialy happens in cases like
+ //url.resolveObject('mailto:local1@domain1', 'local2@domain2')
+ var authInHost = source.host && source.host.indexOf('@') > 0 ?
+ source.host.split('@') : false;
+ if (authInHost) {
+ source.auth = authInHost.shift();
+ source.host = source.hostname = authInHost.shift();
+ }
+ }
+ source.search = relative.search;
+ source.query = relative.query;
+ //to support http.request
+ if (source.pathname !== undefined || source.search !== undefined) {
+ source.path = (source.pathname ? source.pathname : '') +
+ (source.search ? source.search : '');
+ }
+ source.href = urlFormat(source);
+ return source;
+ }
+ if (!srcPath.length) {
+ // no path at all. easy.
+ // we've already handled the other stuff above.
+ delete source.pathname;
+ //to support http.request
+ if (!source.search) {
+ source.path = '/' + source.search;
+ } else {
+ delete source.path;
+ }
+ source.href = urlFormat(source);
+ return source;
+ }
+ // if a url ENDs in . or .., then it must get a trailing slash.
+ // however, if it ends in anything else non-slashy,
+ // then it must NOT get a trailing slash.
+ var last = srcPath.slice(-1)[0];
+ var hasTrailingSlash = (
+ (source.host || relative.host) && (last === '.' || last === '..') ||
+ last === '');
+
+ // strip single dots, resolve double dots to parent dir
+ // if the path tries to go above the root, `up` ends up > 0
+ var up = 0;
+ for (var i = srcPath.length; i >= 0; i--) {
+ last = srcPath[i];
+ if (last == '.') {
+ srcPath.splice(i, 1);
+ } else if (last === '..') {
+ srcPath.splice(i, 1);
+ up++;
+ } else if (up) {
+ srcPath.splice(i, 1);
+ up--;
+ }
+ }
+
+ // if the path is allowed to go above the root, restore leading ..s
+ if (!mustEndAbs && !removeAllDots) {
+ for (; up--; up) {
+ srcPath.unshift('..');
+ }
+ }
+
+ if (mustEndAbs && srcPath[0] !== '' &&
+ (!srcPath[0] || srcPath[0].charAt(0) !== '/')) {
+ srcPath.unshift('');
+ }
+
+ if (hasTrailingSlash && (srcPath.join('/').substr(-1) !== '/')) {
+ srcPath.push('');
+ }
+
+ var isAbsolute = srcPath[0] === '' ||
+ (srcPath[0] && srcPath[0].charAt(0) === '/');
+
+ // put the host back
+ if (psychotic) {
+ source.hostname = source.host = isAbsolute ? '' :
+ srcPath.length ? srcPath.shift() : '';
+ //occationaly the auth can get stuck only in host
+ //this especialy happens in cases like
+ //url.resolveObject('mailto:local1@domain1', 'local2@domain2')
+ var authInHost = source.host && source.host.indexOf('@') > 0 ?
+ source.host.split('@') : false;
+ if (authInHost) {
+ source.auth = authInHost.shift();
+ source.host = source.hostname = authInHost.shift();
+ }
+ }
+
+ mustEndAbs = mustEndAbs || (source.host && srcPath.length);
+
+ if (mustEndAbs && !isAbsolute) {
+ srcPath.unshift('');
+ }
+
+ source.pathname = srcPath.join('/');
+ //to support request.http
+ if (source.pathname !== undefined || source.search !== undefined) {
+ source.path = (source.pathname ? source.pathname : '') +
+ (source.search ? source.search : '');
+ }
+ source.auth = relative.auth || source.auth;
+ source.slashes = source.slashes || relative.slashes;
+ source.href = urlFormat(source);
+ return source;
+}
+
+function parseHost(host) {
+ var out = {};
+ var port = portPattern.exec(host);
+ if (port) {
+ port = port[0];
+ out.port = port.substr(1);
+ host = host.substr(0, host.length - port.length);
+ }
+ if (host) out.hostname = host;
+ return out;
+} \ No newline at end of file
diff --git a/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/url_handler/url_handler.js b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/url_handler/url_handler.js
new file mode 100644
index 0000000..41ec82e
--- /dev/null
+++ b/data/extensions/jid1-KtlZuoiikVfFew@jetpack/resources/librejs/lib/url_handler/url_handler.js
@@ -0,0 +1,120 @@
+/**
+ * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript.
+ * *
+ * Copyright (C) 2011, 2012, 2013, 2014 Loic J. Duros
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+/**
+ * url_handler
+ * A module using the url tool from Node.js to perform operations on
+ * urls at various spots (tabs, caching, ...) in the add-on.
+ *
+ */
+
+// node.js url module. Makes it easier to resole
+// urls in that datauri loaded dom
+var nodeJsUrl = require("url_handler/node_url");
+
+var urlUtils = {
+
+ getFragment: function (url) {
+ var parse = nodeJsUrl.parse(url);
+ if (parse.hash !== undefined) {
+ return(parse.hash);
+ }
+ },
+
+ removeFragment: function (url) {
+ var parse = nodeJsUrl.parse(url);
+ if (parse.hash !== undefined) {
+ // Amazon track package bug fix.
+ // when url has query string and fragment
+ // the add-on wouldn't remove cache entry
+ // properly.
+ delete parse.hash;
+ }
+ return nodeJsUrl.format(parse);
+ },
+
+ addFragment: function (url, query) {
+ var parse = nodeJsUrl.parse(url);
+
+ // replace hash if it exists.
+ parse.hash = '#' + query;
+
+ return nodeJsUrl.format(parse);
+ },
+
+ addQuery: function (url, query) {
+ var parse = nodeJsUrl.parse(url);
+ console.debug('my parse search', parse.search);
+ if (parse.search === undefined) {
+ parse.search = '?' + query;
+ } else {
+ parse.search = parse.search + '&' + query;
+ console.debug('parse search is now' + parse.search);
+ }
+ return nodeJsUrl.format(parse);
+ },
+
+ getHostname: function (url) {
+ return nodeJsUrl.parse(url).hostname;
+ },
+
+ /**
+ * remove www from hostname.
+ */
+ removeWWW: function (str) {
+ if (str !== undefined) {
+ return str.replace("www.", "", 'i');
+ }
+ return "";
+ },
+
+ /**
+ *
+ * haveSameHostname
+ * Compare that two urls have the same hostname.
+ *
+ */
+ haveSameHostname: function (url1, url2) {
+
+ try {
+
+ var host1 = this.removeWWW(this.getHostname(url1)).toLowerCase();
+ var host2 = this.removeWWW(this.getHostname(url2)).toLowerCase();
+ return host1 === host2;
+
+ } catch (x) {
+
+ console.debug('error with url_handler', x, x.fileName, x.lineNumber);
+
+ }
+ }
+};
+
+exports.parse = nodeJsUrl.parse;
+exports.resolve = nodeJsUrl.resolve;
+exports.resolveObject = nodeJsUrl.resolveObject;
+exports.format = nodeJsUrl.format;
+exports.removeFragment = urlUtils.removeFragment;
+exports.addQuery = urlUtils.addQuery;
+exports.getFragment = urlUtils.getFragment;
+exports.addFragment = urlUtils.addFragment;
+exports.getHostname = urlUtils.getHostname;
+exports.haveSameHostname = urlUtils.haveSameHostname;
+exports.removeWWW = urlUtils.removeWWW;