/** * Opens a channel for given URL. Tries a bit harder than NetUtil.newChannel. * * @param {String} url - The URL to open a channel for. * @param {Object} options - The options object passed to @method fetch. * @return {nsIChannel} - The newly created channel. Throws on failure. */ function newChannelForURL(url, { policy, window, principal }, recursing = false) { const securityFlags = Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL; let uri; try { uri = Services.io.newURI(url); } catch (e) { // In the xpcshell tests, the script url is the absolute path of the test // file, which will make a malformed URI error be thrown. Add the file // scheme to see if it helps. uri = Services.io.newURI("file://" + url); } const channelOptions = { contentPolicyType: policy, securityFlags: securityFlags, uri: uri, }; // Ensure that we have some contentPolicyType type set if one was // not provided. if (!channelOptions.contentPolicyType) { channelOptions.contentPolicyType = Ci.nsIContentPolicy.TYPE_OTHER; } // If a window is provided, always use it's document as the loadingNode. // This will provide the correct principal, origin attributes, service // worker controller, etc. if (window) { channelOptions.loadingNode = window.document; } else { // If a window is not provided, then we must set a loading principal. // If the caller did not provide a principal, then we use the URI // to create one. Note, it's not clear what use cases require this // and it may not be correct. let prin = principal; if (!prin) { prin = Services.scriptSecurityManager .createCodebasePrincipal(uri, {}); } channelOptions.loadingPrincipal = prin; } try { return NetUtil.newChannel(channelOptions); } catch (e) { // Don't infinitely recurse if newChannel keeps throwing. if (recursing) { throw e; } // In xpcshell tests on Windows, nsExternalProtocolHandler::NewChannel() // can throw NS_ERROR_UNKNOWN_PROTOCOL if the external protocol isn't // supported by Windows, so we also need to handle the exception here if // parsing the URL above doesn't throw. return newChannelForURL("file://" + url, { policy, window, principal }, /* recursing */ true); } }
/** * Normalize multiple relative paths towards the base paths on the right. */ function normalize(...aURLs) { let base = Services.io.newURI(aURLs.pop()); let url; while ((url = aURLs.pop())) { base = Services.io.newURI(url, null, base); } return base.spec; }
AppValidator.prototype._getOriginURL = function () { if (this.type == "packaged") { let manifestURL = Services.io.newURI(this.manifestURL); return Services.io.newURI(".", null, manifestURL).spec; } else if (this.type == "hosted") { return Services.io.newURI(this.location).prePath; } };
isMixedHTTPSRequest: function (request, location) { try { let requestURI = Services.io.newURI(request); let contentURI = Services.io.newURI(location); return (contentURI.scheme == "https" && requestURI.scheme != "https"); } catch (ex) { return false; } },
isMixedHTTPSRequest: function WCU_isMixedHTTPSRequest(aRequest, aLocation) { try { let requestURI = Services.io.newURI(aRequest, null, null); let contentURI = Services.io.newURI(aLocation, null, null); return (contentURI.scheme == "https" && requestURI.scheme != "https"); } catch (ex) { return false; } },
resolveRelativeURL: function(url, node) { const document = InspectorActorUtils.isNodeDead(node) ? this.window.document : InspectorActorUtils.nodeDocument(node.rawNode); if (!document) { return url; } const baseURI = Services.io.newURI(document.location.href); return Services.io.newURI(url, null, baseURI).spec; },
_mapSourceToAddon: function () { try { var nsuri = Services.io.newURI(this.url.split(" -> ").pop(), null, null); } catch (e) { // We can't do anything with an invalid URI return; } let localURI = resolveURIToLocalPath(nsuri); if (!localURI) { return; } let id = mapURIToAddonID(localURI); if (!id) { return; } this._addonID = id; if (localURI instanceof Ci.nsIJARURI) { // The path in the add-on is easy for jar: uris this._addonPath = localURI.JAREntry; } else if (localURI instanceof Ci.nsIFileURL) { // For file: uris walk up to find the last directory that is part of the // add-on let target = localURI.file; let path = target.leafName; // We can assume that the directory containing the source file is part // of the add-on let root = target.parent; let file = root.parent; while (file && mapURIToAddonID(Services.io.newFileURI(file))) { path = root.leafName + "/" + path; root = file; file = file.parent; } if (!file) { const error = new Error("Could not find the root of the add-on for " + this.url); DevToolsUtils.reportException("SourceActor.prototype._mapSourceToAddon", error); return; } this._addonPath = path; } },
AppValidator.prototype._getPackagedManifestURL = function () { let manifestFile = this._getPackagedManifestFile(); if (!manifestFile) { return null; } return Services.io.newFileURI(manifestFile).spec; };
function getSupportsFile(path) { let cr = Cc["@mozilla.org/chrome/chrome-registry;1"] .getService(Ci.nsIChromeRegistry); let uri = Services.io.newURI(CHROME_ROOT + path, null, null); let fileurl = cr.convertChromeURL(uri); return fileurl.QueryInterface(Ci.nsIFileURL); }
return new Promise((resolve, reject) => { try { uri = Services.io.newURI(uri, null, null); } catch (e) { reject(e); } if (uri.scheme != "resource") { reject(new Error( "Can only register actors whose URI scheme is 'resource'.")); } NetUtil.asyncFetch(uri, (stream, status, req) => { if (!components.isSuccessCode(status)) { reject(new Error("Request failed with status code = " + status + " after NetUtil.asyncFetch for url = " + uri)); return; } let source = NetUtil.readInputStreamToString(stream, stream.available()); stream.close(); resolve(source); }); });
exec: function* (args, context) { let document = context.environment.document; let library = args.library; let name = (library.type === "selection") ? library.selection.name : library.url; let src = (library.type === "selection") ? library.selection.src : library.url; if (context.environment.window.location.protocol == "https:") { src = src.replace(/^http:/, "https:"); } try { // Check if URI is valid Services.io.newURI(src, null, null); } catch (e) { return l10n.lookupFormat("injectFailed", [name]); } let newSource = document.createElement("script"); newSource.setAttribute("src", src); let loadPromise = listenOnce(newSource, "load"); document.head.appendChild(newSource); yield loadPromise; return l10n.lookupFormat("injectLoaded", [name]); }
return new Promise(resolve => { // The launch_path field has to start with a `/` if (manifest.launch_path && manifest.launch_path[0] !== "/") { this.error(strings.formatStringFromName("validator.nonAbsoluteLaunchPath", [manifest.launch_path], 1)); resolve(); } let origin = this._getOriginURL(); let path; if (this.type == "packaged") { path = "." + (manifest.launch_path || "/index.html"); } else if (this.type == "hosted") { path = manifest.launch_path || "/"; } let indexURL; try { indexURL = Services.io.newURI(path, null, Services.io.newURI(origin)).spec; } catch (e) { this.error(strings.formatStringFromName("validator.accessFailedLaunchPath", [origin + path], 1)); return resolve(); } let req = new XMLHttpRequest(); req.overrideMimeType("text/plain"); try { req.open("HEAD", indexURL, true); req.channel.loadFlags |= Ci.nsIRequest.LOAD_BYPASS_CACHE | Ci.nsIRequest.INHIBIT_CACHING; } catch (e) { this.error(strings.formatStringFromName("validator.accessFailedLaunchPath", [indexURL], 1)); return resolve(); } req.onload = () => { if (req.status >= 400) this.error(strings.formatStringFromName("validator.accessFailedLaunchPathBadHttpCode", [indexURL, req.status], 2)); resolve(); }; req.onerror = () => { this.error(strings.formatStringFromName("validator.accessFailedLaunchPath", [indexURL], 1)); resolve(); }; try { req.send(null); } catch (e) { this.error(strings.formatStringFromName("validator.accessFailedLaunchPath", [indexURL], 1)); resolve(); } });
exports.joinURI = (initialPath, ...paths) => { let uri; try { uri = Services.io.newURI(initialPath, null, null); } catch(e) { return; } for(let path of paths) { if (path) { uri = Services.io.newURI(path, null, uri); } } return uri.spec; }
nsIURL: function (url, store = gNSURLStore) { if (store.has(url)) { return store.get(url); } let uri = Services.io.newURI(url).QueryInterface(Ci.nsIURL); store.set(url, uri); return uri; }
/** * Returns the full path of the file with the specified name in a * platform-independent and URL-like form. */ function getFilePath(aName, aAllowMissing=false) { let file = do_get_file(aName, aAllowMissing); let path = Services.io.newFileURI(file).spec; let filePrePath = "file://"; if ("nsILocalFileWin" in Ci && file instanceof Ci.nsILocalFileWin) { filePrePath += "/"; } return path.slice(filePrePath.length); }
/** * Opens a channel for given URL. Tries a bit harder than NetUtil.newChannel. * * @param {String} url - The URL to open a channel for. * @param {Object} options - The options object passed to @method fetch. * @return {nsIChannel} - The newly created channel. Throws on failure. */ function newChannelForURL(url, { policy, window, principal }) { let securityFlags = Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL; let uri; try { uri = Services.io.newURI(url); } catch (e) { // In the xpcshell tests, the script url is the absolute path of the test // file, which will make a malformed URI error be thrown. Add the file // scheme to see if it helps. uri = Services.io.newURI("file://" + url); } let channelOptions = { contentPolicyType: policy, securityFlags: securityFlags, uri: uri }; let prin = principal; if (!prin) { let oa = {}; if (window) { oa = window.document.nodePrincipal.originAttributes; } prin = Services.scriptSecurityManager .createCodebasePrincipal(uri, oa); } // contentPolicyType is required when specifying a principal if (!channelOptions.contentPolicyType) { channelOptions.contentPolicyType = Ci.nsIContentPolicy.TYPE_OTHER; } channelOptions.loadingPrincipal = prin; try { return NetUtil.newChannel(channelOptions); } catch (e) { // In xpcshell tests on Windows, nsExternalProtocolHandler::NewChannel() // can throw NS_ERROR_UNKNOWN_PROTOCOL if the external protocol isn't // supported by Windows, so we also need to handle the exception here if // parsing the URL above doesn't throw. return newChannelForURL("file://" + url, { policy, window, principal }); } }
// Show a warning message in the webconsole when an extension // eval request has been denied, so that the user knows about it // even if the extension doesn't report the error itself. function logAccessDeniedWarning(window, callerInfo, extensionPolicy) { // Do not log the same warning multiple times for the same document. if (deniedWarningDocuments.has(window.document)) { return; } deniedWarningDocuments.add(window.document); const {name} = extensionPolicy; // System principals have a null nodePrincipal.URI and so we use // the url from window.location.href. const reportedURI = isSystemPrincipalWindow(window) ? Services.io.newURI(window.location.href) : window.document.nodePrincipal.URI; const error = Cc["@mozilla.org/scripterror;1"].createInstance(Ci.nsIScriptError); const msg = `The extension "${name}" is not allowed to access ${reportedURI.spec}`; const innerWindowId = window.windowUtils.currentInnerWindowID; const errorFlag = 0; let {url, lineNumber} = callerInfo; const callerURI = callerInfo.url && Services.io.newURI(callerInfo.url); // callerInfo.url is not the full path to the file that called the WebExtensions // API yet (Bug 1448878), and so we associate the error to the url of the extension // manifest.json file as a fallback. if (callerURI.filePath === "/") { url = extensionPolicy.getURL("/manifest.json"); lineNumber = null; } error.initWithWindowID(msg, url, lineNumber, 0, 0, errorFlag, "webExtensions", innerWindowId); Services.console.logMessage(error); }
function createFakeAddonWindow({addonId} = {}) { let baseURI = Services.io.newURI("about:blank", null, null); let originAttributes = {addonId}; let principal = Services.scriptSecurityManager .createCodebasePrincipal(baseURI, originAttributes); let chromeWebNav = Services.appShell.createWindowlessBrowser(true); let docShell = chromeWebNav.QueryInterface(Ci.nsIInterfaceRequestor) .getInterface(Ci.nsIDocShell); docShell.createAboutBlankContentViewer(principal); let addonWindow = docShell.contentViewer.DOMDocument.defaultView; return {addonWindow, chromeWebNav}; }
/** * Returns the full path of the file with the specified name in a * platform-independent and URL-like form. */ function getFilePath(name, allowMissing = false, usePlatformPathSeparator = false) { const file = do_get_file(name, allowMissing); let path = Services.io.newFileURI(file).spec; let filePrePath = "file://"; if ("nsILocalFileWin" in Ci && file instanceof Ci.nsILocalFileWin) { filePrePath += "/"; } path = path.slice(filePrePath.length); if (usePlatformPathSeparator && path.match(/^\w:/)) { path = path.replace(/\//g, "\\"); } return path; }
webExtensionTargetPrototype._allowSource = function(source) { // Use the source.element to detect the allowed source, if any. if (source.element) { const domEl = unwrapDebuggerObjectGlobal(source.element); return (this.isExtensionWindow(domEl.ownerGlobal) || this.isExtensionWindowDescendent(domEl.ownerGlobal)); } // Fallback to check the uri if there is no source.element associated to the source. // Retrieve the first component of source.url in the form "url1 -> url2 -> ...". const url = source.url.split(" -> ").pop(); // Filter out the code introduced by evaluating code in the webconsole. if (url === "debugger eval code") { return false; } let uri; // Try to decode the url. try { uri = Services.io.newURI(url); } catch (err) { Cu.reportError(`Unexpected invalid url: ${url}`); return false; } // Filter out resource and chrome sources (which are related to the loaded internals). if (["resource", "chrome", "file"].includes(uri.scheme)) { return false; } try { const addonID = this.aps.extensionURIToAddonId(uri); return addonID == this.addonId; } catch (err) { // extensionURIToAddonId raises an exception on non-extension URLs. return false; } };
_shouldAddNewGlobalAsDebuggee: function (aGlobal) { const global = unwrapDebuggerObjectGlobal(aGlobal); try { // This will fail for non-Sandbox objects, hence the try-catch block. let metadata = Cu.getSandboxMetadata(global); if (metadata) { return metadata.addonID === this.id; } } catch (e) {} if (global instanceof Ci.nsIDOMWindow) { let id = {}; if (mapURIToAddonID(global.document.documentURIObject, id)) { return id.value === this.id; } return false; } // Check the global for a __URI__ property and then try to map that to an // add-on let uridescriptor = aGlobal.getOwnPropertyDescriptor("__URI__"); if (uridescriptor && "value" in uridescriptor && uridescriptor.value) { let uri; try { uri = Services.io.newURI(uridescriptor.value, null, null); } catch (e) { DevToolsUtils.reportException( "BrowserAddonActor.prototype._shouldAddNewGlobalAsDebuggee", new Error("Invalid URI: " + uridescriptor.value) ); return false; } let id = {}; if (mapURIToAddonID(uri, id)) { return id.value === this.id; } } return false; },
AppValidator.prototype._getManifest = function () { let manifestURL; if (this.type == "packaged") { manifestURL = this._getPackagedManifestURL(); if (!manifestURL) return Promise.resolve(null); } else if (this.type == "hosted") { manifestURL = this.location; try { Services.io.newURI(manifestURL); } catch (e) { this.error(strings.formatStringFromName("validator.invalidHostedManifestURL", [manifestURL, e.message], 2)); return Promise.resolve(null); } } else { this.error(strings.formatStringFromName("validator.invalidProjectType", [this.type], 1)); return Promise.resolve(null); } return this._fetchManifest(manifestURL); };
/** * Resolve a URI back to physical file. * * Of course, this works only for URIs pointing to local resources. * * @param uri * URI to resolve * @return * resolved nsIURI */ function resolveURIToLocalPath(uri) { let resolved; switch (uri.scheme) { case "jar": case "file": return uri; case "chrome": resolved = Cc["@mozilla.org/chrome/chrome-registry;1"] .getService(Ci.nsIChromeRegistry).convertChromeURL(uri); return resolveURIToLocalPath(resolved); case "resource": resolved = Cc["@mozilla.org/network/protocol;1?name=resource"] .getService(Ci.nsIResProtocolHandler).resolveURI(uri); uri = Services.io.newURI(resolved); return resolveURIToLocalPath(uri); default: return null; } }
/** * Restore the default bookmarks for the current profile */ function restoreDefaultBookmarks() { const TOPIC_BOOKMARKS_RESTORE_SUCCESS = "bookmarks-restore-success"; const BOOKMARKS_RESOURCE = "resource:///defaults/profile/bookmarks.html"; // In theory, could take a long time to finish. In practice never seems to. const BOOKMARKS_TIMEOUT = 10000; // Set up the observer -- we're only checking for success here, so we'll simply // time out and throw on failure. It makes the code much clearer than handling // finished state and success state separately. var importObserver = { observe: function (aSubject, aTopic, aData) { if (aTopic === TOPIC_BOOKMARKS_RESTORE_SUCCESS) this.success = true; }, success: false } services.obs.addObserver(importObserver, TOPIC_BOOKMARKS_RESTORE_SUCCESS, false); try { // newURI requires all params to be supplied, even if undefined. var bookmarksURI = services.io.newURI(BOOKMARKS_RESOURCE, undefined, undefined); // Fire off the import services.placesImportExport.importHTMLFromURI(bookmarksURI, true); // Wait for it to be finished--the observer above will flip this flag driver.waitFor(function () { return importObserver.success; }, "Default bookmarks have finished importing", BOOKMARKS_TIMEOUT); } finally { // Whatever happens, remove the observer afterwards services.obs.removeObserver(importObserver, TOPIC_BOOKMARKS_RESTORE_SUCCESS); } }
return new Promise((resolve, reject) => { try { uri = Services.io.newURI(uri, null, null); } catch (e) { reject(e); } NetUtil.asyncFetch({ uri, loadUsingSystemPrincipal: true, }, (stream, status, req) => { if (!components.isSuccessCode(status)) { reject(new Error("Request failed with status code = " + status + " after NetUtil.asyncFetch for url = " + uri)); return; } let source = NetUtil.readInputStreamToString(stream, stream.available()); stream.close(); resolve(source); }); });
/** * Save the screenshot data to disk, returning a promise which is resolved on * completion. * * @param object image * The image object that was sent from the server. * * @return string * Response message from processing the screenshot. */ async function saveToFile(image) { let filename = image.filename; // Check there is a .png extension to filename if (!filename.match(/.png$/i)) { filename += ".png"; } const downloadsDir = await Downloads.getPreferredDownloadsDirectory(); const downloadsDirExists = await OS.File.exists(downloadsDir); if (downloadsDirExists) { // If filename is absolute, it will override the downloads directory and // still be applied as expected. filename = OS.Path.join(downloadsDir, filename); } const sourceURI = Services.io.newURI(image.data); const targetFile = new FileUtils.File(filename); // Create download and track its progress. try { const download = await Downloads.createDownload({ source: sourceURI, target: targetFile }); const list = await Downloads.getList(Downloads.ALL); // add the download to the download list in the Downloads list in the Browser UI list.add(download); // Await successful completion of the save via the download manager await download.start(); return L10N.getFormatStr("screenshotSavedToFile", filename); } catch (ex) { console.error(ex); return L10N.getFormatStr("screenshotErrorSavingToFile", filename); } }
function getHostedURL(window, location) { const ret = { value: null }; if (!location) { Services.prompt.prompt(window, Strings.GetStringFromName("importHostedApp_title"), Strings.GetStringFromName("importHostedApp_header"), ret, null, {}); location = ret.value; } if (!location) { return null; } // Clean location string and add "http://" if missing location = location.trim(); try { // Will fail if no scheme Services.io.extractScheme(location); } catch (e) { location = "http://" + location; } return location; }
newChannel: function(aURI, aLoadInfo) { let chan = Services.io.newChannelFromURIWithLoadInfo(this.uri, aLoadInfo); chan.owner = Services.scriptSecurityManager.getSystemPrincipal(); return chan; },
"use strict"; // Register about:devtools-toolbox which allows to open a devtools toolbox // in a Firefox tab or a custom html iframe in browser.html const { Ci, Cu, Cm, components } = require("chrome"); const registrar = Cm.QueryInterface(Ci.nsIComponentRegistrar); const Services = require("Services"); const { XPCOMUtils } = Cu.import("resource://gre/modules/XPCOMUtils.jsm", {}); const { nsIAboutModule } = Ci; function AboutURL() {} AboutURL.prototype = { uri: Services.io.newURI("chrome://devtools/content/framework/toolbox.xul", null, null), classDescription: "about:devtools-toolbox", classID: components.ID("11342911-3135-45a8-8d71-737a2b0ad469"), contractID: "@mozilla.org/network/protocol/about;1?what=devtools-toolbox", QueryInterface: XPCOMUtils.generateQI([nsIAboutModule]), newChannel: function(aURI, aLoadInfo) { let chan = Services.io.newChannelFromURIWithLoadInfo(this.uri, aLoadInfo); chan.owner = Services.scriptSecurityManager.getSystemPrincipal(); return chan; }, getURIFlags: function(aURI) { return nsIAboutModule.ALLOW_SCRIPT || nsIAboutModule.ENABLE_INDEXED_DB; }
function dirname(aPath) { return Services.io.newURI( ".", null, Services.io.newURI(aPath)).spec; }