110 lines
3.3 KiB
JavaScript
110 lines
3.3 KiB
JavaScript
/* 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/. */
|
|
|
|
const lazy = {};
|
|
|
|
ChromeUtils.defineESModuleGetters(lazy, {
|
|
E10SUtils: "resource://gre/modules/E10SUtils.sys.mjs",
|
|
});
|
|
|
|
const MOZ_NEWTAB_REMOTE_RENDERER_SCHEME = "moz-newtab-remote-renderer";
|
|
|
|
export class MozNewTabRemoteRendererProtocolHandler {
|
|
#getActor(loadInfo) {
|
|
try {
|
|
const browsingContext = loadInfo.browsingContext;
|
|
const globalChild = browsingContext.window.windowGlobalChild;
|
|
return globalChild.getActor("MozNewTabRemoteRendererProtocol");
|
|
} catch (e) {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* The protocol scheme handled by this handler.
|
|
*/
|
|
scheme = MOZ_NEWTAB_REMOTE_RENDERER_SCHEME;
|
|
|
|
/**
|
|
* Determines whether a given port is allowed for this protocol.
|
|
*
|
|
* @param {number} _port
|
|
* The port number to check.
|
|
* @param {string} _scheme
|
|
* The protocol scheme.
|
|
* @returns {boolean}
|
|
* Always false as this protocol doesn't use ports.
|
|
*/
|
|
allowPort(_port, _scheme) {
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Creates a new channel for handling moz-newtab-remote-renderer:// URLs.
|
|
*
|
|
* @param {nsIURI} uri
|
|
* The URI to create a channel for.
|
|
* @param {nsILoadInfo} loadInfo
|
|
* Load information containing security context.
|
|
* @returns {MozCachedOHTTPChannel}
|
|
* A new channel instance.
|
|
* @throws {Components.Exception}
|
|
* If the request is not from a valid context
|
|
*/
|
|
newChannel(uri, loadInfo) {
|
|
// Check if we're in a privileged about content process
|
|
if (
|
|
Services.appinfo.remoteType === lazy.E10SUtils.PRIVILEGEDABOUT_REMOTE_TYPE
|
|
) {
|
|
const innerChannel = Cc["@mozilla.org/network/input-stream-channel;1"]
|
|
.createInstance(Ci.nsIInputStreamChannel)
|
|
.QueryInterface(Ci.nsIChannel);
|
|
innerChannel.loadInfo = loadInfo;
|
|
innerChannel.setURI(uri);
|
|
|
|
let suspendedChannel =
|
|
Services.io.newSuspendableChannelWrapper(innerChannel);
|
|
suspendedChannel.suspend();
|
|
|
|
Promise.resolve()
|
|
.then(() => {
|
|
const actor = this.#getActor(loadInfo);
|
|
if (!actor) {
|
|
throw Components.Exception(
|
|
`${MOZ_NEWTAB_REMOTE_RENDERER_SCHEME} protocol window actor pair not registered`,
|
|
Cr.NS_ERROR_NOT_AVAILABLE
|
|
);
|
|
}
|
|
|
|
return actor.sendQuery("GetInputStream", {
|
|
uriString: uri.spec,
|
|
});
|
|
})
|
|
.then(result => {
|
|
if (result.success) {
|
|
innerChannel.contentStream = result.inputStream;
|
|
innerChannel.contentType = result.contentType;
|
|
suspendedChannel.resume();
|
|
} else {
|
|
innerChannel.cancel(Cr.NS_ERROR_FAILURE);
|
|
suspendedChannel.resume();
|
|
}
|
|
})
|
|
.catch(error => {
|
|
console.error("Failed to get input stream:", error);
|
|
innerChannel.cancel(Cr.NS_ERROR_FAILURE);
|
|
suspendedChannel.resume();
|
|
});
|
|
return suspendedChannel;
|
|
}
|
|
|
|
throw Components.Exception(
|
|
`${MOZ_NEWTAB_REMOTE_RENDERER_SCHEME} protocol only accessible from privileged about content`,
|
|
Cr.NS_ERROR_INVALID_ARG
|
|
);
|
|
}
|
|
|
|
QueryInterface = ChromeUtils.generateQI(["nsIProtocolHandler"]);
|
|
}
|