Bug 731779: Integrate the Add-on SDK loader and API libraries into Firefox (uplifting from addon-sdk a16bbd5772880b578a939eeb65102bca6560d494)
This commit is contained in:
236
addon-sdk/source/lib/sdk/url.js
Normal file
236
addon-sdk/source/lib/sdk/url.js
Normal file
@@ -0,0 +1,236 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
module.metadata = {
|
||||
"stability": "experimental"
|
||||
};
|
||||
|
||||
const { Cc, Ci, Cr } = require("chrome");
|
||||
|
||||
const { Class } = require("./core/heritage");
|
||||
const base64 = require("./base64");
|
||||
|
||||
var ios = Cc['@mozilla.org/network/io-service;1']
|
||||
.getService(Ci.nsIIOService);
|
||||
|
||||
var resProt = ios.getProtocolHandler("resource")
|
||||
.QueryInterface(Ci.nsIResProtocolHandler);
|
||||
|
||||
function newURI(uriStr, base) {
|
||||
try {
|
||||
let baseURI = base ? ios.newURI(base, null, null) : null;
|
||||
return ios.newURI(uriStr, null, baseURI);
|
||||
}
|
||||
catch (e if e.result == Cr.NS_ERROR_MALFORMED_URI) {
|
||||
throw new Error("malformed URI: " + uriStr);
|
||||
}
|
||||
catch (e if (e.result == Cr.NS_ERROR_FAILURE ||
|
||||
e.result == Cr.NS_ERROR_ILLEGAL_VALUE)) {
|
||||
throw new Error("invalid URI: " + uriStr);
|
||||
}
|
||||
}
|
||||
|
||||
function resolveResourceURI(uri) {
|
||||
var resolved;
|
||||
try {
|
||||
resolved = resProt.resolveURI(uri);
|
||||
} catch (e if e.result == Cr.NS_ERROR_NOT_AVAILABLE) {
|
||||
throw new Error("resource does not exist: " + uri.spec);
|
||||
};
|
||||
return resolved;
|
||||
}
|
||||
|
||||
let fromFilename = exports.fromFilename = function fromFilename(path) {
|
||||
var file = Cc['@mozilla.org/file/local;1']
|
||||
.createInstance(Ci.nsILocalFile);
|
||||
file.initWithPath(path);
|
||||
return ios.newFileURI(file).spec;
|
||||
};
|
||||
|
||||
let toFilename = exports.toFilename = function toFilename(url) {
|
||||
var uri = newURI(url);
|
||||
if (uri.scheme == "resource")
|
||||
uri = newURI(resolveResourceURI(uri));
|
||||
if (uri.scheme == "chrome") {
|
||||
var channel = ios.newChannelFromURI(uri);
|
||||
try {
|
||||
channel = channel.QueryInterface(Ci.nsIFileChannel);
|
||||
return channel.file.path;
|
||||
} catch (e if e.result == Cr.NS_NOINTERFACE) {
|
||||
throw new Error("chrome url isn't on filesystem: " + url);
|
||||
}
|
||||
}
|
||||
if (uri.scheme == "file") {
|
||||
var file = uri.QueryInterface(Ci.nsIFileURL).file;
|
||||
return file.path;
|
||||
}
|
||||
throw new Error("cannot map to filename: " + url);
|
||||
};
|
||||
|
||||
function URL(url, base) {
|
||||
if (!(this instanceof URL)) {
|
||||
return new URL(url, base);
|
||||
}
|
||||
|
||||
var uri = newURI(url, base);
|
||||
|
||||
var userPass = null;
|
||||
try {
|
||||
userPass = uri.userPass ? uri.userPass : null;
|
||||
} catch (e if e.result == Cr.NS_ERROR_FAILURE) {}
|
||||
|
||||
var host = null;
|
||||
try {
|
||||
host = uri.host;
|
||||
} catch (e if e.result == Cr.NS_ERROR_FAILURE) {}
|
||||
|
||||
var port = null;
|
||||
try {
|
||||
port = uri.port == -1 ? null : uri.port;
|
||||
} catch (e if e.result == Cr.NS_ERROR_FAILURE) {}
|
||||
|
||||
this.__defineGetter__("scheme", function() uri.scheme);
|
||||
this.__defineGetter__("userPass", function() userPass);
|
||||
this.__defineGetter__("host", function() host);
|
||||
this.__defineGetter__("port", function() port);
|
||||
this.__defineGetter__("path", function() uri.path);
|
||||
|
||||
Object.defineProperties(this, {
|
||||
toString: {
|
||||
value: function URL_toString() new String(uri.spec).toString(),
|
||||
enumerable: false
|
||||
},
|
||||
valueOf: {
|
||||
value: function() new String(uri.spec).valueOf(),
|
||||
enumerable: false
|
||||
},
|
||||
toSource: {
|
||||
value: function() new String(uri.spec).toSource(),
|
||||
enumerable: false
|
||||
}
|
||||
});
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
URL.prototype = Object.create(String.prototype);
|
||||
exports.URL = URL;
|
||||
|
||||
/**
|
||||
* Parse and serialize a Data URL.
|
||||
*
|
||||
* See: http://tools.ietf.org/html/rfc2397
|
||||
*
|
||||
* Note: Could be extended in the future to decode / encode automatically binary
|
||||
* data.
|
||||
*/
|
||||
const DataURL = Class({
|
||||
|
||||
get base64 () {
|
||||
return "base64" in this.parameters;
|
||||
},
|
||||
|
||||
set base64 (value) {
|
||||
if (value)
|
||||
this.parameters["base64"] = "";
|
||||
else
|
||||
delete this.parameters["base64"];
|
||||
},
|
||||
/**
|
||||
* Initialize the Data URL object. If a uri is given, it will be parsed.
|
||||
*
|
||||
* @param {String} [uri] The uri to parse
|
||||
*
|
||||
* @throws {URIError} if the Data URL is malformed
|
||||
*/
|
||||
initialize: function(uri) {
|
||||
// Due to bug 751834 it is not possible document and define these
|
||||
// properties in the prototype.
|
||||
|
||||
/**
|
||||
* An hashmap that contains the parameters of the Data URL. By default is
|
||||
* empty, that accordingly to RFC is equivalent to {"charset" : "US-ASCII"}
|
||||
*/
|
||||
this.parameters = {};
|
||||
|
||||
/**
|
||||
* The MIME type of the data. By default is empty, that accordingly to RFC
|
||||
* is equivalent to "text/plain"
|
||||
*/
|
||||
this.mimeType = "";
|
||||
|
||||
/**
|
||||
* The string that represent the data in the Data URL
|
||||
*/
|
||||
this.data = "";
|
||||
|
||||
if (typeof uri === "undefined")
|
||||
return;
|
||||
|
||||
uri = String(uri);
|
||||
|
||||
let matches = uri.match(/^data:([^,]*),(.*)$/i);
|
||||
|
||||
if (!matches)
|
||||
throw new URIError("Malformed Data URL: " + uri);
|
||||
|
||||
let mediaType = matches[1].trim();
|
||||
|
||||
this.data = decodeURIComponent(matches[2].trim());
|
||||
|
||||
if (!mediaType)
|
||||
return;
|
||||
|
||||
let parametersList = mediaType.split(";");
|
||||
|
||||
this.mimeType = parametersList.shift().trim();
|
||||
|
||||
for (let parameter, i = 0; parameter = parametersList[i++];) {
|
||||
let pairs = parameter.split("=");
|
||||
let name = pairs[0].trim();
|
||||
let value = pairs.length > 1 ? decodeURIComponent(pairs[1].trim()) : "";
|
||||
|
||||
this.parameters[name] = value;
|
||||
}
|
||||
|
||||
if (this.base64)
|
||||
this.data = base64.decode(this.data);
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the object as a valid Data URL string
|
||||
*
|
||||
* @returns {String} The Data URL
|
||||
*/
|
||||
toString : function() {
|
||||
let parametersList = [];
|
||||
|
||||
for (let name in this.parameters) {
|
||||
let encodedParameter = encodeURIComponent(name);
|
||||
let value = this.parameters[name];
|
||||
|
||||
if (value)
|
||||
encodedParameter += "=" + encodeURIComponent(value);
|
||||
|
||||
parametersList.push(encodedParameter);
|
||||
}
|
||||
|
||||
// If there is at least a parameter, add an empty string in order
|
||||
// to start with a `;` on join call.
|
||||
if (parametersList.length > 0)
|
||||
parametersList.unshift("");
|
||||
|
||||
let data = this.base64 ? base64.encode(this.data) : this.data;
|
||||
|
||||
return "data:" +
|
||||
this.mimeType +
|
||||
parametersList.join(";") + "," +
|
||||
encodeURIComponent(data);
|
||||
}
|
||||
});
|
||||
|
||||
exports.DataURL = DataURL;
|
||||
Reference in New Issue
Block a user