addon-sdk/source/lib/sdk/url.js

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4 "use strict";
michael@0 5
michael@0 6 module.metadata = {
michael@0 7 "stability": "experimental"
michael@0 8 };
michael@0 9
michael@0 10 const { Cc, Ci, Cr } = require("chrome");
michael@0 11
michael@0 12 const { Class } = require("./core/heritage");
michael@0 13 const base64 = require("./base64");
michael@0 14 var tlds = Cc["@mozilla.org/network/effective-tld-service;1"]
michael@0 15 .getService(Ci.nsIEffectiveTLDService);
michael@0 16
michael@0 17 var ios = Cc['@mozilla.org/network/io-service;1']
michael@0 18 .getService(Ci.nsIIOService);
michael@0 19
michael@0 20 var resProt = ios.getProtocolHandler("resource")
michael@0 21 .QueryInterface(Ci.nsIResProtocolHandler);
michael@0 22
michael@0 23 var URLParser = Cc["@mozilla.org/network/url-parser;1?auth=no"]
michael@0 24 .getService(Ci.nsIURLParser);
michael@0 25
michael@0 26 function newURI(uriStr, base) {
michael@0 27 try {
michael@0 28 let baseURI = base ? ios.newURI(base, null, null) : null;
michael@0 29 return ios.newURI(uriStr, null, baseURI);
michael@0 30 }
michael@0 31 catch (e) {
michael@0 32 if (e.result == Cr.NS_ERROR_MALFORMED_URI) {
michael@0 33 throw new Error("malformed URI: " + uriStr);
michael@0 34 }
michael@0 35 if (e.result == Cr.NS_ERROR_FAILURE ||
michael@0 36 e.result == Cr.NS_ERROR_ILLEGAL_VALUE) {
michael@0 37 throw new Error("invalid URI: " + uriStr);
michael@0 38 }
michael@0 39 }
michael@0 40 }
michael@0 41
michael@0 42 function resolveResourceURI(uri) {
michael@0 43 var resolved;
michael@0 44 try {
michael@0 45 resolved = resProt.resolveURI(uri);
michael@0 46 }
michael@0 47 catch (e) {
michael@0 48 if (e.result == Cr.NS_ERROR_NOT_AVAILABLE) {
michael@0 49 throw new Error("resource does not exist: " + uri.spec);
michael@0 50 }
michael@0 51 }
michael@0 52 return resolved;
michael@0 53 }
michael@0 54
michael@0 55 let fromFilename = exports.fromFilename = function fromFilename(path) {
michael@0 56 var file = Cc['@mozilla.org/file/local;1']
michael@0 57 .createInstance(Ci.nsILocalFile);
michael@0 58 file.initWithPath(path);
michael@0 59 return ios.newFileURI(file).spec;
michael@0 60 };
michael@0 61
michael@0 62 let toFilename = exports.toFilename = function toFilename(url) {
michael@0 63 var uri = newURI(url);
michael@0 64 if (uri.scheme == "resource")
michael@0 65 uri = newURI(resolveResourceURI(uri));
michael@0 66 if (uri.scheme == "chrome") {
michael@0 67 var channel = ios.newChannelFromURI(uri);
michael@0 68 try {
michael@0 69 channel = channel.QueryInterface(Ci.nsIFileChannel);
michael@0 70 return channel.file.path;
michael@0 71 }
michael@0 72 catch (e) {
michael@0 73 if (e.result == Cr.NS_NOINTERFACE) {
michael@0 74 throw new Error("chrome url isn't on filesystem: " + url);
michael@0 75 }
michael@0 76 }
michael@0 77 }
michael@0 78 if (uri.scheme == "file") {
michael@0 79 var file = uri.QueryInterface(Ci.nsIFileURL).file;
michael@0 80 return file.path;
michael@0 81 }
michael@0 82 throw new Error("cannot map to filename: " + url);
michael@0 83 };
michael@0 84
michael@0 85 function URL(url, base) {
michael@0 86 if (!(this instanceof URL)) {
michael@0 87 return new URL(url, base);
michael@0 88 }
michael@0 89
michael@0 90 var uri = newURI(url, base);
michael@0 91
michael@0 92 var userPass = null;
michael@0 93 try {
michael@0 94 userPass = uri.userPass ? uri.userPass : null;
michael@0 95 }
michael@0 96 catch (e) {
michael@0 97 if (e.result != Cr.NS_ERROR_FAILURE) {
michael@0 98 throw e;
michael@0 99 }
michael@0 100 }
michael@0 101
michael@0 102 var host = null;
michael@0 103 try {
michael@0 104 host = uri.host;
michael@0 105 }
michael@0 106 catch (e) {
michael@0 107 if (e.result != Cr.NS_ERROR_FAILURE) {
michael@0 108 throw e;
michael@0 109 }
michael@0 110 }
michael@0 111
michael@0 112 var port = null;
michael@0 113 try {
michael@0 114 port = uri.port == -1 ? null : uri.port;
michael@0 115 }
michael@0 116 catch (e) {
michael@0 117 if (e.result != Cr.NS_ERROR_FAILURE) {
michael@0 118 throw e;
michael@0 119 }
michael@0 120 }
michael@0 121
michael@0 122 let uriData = [uri.path, uri.path.length, {}, {}, {}, {}, {}, {}];
michael@0 123 URLParser.parsePath.apply(URLParser, uriData);
michael@0 124 let [{ value: filepathPos }, { value: filepathLen },
michael@0 125 { value: queryPos }, { value: queryLen },
michael@0 126 { value: refPos }, { value: refLen }] = uriData.slice(2);
michael@0 127
michael@0 128 let hash = uri.ref ? "#" + uri.ref : "";
michael@0 129 let pathname = uri.path.substr(filepathPos, filepathLen);
michael@0 130 let search = uri.path.substr(queryPos, queryLen);
michael@0 131 search = search ? "?" + search : "";
michael@0 132
michael@0 133 this.__defineGetter__("scheme", function() uri.scheme);
michael@0 134 this.__defineGetter__("userPass", function() userPass);
michael@0 135 this.__defineGetter__("host", function() host);
michael@0 136 this.__defineGetter__("hostname", function() host);
michael@0 137 this.__defineGetter__("port", function() port);
michael@0 138 this.__defineGetter__("path", function() uri.path);
michael@0 139 this.__defineGetter__("pathname", function() pathname);
michael@0 140 this.__defineGetter__("hash", function() hash);
michael@0 141 this.__defineGetter__("href", function() uri.spec);
michael@0 142 this.__defineGetter__("origin", function() uri.prePath);
michael@0 143 this.__defineGetter__("protocol", function() uri.scheme + ":");
michael@0 144 this.__defineGetter__("search", function() search);
michael@0 145
michael@0 146 Object.defineProperties(this, {
michael@0 147 toString: {
michael@0 148 value: function URL_toString() new String(uri.spec).toString(),
michael@0 149 enumerable: false
michael@0 150 },
michael@0 151 valueOf: {
michael@0 152 value: function() new String(uri.spec).valueOf(),
michael@0 153 enumerable: false
michael@0 154 },
michael@0 155 toSource: {
michael@0 156 value: function() new String(uri.spec).toSource(),
michael@0 157 enumerable: false
michael@0 158 }
michael@0 159 });
michael@0 160
michael@0 161 return this;
michael@0 162 };
michael@0 163
michael@0 164 URL.prototype = Object.create(String.prototype);
michael@0 165 exports.URL = URL;
michael@0 166
michael@0 167 /**
michael@0 168 * Parse and serialize a Data URL.
michael@0 169 *
michael@0 170 * See: http://tools.ietf.org/html/rfc2397
michael@0 171 *
michael@0 172 * Note: Could be extended in the future to decode / encode automatically binary
michael@0 173 * data.
michael@0 174 */
michael@0 175 const DataURL = Class({
michael@0 176
michael@0 177 get base64 () {
michael@0 178 return "base64" in this.parameters;
michael@0 179 },
michael@0 180
michael@0 181 set base64 (value) {
michael@0 182 if (value)
michael@0 183 this.parameters["base64"] = "";
michael@0 184 else
michael@0 185 delete this.parameters["base64"];
michael@0 186 },
michael@0 187 /**
michael@0 188 * Initialize the Data URL object. If a uri is given, it will be parsed.
michael@0 189 *
michael@0 190 * @param {String} [uri] The uri to parse
michael@0 191 *
michael@0 192 * @throws {URIError} if the Data URL is malformed
michael@0 193 */
michael@0 194 initialize: function(uri) {
michael@0 195 // Due to bug 751834 it is not possible document and define these
michael@0 196 // properties in the prototype.
michael@0 197
michael@0 198 /**
michael@0 199 * An hashmap that contains the parameters of the Data URL. By default is
michael@0 200 * empty, that accordingly to RFC is equivalent to {"charset" : "US-ASCII"}
michael@0 201 */
michael@0 202 this.parameters = {};
michael@0 203
michael@0 204 /**
michael@0 205 * The MIME type of the data. By default is empty, that accordingly to RFC
michael@0 206 * is equivalent to "text/plain"
michael@0 207 */
michael@0 208 this.mimeType = "";
michael@0 209
michael@0 210 /**
michael@0 211 * The string that represent the data in the Data URL
michael@0 212 */
michael@0 213 this.data = "";
michael@0 214
michael@0 215 if (typeof uri === "undefined")
michael@0 216 return;
michael@0 217
michael@0 218 uri = String(uri);
michael@0 219
michael@0 220 let matches = uri.match(/^data:([^,]*),(.*)$/i);
michael@0 221
michael@0 222 if (!matches)
michael@0 223 throw new URIError("Malformed Data URL: " + uri);
michael@0 224
michael@0 225 let mediaType = matches[1].trim();
michael@0 226
michael@0 227 this.data = decodeURIComponent(matches[2].trim());
michael@0 228
michael@0 229 if (!mediaType)
michael@0 230 return;
michael@0 231
michael@0 232 let parametersList = mediaType.split(";");
michael@0 233
michael@0 234 this.mimeType = parametersList.shift().trim();
michael@0 235
michael@0 236 for (let parameter, i = 0; parameter = parametersList[i++];) {
michael@0 237 let pairs = parameter.split("=");
michael@0 238 let name = pairs[0].trim();
michael@0 239 let value = pairs.length > 1 ? decodeURIComponent(pairs[1].trim()) : "";
michael@0 240
michael@0 241 this.parameters[name] = value;
michael@0 242 }
michael@0 243
michael@0 244 if (this.base64)
michael@0 245 this.data = base64.decode(this.data);
michael@0 246
michael@0 247 },
michael@0 248
michael@0 249 /**
michael@0 250 * Returns the object as a valid Data URL string
michael@0 251 *
michael@0 252 * @returns {String} The Data URL
michael@0 253 */
michael@0 254 toString : function() {
michael@0 255 let parametersList = [];
michael@0 256
michael@0 257 for (let name in this.parameters) {
michael@0 258 let encodedParameter = encodeURIComponent(name);
michael@0 259 let value = this.parameters[name];
michael@0 260
michael@0 261 if (value)
michael@0 262 encodedParameter += "=" + encodeURIComponent(value);
michael@0 263
michael@0 264 parametersList.push(encodedParameter);
michael@0 265 }
michael@0 266
michael@0 267 // If there is at least a parameter, add an empty string in order
michael@0 268 // to start with a `;` on join call.
michael@0 269 if (parametersList.length > 0)
michael@0 270 parametersList.unshift("");
michael@0 271
michael@0 272 let data = this.base64 ? base64.encode(this.data) : this.data;
michael@0 273
michael@0 274 return "data:" +
michael@0 275 this.mimeType +
michael@0 276 parametersList.join(";") + "," +
michael@0 277 encodeURIComponent(data);
michael@0 278 }
michael@0 279 });
michael@0 280
michael@0 281 exports.DataURL = DataURL;
michael@0 282
michael@0 283 let getTLD = exports.getTLD = function getTLD (url) {
michael@0 284 let uri = newURI(url.toString());
michael@0 285 let tld = null;
michael@0 286 try {
michael@0 287 tld = tlds.getPublicSuffix(uri);
michael@0 288 }
michael@0 289 catch (e) {
michael@0 290 if (e.result != Cr.NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS &&
michael@0 291 e.result != Cr.NS_ERROR_HOST_IS_IP_ADDRESS) {
michael@0 292 throw e;
michael@0 293 }
michael@0 294 }
michael@0 295 return tld;
michael@0 296 };
michael@0 297
michael@0 298 let isValidURI = exports.isValidURI = function (uri) {
michael@0 299 try {
michael@0 300 newURI(uri);
michael@0 301 }
michael@0 302 catch(e) {
michael@0 303 return false;
michael@0 304 }
michael@0 305 return true;
michael@0 306 }
michael@0 307
michael@0 308 function isLocalURL(url) {
michael@0 309 if (String.indexOf(url, './') === 0)
michael@0 310 return true;
michael@0 311
michael@0 312 try {
michael@0 313 return ['resource', 'data', 'chrome'].indexOf(URL(url).scheme) > -1;
michael@0 314 }
michael@0 315 catch(e) {}
michael@0 316
michael@0 317 return false;
michael@0 318 }
michael@0 319 exports.isLocalURL = isLocalURL;

mercurial