зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1499092 - move bulk of registerProtocolHandler checks into compiled code so we don't need a dedicated component in the child process, r=nika
Differential Revision: https://phabricator.services.mozilla.com/D13697 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
61cf4613b9
Коммит
7ab8abdd16
|
@ -1,2 +1,2 @@
|
|||
component {792a7e82-06a0-437c-af63-b2d12e808acc} WebContentConverter.js
|
||||
contract @mozilla.org/embeddor.implemented/web-content-handler-registrar;1 {792a7e82-06a0-437c-af63-b2d12e808acc}
|
||||
component {792a7e82-06a0-437c-af63-b2d12e808acc} WebContentConverter.js process=main
|
||||
contract @mozilla.org/embeddor.implemented/web-content-handler-registrar;1 {792a7e82-06a0-437c-af63-b2d12e808acc} process=main
|
||||
|
|
|
@ -5,135 +5,11 @@
|
|||
|
||||
ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "PrivateBrowsingUtils",
|
||||
"resource://gre/modules/PrivateBrowsingUtils.jsm");
|
||||
|
||||
function LOG(str) {
|
||||
// dump("*** " + str + "\n");
|
||||
}
|
||||
|
||||
const WCCR_CLASSID = Components.ID("{792a7e82-06a0-437c-af63-b2d12e808acc}");
|
||||
|
||||
const WCC_CLASSID = Components.ID("{db7ebf28-cc40-415f-8a51-1b111851df1e}");
|
||||
const WCC_CLASSNAME = "Web Service Handler";
|
||||
|
||||
const PREF_HANDLER_EXTERNAL_PREFIX = "network.protocol-handler.external";
|
||||
|
||||
const STRING_BUNDLE_URI = "chrome://browser/locale/feeds/subscribe.properties";
|
||||
|
||||
const NS_ERROR_MODULE_DOM = 2152923136;
|
||||
const NS_ERROR_DOM_SYNTAX_ERR = NS_ERROR_MODULE_DOM + 12;
|
||||
|
||||
const Utils = {
|
||||
makeURI(aURL, aOriginCharset, aBaseURI) {
|
||||
return Services.io.newURI(aURL, aOriginCharset, aBaseURI);
|
||||
},
|
||||
|
||||
checkAndGetURI(aURIString, aContentWindow) {
|
||||
let uri;
|
||||
try {
|
||||
let baseURI = aContentWindow.document.baseURIObject;
|
||||
uri = this.makeURI(aURIString, null, baseURI);
|
||||
} catch (ex) {
|
||||
throw NS_ERROR_DOM_SYNTAX_ERR;
|
||||
}
|
||||
|
||||
// For security reasons we reject non-http(s) urls (see bug 354316),
|
||||
// we may need to revise this once we support more content types
|
||||
if (uri.scheme != "http" && uri.scheme != "https") {
|
||||
throw this.getSecurityError(
|
||||
"Permission denied to add " + uri.spec + " as a content or protocol handler",
|
||||
aContentWindow);
|
||||
}
|
||||
|
||||
// We also reject handlers registered from a different host (see bug 402287)
|
||||
if (!["http:", "https:"].includes(aContentWindow.location.protocol) ||
|
||||
aContentWindow.location.hostname != uri.host) {
|
||||
throw this.getSecurityError(
|
||||
"Permission denied to add " + uri.spec + " as a content or protocol handler",
|
||||
aContentWindow);
|
||||
}
|
||||
|
||||
// If the uri doesn't contain '%s', it won't be a good handler
|
||||
if (!uri.spec.includes("%s"))
|
||||
throw NS_ERROR_DOM_SYNTAX_ERR;
|
||||
|
||||
return uri;
|
||||
},
|
||||
|
||||
// This list should be kept up-to-date with the spec:
|
||||
// https://html.spec.whatwg.org/multipage/system-state.html#custom-handlers
|
||||
_safeProtocols: new Set([
|
||||
"bitcoin",
|
||||
"geo",
|
||||
"im",
|
||||
"irc",
|
||||
"ircs",
|
||||
"magnet",
|
||||
"mailto",
|
||||
"mms",
|
||||
"news",
|
||||
"nntp",
|
||||
"openpgp4fpr",
|
||||
"sip",
|
||||
"sms",
|
||||
"smsto",
|
||||
"ssh",
|
||||
"tel",
|
||||
"urn",
|
||||
"webcal",
|
||||
"wtai",
|
||||
"xmpp",
|
||||
]),
|
||||
|
||||
// NB: Throws if aProtocol is not allowed.
|
||||
checkProtocolHandlerAllowed(aProtocol, aURIString, aWindowOrNull) {
|
||||
if (aProtocol.startsWith("web+")) {
|
||||
if (!/[a-z]+/.test(aProtocol.substring(4 /* web+ */))) {
|
||||
throw this.getSecurityError(
|
||||
`Permission denied to add a protocol handler for ${aProtocol}`,
|
||||
aWindowOrNull);
|
||||
}
|
||||
} else if (!this._safeProtocols.has(aProtocol)) {
|
||||
throw this.getSecurityError(
|
||||
`Permission denied to add a protocol handler for ${aProtocol}`,
|
||||
aWindowOrNull);
|
||||
}
|
||||
|
||||
// First, check to make sure this isn't already handled internally (we don't
|
||||
// want to let them take over, say "chrome").
|
||||
let handler = Services.io.getProtocolHandler(aProtocol);
|
||||
if (!(handler instanceof Ci.nsIExternalProtocolHandler)) {
|
||||
// This is handled internally, so we don't want them to register
|
||||
throw this.getSecurityError(
|
||||
`Permission denied to add ${aURIString} as a protocol handler`,
|
||||
aWindowOrNull);
|
||||
}
|
||||
|
||||
// check if it is in the black list
|
||||
let pb = Services.prefs;
|
||||
let allowed =
|
||||
pb.getBoolPref(PREF_HANDLER_EXTERNAL_PREFIX + "." + aProtocol,
|
||||
pb.getBoolPref(PREF_HANDLER_EXTERNAL_PREFIX + "-default"));
|
||||
if (!allowed) {
|
||||
throw this.getSecurityError(
|
||||
`Not allowed to register a protocol handler for ${aProtocol}`,
|
||||
aWindowOrNull);
|
||||
}
|
||||
},
|
||||
|
||||
// Return a SecurityError exception from the given Window if one is given. If
|
||||
// none is given, just return the given error string, for lack of anything
|
||||
// better.
|
||||
getSecurityError(errorString, aWindowOrNull) {
|
||||
if (!aWindowOrNull) {
|
||||
return errorString;
|
||||
}
|
||||
|
||||
return new aWindowOrNull.DOMException(errorString, "SecurityError");
|
||||
},
|
||||
};
|
||||
|
||||
function WebContentConverterRegistrar() {
|
||||
}
|
||||
|
||||
|
@ -191,8 +67,9 @@ WebContentConverterRegistrar.prototype = {
|
|||
for (let i = 0; i < handlers.length; i++) {
|
||||
try { // We only want to test web handlers
|
||||
let handler = handlers.queryElementAt(i, Ci.nsIWebHandlerApp);
|
||||
if (handler.uriTemplate == aURITemplate)
|
||||
if (handler.uriTemplate == aURITemplate) {
|
||||
return true;
|
||||
}
|
||||
} catch (e) { /* it wasn't a web handler */ }
|
||||
}
|
||||
return false;
|
||||
|
@ -201,79 +78,67 @@ WebContentConverterRegistrar.prototype = {
|
|||
/**
|
||||
* See nsIWebContentHandlerRegistrar
|
||||
*/
|
||||
registerProtocolHandler(aProtocol, aURIString, aTitle, aBrowserOrWindow) {
|
||||
registerProtocolHandler(aProtocol, aURI, aTitle, aDocumentURI, aBrowserOrWindow) {
|
||||
aProtocol = (aProtocol || "").toLowerCase();
|
||||
LOG("registerProtocolHandler(" + aProtocol + "," + aURIString + "," + aTitle + ")");
|
||||
let haveWindow = (aBrowserOrWindow instanceof Ci.nsIDOMWindow);
|
||||
let uri;
|
||||
if (haveWindow) {
|
||||
uri = Utils.checkAndGetURI(aURIString, aBrowserOrWindow);
|
||||
} else {
|
||||
// aURIString must not be a relative URI.
|
||||
uri = Utils.makeURI(aURIString, null);
|
||||
if (!aURI || !aDocumentURI) {
|
||||
return;
|
||||
}
|
||||
|
||||
let browser = aBrowserOrWindow; // This is the e10s case.
|
||||
if (aBrowserOrWindow instanceof Ci.nsIDOMWindow) {
|
||||
// In the non-e10s case, grab the browser off the same-process window.
|
||||
let rootDocShell = aBrowserOrWindow.docShell.sameTypeRootTreeItem;
|
||||
browser = rootDocShell.QueryInterface(Ci.nsIDocShell).chromeEventHandler;
|
||||
}
|
||||
|
||||
let browserWindow = browser.ownerGlobal;
|
||||
try {
|
||||
browserWindow.navigator.checkProtocolHandlerAllowed(aProtocol, aURI, aDocumentURI);
|
||||
} catch (ex) {
|
||||
// We should have already shown the user an error.
|
||||
return;
|
||||
}
|
||||
|
||||
// If the protocol handler is already registered, just return early.
|
||||
if (this._protocolHandlerRegistered(aProtocol, uri.spec)) {
|
||||
if (this._protocolHandlerRegistered(aProtocol, aURI.spec)) {
|
||||
return;
|
||||
}
|
||||
|
||||
let browser;
|
||||
if (haveWindow) {
|
||||
let browserWindow =
|
||||
this._getBrowserWindowForContentWindow(aBrowserOrWindow);
|
||||
browser = this._getBrowserForContentWindow(browserWindow,
|
||||
aBrowserOrWindow);
|
||||
} else {
|
||||
browser = aBrowserOrWindow;
|
||||
}
|
||||
if (PrivateBrowsingUtils.isBrowserPrivate(browser)) {
|
||||
// Inside the private browsing mode, we don't want to alert the user to save
|
||||
// a protocol handler. We log it to the error console so that web developers
|
||||
// would have some way to tell what's going wrong.
|
||||
Services.console.
|
||||
logStringMessage("Web page denied access to register a protocol handler inside private browsing mode");
|
||||
return;
|
||||
}
|
||||
|
||||
Utils.checkProtocolHandlerAllowed(aProtocol, aURIString,
|
||||
haveWindow ? aBrowserOrWindow : null);
|
||||
|
||||
// Now Ask the user and provide the proper callback
|
||||
let message = this._getFormattedString("addProtocolHandlerMessage",
|
||||
[uri.host, aProtocol]);
|
||||
[aURI.host, aProtocol]);
|
||||
|
||||
let notificationIcon = uri.prePath + "/favicon.ico";
|
||||
let notificationIcon = aURI.prePath + "/favicon.ico";
|
||||
let notificationValue = "Protocol Registration: " + aProtocol;
|
||||
let addButton = {
|
||||
label: this._getString("addProtocolHandlerAddButton"),
|
||||
accessKey: this._getString("addProtocolHandlerAddButtonAccesskey"),
|
||||
protocolInfo: { protocol: aProtocol, uri: uri.spec, name: aTitle },
|
||||
protocolInfo: { protocol: aProtocol, uri: aURI.spec, name: aTitle },
|
||||
|
||||
callback(aNotification, aButtonInfo) {
|
||||
let protocol = aButtonInfo.protocolInfo.protocol;
|
||||
let name = aButtonInfo.protocolInfo.name;
|
||||
let protocol = aButtonInfo.protocolInfo.protocol;
|
||||
let name = aButtonInfo.protocolInfo.name;
|
||||
|
||||
let handler = Cc["@mozilla.org/uriloader/web-handler-app;1"].
|
||||
createInstance(Ci.nsIWebHandlerApp);
|
||||
handler.name = name;
|
||||
handler.uriTemplate = aButtonInfo.protocolInfo.uri;
|
||||
let handler = Cc["@mozilla.org/uriloader/web-handler-app;1"].
|
||||
createInstance(Ci.nsIWebHandlerApp);
|
||||
handler.name = name;
|
||||
handler.uriTemplate = aButtonInfo.protocolInfo.uri;
|
||||
|
||||
let eps = Cc["@mozilla.org/uriloader/external-protocol-service;1"].
|
||||
getService(Ci.nsIExternalProtocolService);
|
||||
let handlerInfo = eps.getProtocolHandlerInfo(protocol);
|
||||
handlerInfo.possibleApplicationHandlers.appendElement(handler);
|
||||
let eps = Cc["@mozilla.org/uriloader/external-protocol-service;1"].
|
||||
getService(Ci.nsIExternalProtocolService);
|
||||
let handlerInfo = eps.getProtocolHandlerInfo(protocol);
|
||||
handlerInfo.possibleApplicationHandlers.appendElement(handler);
|
||||
|
||||
// Since the user has agreed to add a new handler, chances are good
|
||||
// that the next time they see a handler of this type, they're going
|
||||
// to want to use it. Reset the handlerInfo to ask before the next
|
||||
// use.
|
||||
handlerInfo.alwaysAskBeforeHandling = true;
|
||||
// Since the user has agreed to add a new handler, chances are good
|
||||
// that the next time they see a handler of this type, they're going
|
||||
// to want to use it. Reset the handlerInfo to ask before the next
|
||||
// use.
|
||||
handlerInfo.alwaysAskBeforeHandling = true;
|
||||
|
||||
let hs = Cc["@mozilla.org/uriloader/handler-service;1"].
|
||||
getService(Ci.nsIHandlerService);
|
||||
hs.store(handlerInfo);
|
||||
},
|
||||
let hs = Cc["@mozilla.org/uriloader/handler-service;1"].
|
||||
getService(Ci.nsIHandlerService);
|
||||
hs.store(handlerInfo);
|
||||
},
|
||||
};
|
||||
let notificationBox = browser.getTabBrowser().getNotificationBox(browser);
|
||||
notificationBox.appendNotification(message,
|
||||
|
@ -283,60 +148,6 @@ WebContentConverterRegistrar.prototype = {
|
|||
[addButton]);
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the browser chrome window in which the content window is in
|
||||
*/
|
||||
_getBrowserWindowForContentWindow(aContentWindow) {
|
||||
return aContentWindow.docShell.rootTreeItem.domWindow
|
||||
.wrappedJSObject;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the <xul:browser> element associated with the given content
|
||||
* window.
|
||||
*
|
||||
* @param aBrowserWindow
|
||||
* The browser window in which the content window is in.
|
||||
* @param aContentWindow
|
||||
* The content window. It's possible to pass a child content window
|
||||
* (i.e. the content window of a frame/iframe).
|
||||
*/
|
||||
_getBrowserForContentWindow(aBrowserWindow, aContentWindow) {
|
||||
// This depends on pseudo APIs of browser.js and tabbrowser.xml
|
||||
aContentWindow = aContentWindow.top;
|
||||
return aBrowserWindow.gBrowser.browsers.find((browser) =>
|
||||
browser.contentWindow == aContentWindow);
|
||||
},
|
||||
|
||||
classID: WCCR_CLASSID,
|
||||
|
||||
/**
|
||||
* See nsISupports
|
||||
*/
|
||||
QueryInterface: ChromeUtils.generateQI([Ci.nsIWebContentHandlerRegistrar]),
|
||||
};
|
||||
|
||||
function WebContentConverterRegistrarContent() {
|
||||
}
|
||||
|
||||
WebContentConverterRegistrarContent.prototype = {
|
||||
registerProtocolHandler(aProtocol, aURIString, aTitle, aBrowserOrWindow) {
|
||||
aProtocol = (aProtocol || "").toLowerCase();
|
||||
// aBrowserOrWindow must be a window.
|
||||
let messageManager = aBrowserOrWindow.docShell
|
||||
.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsITabChild)
|
||||
.messageManager;
|
||||
|
||||
let uri = Utils.checkAndGetURI(aURIString, aBrowserOrWindow);
|
||||
Utils.checkProtocolHandlerAllowed(aProtocol, aURIString, aBrowserOrWindow);
|
||||
|
||||
messageManager.sendAsyncMessage("WCCR:registerProtocolHandler",
|
||||
{ protocol: aProtocol,
|
||||
uri: uri.spec,
|
||||
title: aTitle });
|
||||
},
|
||||
|
||||
classID: WCCR_CLASSID,
|
||||
|
||||
/**
|
||||
|
@ -346,6 +157,4 @@ WebContentConverterRegistrarContent.prototype = {
|
|||
};
|
||||
|
||||
this.NSGetFactory =
|
||||
(Services.appinfo.processType === Services.appinfo.PROCESS_TYPE_CONTENT) ?
|
||||
XPCOMUtils.generateNSGetFactory([WebContentConverterRegistrarContent]) :
|
||||
XPCOMUtils.generateNSGetFactory([WebContentConverterRegistrar]);
|
||||
XPCOMUtils.generateNSGetFactory([WebContentConverterRegistrar]);
|
||||
|
|
|
@ -51,8 +51,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=402788
|
|||
is(testRegisterHandler(true, "fweb+oo", "http://remotehost:8888/%s", "Foo handler"), false, "registering a web+foo protocol handler with a different host should not work");
|
||||
|
||||
// restriction to http(s) for the uri of the handler (bug 401343)
|
||||
// https should work (http already tested in the generic case)
|
||||
is(testRegisterHandler(true, "web+foo", "https://mochi.test:8888/%s", "Foo handler"), true, "registering a web+foo protocol handler with https scheme should work");
|
||||
// http is already tested in the generic case
|
||||
// ftp should not work
|
||||
is(testRegisterHandler(true, "web+foo", "ftp://mochi.test:8888/%s", "Foo handler"), false, "registering a web+foo protocol handler with ftp scheme should not work");
|
||||
// chrome should not work
|
||||
|
|
|
@ -403,7 +403,6 @@ XPCOMUtils.defineLazyModuleGetters(this, {
|
|||
DateTimePickerParent: "resource://gre/modules/DateTimePickerParent.jsm",
|
||||
Discovery: "resource:///modules/Discovery.jsm",
|
||||
ExtensionsUI: "resource:///modules/ExtensionsUI.jsm",
|
||||
Feeds: "resource:///modules/Feeds.jsm",
|
||||
FileSource: "resource://gre/modules/L10nRegistry.jsm",
|
||||
FormValidationHandler: "resource:///modules/FormValidationHandler.jsm",
|
||||
FxAccounts: "resource://gre/modules/FxAccounts.jsm",
|
||||
|
@ -532,7 +531,6 @@ const listeners = {
|
|||
"RemoteLogins:removeLogin": ["LoginManagerParent"],
|
||||
"RemoteLogins:insecureLoginFormPresent": ["LoginManagerParent"],
|
||||
// PLEASE KEEP THIS LIST IN SYNC WITH THE MOBILE LISTENERS IN BrowserCLH.js
|
||||
"WCCR:registerProtocolHandler": ["Feeds"],
|
||||
"rtcpeer:CancelRequest": ["webrtcUI"],
|
||||
"rtcpeer:Request": ["webrtcUI"],
|
||||
"webrtc:CancelRequest": ["webrtcUI"],
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
/* 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";
|
||||
|
||||
var EXPORTED_SYMBOLS = [ "Feeds" ];
|
||||
|
||||
var Feeds = {
|
||||
// Listeners are added in nsBrowserGlue.js
|
||||
receiveMessage(aMessage) {
|
||||
let data = aMessage.data;
|
||||
switch (aMessage.name) {
|
||||
case "WCCR:registerProtocolHandler": {
|
||||
let registrar = Cc["@mozilla.org/embeddor.implemented/web-content-handler-registrar;1"].
|
||||
getService(Ci.nsIWebContentHandlerRegistrar);
|
||||
registrar.registerProtocolHandler(data.protocol, data.uri, data.title,
|
||||
aMessage.target);
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
|
@ -136,7 +136,6 @@ EXTRA_JS_MODULES += [
|
|||
'Discovery.jsm',
|
||||
'ExtensionsUI.jsm',
|
||||
'FaviconLoader.jsm',
|
||||
'Feeds.jsm',
|
||||
'FormValidationHandler.jsm',
|
||||
'HomePage.jsm',
|
||||
'LaterRun.jsm',
|
||||
|
|
|
@ -74,6 +74,10 @@
|
|||
#include "nsIPresentationService.h"
|
||||
#include "nsIScriptError.h"
|
||||
|
||||
#include "nsIExternalProtocolHandler.h"
|
||||
#include "TabChild.h"
|
||||
#include "URIUtils.h"
|
||||
|
||||
#include "mozilla/dom/MediaDevices.h"
|
||||
#include "MediaManager.h"
|
||||
|
||||
|
@ -821,27 +825,179 @@ void Navigator::RegisterContentHandler(const nsAString& aMIMEType,
|
|||
const nsAString& aTitle,
|
||||
ErrorResult& aRv) {}
|
||||
|
||||
void Navigator::RegisterProtocolHandler(const nsAString& aProtocol,
|
||||
const nsAString& aURI,
|
||||
const nsAString& aTitle,
|
||||
ErrorResult& aRv) {
|
||||
if (!mWindow || !mWindow->GetOuterWindow() || !mWindow->GetDocShell()) {
|
||||
// This list should be kept up-to-date with the spec:
|
||||
// https://html.spec.whatwg.org/multipage/system-state.html#custom-handlers
|
||||
static const char* const kSafeSchemes[] = {
|
||||
"bitcoin", "geo", "im", "irc", "ircs", "magnet", "mailto",
|
||||
"mms", "news", "nntp", "openpgp4fpr", "sip", "sms", "smsto",
|
||||
"ssh", "tel", "urn", "webcal", "wtai", "xmpp"};
|
||||
|
||||
void Navigator::CheckProtocolHandlerAllowed(const nsAString& aScheme,
|
||||
nsIURI* aHandlerURI,
|
||||
nsIURI* aDocumentURI,
|
||||
ErrorResult& aRv) {
|
||||
auto raisePermissionDeniedHandler = [&] {
|
||||
nsAutoCString spec;
|
||||
aHandlerURI->GetSpec(spec);
|
||||
nsPrintfCString message("Permission denied to add %s as a protocol handler",
|
||||
spec.get());
|
||||
aRv.ThrowDOMException(NS_ERROR_DOM_SECURITY_ERR, message);
|
||||
};
|
||||
|
||||
auto raisePermissionDeniedScheme = [&] {
|
||||
nsPrintfCString message(
|
||||
"Permission denied to add a protocol handler for %s",
|
||||
NS_ConvertUTF16toUTF8(aScheme).get());
|
||||
aRv.ThrowDOMException(NS_ERROR_DOM_SECURITY_ERR, message);
|
||||
};
|
||||
|
||||
if (!aDocumentURI || !aHandlerURI) {
|
||||
aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mWindow->IsSecureContext() && mWindow->GetDoc()) {
|
||||
mWindow->GetDoc()->WarnOnceAbout(
|
||||
nsIDocument::eRegisterProtocolHandlerInsecure);
|
||||
nsCString spec;
|
||||
aHandlerURI->GetSpec(spec);
|
||||
// If the uri doesn't contain '%s', it won't be a good handler - the %s
|
||||
// gets replaced with the handled URI.
|
||||
if (!FindInReadable(NS_LITERAL_CSTRING("%s"), spec)) {
|
||||
aRv.ThrowDOMException(NS_ERROR_DOM_SYNTAX_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
// For security reasons we reject non-http(s) urls (see bug 354316),
|
||||
nsAutoCString docScheme;
|
||||
nsAutoCString handlerScheme;
|
||||
aDocumentURI->GetScheme(docScheme);
|
||||
aHandlerURI->GetScheme(handlerScheme);
|
||||
if ((!docScheme.EqualsLiteral("https") && !docScheme.EqualsLiteral("http")) ||
|
||||
(!handlerScheme.EqualsLiteral("https") &&
|
||||
!handlerScheme.EqualsLiteral("http"))) {
|
||||
raisePermissionDeniedHandler();
|
||||
return;
|
||||
}
|
||||
|
||||
// Should be same-origin:
|
||||
nsAutoCString handlerHost;
|
||||
aHandlerURI->GetHostPort(handlerHost);
|
||||
nsAutoCString documentHost;
|
||||
aDocumentURI->GetHostPort(documentHost);
|
||||
if (!handlerHost.Equals(documentHost) || !handlerScheme.Equals(docScheme)) {
|
||||
raisePermissionDeniedHandler();
|
||||
return;
|
||||
}
|
||||
|
||||
// Having checked the handler URI, check the scheme:
|
||||
nsAutoCString scheme;
|
||||
ToLowerCase(NS_ConvertUTF16toUTF8(aScheme), scheme);
|
||||
if (StringBeginsWith(scheme, NS_LITERAL_CSTRING("web+"))) {
|
||||
// Check for non-ascii
|
||||
nsReadingIterator<char> iter;
|
||||
nsReadingIterator<char> iterEnd;
|
||||
auto remainingScheme = Substring(scheme, 4 /* web+ */);
|
||||
remainingScheme.BeginReading(iter);
|
||||
remainingScheme.EndReading(iterEnd);
|
||||
// Scheme suffix must be non-empty
|
||||
if (iter == iterEnd) {
|
||||
raisePermissionDeniedScheme();
|
||||
return;
|
||||
}
|
||||
for (; iter != iterEnd; iter++) {
|
||||
if (*iter < 'a' || *iter > 'z') {
|
||||
raisePermissionDeniedScheme();
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
bool matches = false;
|
||||
for (const char* safeScheme : kSafeSchemes) {
|
||||
if (scheme.Equals(safeScheme)) {
|
||||
matches = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!matches) {
|
||||
raisePermissionDeniedScheme();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIProtocolHandler> handler;
|
||||
nsCOMPtr<nsIIOService> io = services::GetIOService();
|
||||
if (NS_FAILED(
|
||||
io->GetProtocolHandler(scheme.get(), getter_AddRefs(handler)))) {
|
||||
raisePermissionDeniedScheme();
|
||||
return;
|
||||
}
|
||||
|
||||
// Check to make sure this isn't already handled internally (we don't
|
||||
// want to let them take over, say "chrome"). In theory, the checks above
|
||||
// should have already taken care of this.
|
||||
nsCOMPtr<nsIExternalProtocolHandler> externalHandler =
|
||||
do_QueryInterface(handler);
|
||||
MOZ_RELEASE_ASSERT(
|
||||
externalHandler,
|
||||
"We should never allow overriding a builtin protocol handler");
|
||||
|
||||
// check if we have prefs set saying not to add this.
|
||||
bool defaultExternal =
|
||||
Preferences::GetBool("network.protocol-handler.external-default");
|
||||
nsPrintfCString specificPref("network.protocol-handler.external.%s",
|
||||
scheme.get());
|
||||
if (!Preferences::GetBool(specificPref.get(), defaultExternal)) {
|
||||
raisePermissionDeniedScheme();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void Navigator::RegisterProtocolHandler(const nsAString& aScheme,
|
||||
const nsAString& aURI,
|
||||
const nsAString& aTitle,
|
||||
ErrorResult& aRv) {
|
||||
if (!mWindow || !mWindow->GetOuterWindow() || !mWindow->GetDocShell() ||
|
||||
!mWindow->GetDoc()) {
|
||||
return;
|
||||
}
|
||||
nsCOMPtr<nsILoadContext> loadContext = do_GetInterface(mWindow);
|
||||
if (loadContext->UsePrivateBrowsing()) {
|
||||
// If we're a private window, don't alert the user or webpage. We log to the
|
||||
// console so that web developers have some way to tell what's going wrong.
|
||||
nsContentUtils::ReportToConsole(
|
||||
nsIScriptError::warningFlag, NS_LITERAL_CSTRING("DOM"),
|
||||
mWindow->GetDoc(), nsContentUtils::eDOM_PROPERTIES,
|
||||
"RegisterProtocolHandlerPrivateBrowsingWarning");
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDocument> doc = mWindow->GetDoc();
|
||||
if (!mWindow->IsSecureContext()) {
|
||||
doc->WarnOnceAbout(nsIDocument::eRegisterProtocolHandlerInsecure);
|
||||
}
|
||||
|
||||
// Determine if doc is allowed to assign this handler
|
||||
nsIURI* docURI = doc->GetDocumentURIObject();
|
||||
nsCOMPtr<nsIURI> handlerURI;
|
||||
NS_NewURI(getter_AddRefs(handlerURI), NS_ConvertUTF16toUTF8(aURI),
|
||||
doc->GetDocumentCharacterSet(), docURI);
|
||||
CheckProtocolHandlerAllowed(aScheme, handlerURI, docURI, aRv);
|
||||
if (aRv.Failed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (XRE_IsContentProcess()) {
|
||||
nsAutoString scheme(aScheme);
|
||||
nsAutoString title(aTitle);
|
||||
RefPtr<TabChild> tabChild = TabChild::GetFrom(mWindow);
|
||||
tabChild->SendRegisterProtocolHandler(scheme, handlerURI, title, docURI);
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIWebContentHandlerRegistrar> registrar =
|
||||
do_GetService(NS_WEBCONTENTHANDLERREGISTRAR_CONTRACTID);
|
||||
if (!registrar) {
|
||||
return;
|
||||
if (registrar) {
|
||||
aRv = registrar->RegisterProtocolHandler(aScheme, handlerURI, aTitle,
|
||||
docURI, mWindow->GetOuterWindow());
|
||||
}
|
||||
|
||||
aRv = registrar->RegisterProtocolHandler(aProtocol, aURI, aTitle,
|
||||
mWindow->GetOuterWindow());
|
||||
}
|
||||
|
||||
Geolocation* Navigator::GetGeolocation(ErrorResult& aRv) {
|
||||
|
|
|
@ -113,6 +113,9 @@ class Navigator final : public nsISupports, public nsWrapperCache {
|
|||
void GetUserAgent(nsAString& aUserAgent, CallerType aCallerType,
|
||||
ErrorResult& aRv) const;
|
||||
bool OnLine();
|
||||
void CheckProtocolHandlerAllowed(const nsAString& aScheme,
|
||||
nsIURI* aHandlerURI, nsIURI* aDocumentURI,
|
||||
ErrorResult& aRv);
|
||||
void RegisterProtocolHandler(const nsAString& aScheme, const nsAString& aURL,
|
||||
const nsAString& aTitle, ErrorResult& aRv);
|
||||
void RegisterContentHandler(const nsAString& aMIMEType, const nsAString& aURL,
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
interface nsIURI;
|
||||
|
||||
/**
|
||||
* nsIWebContentHandlerRegistrar
|
||||
*
|
||||
|
@ -26,8 +28,9 @@ interface nsIWebContentHandlerRegistrar : nsISupports
|
|||
* content window from which the method has been called.
|
||||
*/
|
||||
void registerProtocolHandler(in AString protocol,
|
||||
in AString uri,
|
||||
in nsIURI uri,
|
||||
in AString title,
|
||||
in nsIURI documentURI,
|
||||
in nsISupports windowOrBrowser);
|
||||
/**
|
||||
* Removes a registered protocol handler
|
||||
|
|
|
@ -88,6 +88,7 @@ using mozilla::FontRange from "ipc/nsGUIEventIPC.h";
|
|||
using mozilla::a11y::IAccessibleHolder from "mozilla/a11y/IPCTypes.h";
|
||||
using mozilla::OriginAttributes from "mozilla/ipc/BackgroundUtils.h";
|
||||
using mozilla::dom::BrowsingContextId from "mozilla/dom/ipc/IdType.h";
|
||||
using refcounted class nsIURI from "mozilla/ipc/URIUtils.h";
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
@ -521,6 +522,9 @@ parent:
|
|||
|
||||
async SetHasBeforeUnload(bool aHasBeforeUnload);
|
||||
|
||||
async RegisterProtocolHandler(nsString scheme, nsIURI handlerURI, nsString title,
|
||||
nsIURI documentURI);
|
||||
|
||||
child:
|
||||
async NativeSynthesisResponse(uint64_t aObserverId, nsCString aResponse);
|
||||
|
||||
|
|
|
@ -63,6 +63,7 @@
|
|||
#include "nsIURI.h"
|
||||
#include "nsIWindowWatcher.h"
|
||||
#include "nsIWebBrowserChrome.h"
|
||||
#include "nsIWebContentHandlerRegistrar.h"
|
||||
#include "nsIXULBrowserWindow.h"
|
||||
#include "nsIXULWindow.h"
|
||||
#include "nsViewManager.h"
|
||||
|
@ -2099,6 +2100,19 @@ mozilla::ipc::IPCResult TabParent::RecvSetHasBeforeUnload(
|
|||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult TabParent::RecvRegisterProtocolHandler(
|
||||
const nsString& aScheme, nsIURI* aHandlerURI, const nsString& aTitle,
|
||||
nsIURI* aDocURI) {
|
||||
nsCOMPtr<nsIWebContentHandlerRegistrar> registrar =
|
||||
do_GetService(NS_WEBCONTENTHANDLERREGISTRAR_CONTRACTID);
|
||||
if (registrar) {
|
||||
registrar->RegisterProtocolHandler(aScheme, aHandlerURI, aTitle, aDocURI,
|
||||
mFrameElement);
|
||||
}
|
||||
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
bool TabParent::HandleQueryContentEvent(WidgetQueryContentEvent& aEvent) {
|
||||
nsCOMPtr<nsIWidget> widget = GetWidget();
|
||||
if (!widget) {
|
||||
|
|
|
@ -156,6 +156,10 @@ class TabParent final : public PBrowserParent,
|
|||
virtual mozilla::ipc::IPCResult RecvSetHasBeforeUnload(
|
||||
const bool& aHasBeforeUnload) override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult RecvRegisterProtocolHandler(
|
||||
const nsString& aScheme, nsIURI* aHandlerURI, const nsString& aTitle,
|
||||
nsIURI* aDocURI) override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult RecvBrowserFrameOpenWindow(
|
||||
PBrowserParent* aOpener, const nsString& aURL, const nsString& aName,
|
||||
const nsString& aFeatures,
|
||||
|
|
|
@ -344,6 +344,8 @@ InvalidKeyframePropertyValue=Keyframe property value “%1$S” is invalid accor
|
|||
ReadableStreamReadingFailed=Failed to read data from the ReadableStream: “%S”.
|
||||
# LOCALIZATION NOTE: Do not translate "registerProtocolHandler".
|
||||
RegisterProtocolHandlerInsecureWarning=Use of the registerProtocolHandler for insecure connections will be removed in version 62.
|
||||
# LOCALIZATION NOTE: Do not translate "registerProtocolHandler"
|
||||
RegisterProtocolHandlerPrivateBrowsingWarning=Can’t use registerProtocolHandler inside private browsing mode.
|
||||
MixedDisplayObjectSubrequestWarning=Loading insecure content within a plugin embedded in a secure connection is going to be removed.
|
||||
MotionEventWarning=Use of the motion sensor is deprecated.
|
||||
OrientationEventWarning=Use of the orientation sensor is deprecated.
|
||||
|
|
|
@ -23,6 +23,8 @@
|
|||
* and create derivative works of this document.
|
||||
*/
|
||||
|
||||
interface URI;
|
||||
|
||||
// http://www.whatwg.org/specs/web-apps/current-work/#the-navigator-object
|
||||
[HeaderFile="Navigator.h"]
|
||||
interface Navigator {
|
||||
|
@ -80,6 +82,8 @@ interface NavigatorOnLine {
|
|||
[NoInterfaceObject]
|
||||
interface NavigatorContentUtils {
|
||||
// content handler registration
|
||||
[Throws, ChromeOnly]
|
||||
void checkProtocolHandlerAllowed(DOMString scheme, URI handlerURI, URI documentURI);
|
||||
[Throws, Func="nsGlobalWindowInner::RegisterProtocolHandlerAllowedForContext"]
|
||||
void registerProtocolHandler(DOMString scheme, DOMString url, DOMString title);
|
||||
[Pref="dom.registerContentHandler.enabled", Throws]
|
||||
|
|
|
@ -1,180 +0,0 @@
|
|||
[protocol.https.html]
|
||||
[a url argument pointing to a different domain name, without %s should throw SYNTAX_ERR]
|
||||
expected: FAIL
|
||||
|
||||
[a protocol argument containing non-alphanumeric characters (like a cyrillic “а”) should throw SYNTAX_ERR]
|
||||
expected:
|
||||
if os == "android": FAIL
|
||||
|
||||
[attempting to override the mocha protocol should throw SECURITY_ERR]
|
||||
expected:
|
||||
if os == "android": FAIL
|
||||
|
||||
[attempting to override the res protocol should throw SECURITY_ERR]
|
||||
expected:
|
||||
if os == "android": FAIL
|
||||
|
||||
[attempting to override the view-source protocol should throw SECURITY_ERR]
|
||||
expected:
|
||||
if os == "android": FAIL
|
||||
|
||||
[attempting to override the blob protocol should throw SECURITY_ERR]
|
||||
expected:
|
||||
if os == "android": FAIL
|
||||
|
||||
[%s instead of domain name should throw SECURITY_ERR]
|
||||
expected:
|
||||
if os == "android": FAIL
|
||||
|
||||
[a protocol argument containing :// should throw SYNTAX_ERR]
|
||||
expected:
|
||||
if os == "android": FAIL
|
||||
|
||||
[attempting to override the opera protocol should throw SECURITY_ERR]
|
||||
expected:
|
||||
if os == "android": FAIL
|
||||
|
||||
[attempting to override the cid protocol should throw SECURITY_ERR]
|
||||
expected:
|
||||
if os == "android": FAIL
|
||||
|
||||
[a url argument pointing to a non-http[s\] scheme should throw SECURITY_ERR due to not being of the same origin]
|
||||
expected:
|
||||
if os == "android": FAIL
|
||||
|
||||
[a protocol argument containing an unrecognized scheme should throw SECURITY_ERR]
|
||||
expected:
|
||||
if os == "android": FAIL
|
||||
|
||||
[a url argument pointing to a different domain name should throw SECURITY_ERR (2)]
|
||||
expected:
|
||||
if os == "android": FAIL
|
||||
|
||||
[attempting to override the javascript protocol should throw SECURITY_ERR]
|
||||
expected:
|
||||
if os == "android": FAIL
|
||||
|
||||
[attempting to override the operamail protocol should throw SECURITY_ERR]
|
||||
expected:
|
||||
if os == "android": FAIL
|
||||
|
||||
[a url argument without %s (but with %) should throw SYNTAX_ERR]
|
||||
expected:
|
||||
if os == "android": FAIL
|
||||
|
||||
[a protocol argument containing : should throw SYNTAX_ERR]
|
||||
expected:
|
||||
if os == "android": FAIL
|
||||
|
||||
[attempting to override the http protocol should throw SECURITY_ERR]
|
||||
expected:
|
||||
if os == "android": FAIL
|
||||
|
||||
[an empty url argument should throw SYNTAX_ERR]
|
||||
expected:
|
||||
if os == "android": FAIL
|
||||
|
||||
[attempting to override the wyciwyg protocol should throw SECURITY_ERR]
|
||||
expected:
|
||||
if os == "android": FAIL
|
||||
|
||||
[a protocol argument containing a backspace character should throw SYNTAX_ERR]
|
||||
expected:
|
||||
if os == "android": FAIL
|
||||
|
||||
[attempting to override the tcl protocol should throw SECURITY_ERR]
|
||||
expected:
|
||||
if os == "android": FAIL
|
||||
|
||||
[a url argument without %s should throw SYNTAX_ERR]
|
||||
expected:
|
||||
if os == "android": FAIL
|
||||
|
||||
[attempting to override the about protocol should throw SECURITY_ERR]
|
||||
expected:
|
||||
if os == "android": FAIL
|
||||
|
||||
[attempting to override the chrome protocol should throw SECURITY_ERR]
|
||||
expected:
|
||||
if os == "android": FAIL
|
||||
|
||||
[a protocol argument containing http:// should throw SYNTAX_ERR]
|
||||
expected:
|
||||
if os == "android": FAIL
|
||||
|
||||
[attempting to override the wss protocol should throw SECURITY_ERR]
|
||||
expected:
|
||||
if os == "android": FAIL
|
||||
|
||||
[a protocol argument containing a LF character should throw SYNTAX_ERR]
|
||||
expected:
|
||||
if os == "android": FAIL
|
||||
|
||||
[attempting to override the mid protocol should throw SECURITY_ERR]
|
||||
expected:
|
||||
if os == "android": FAIL
|
||||
|
||||
[a url argument pointing to a different domain name should throw SECURITY_ERR (3)]
|
||||
expected:
|
||||
if os == "android": FAIL
|
||||
|
||||
[attempting to override the ftp protocol should throw SECURITY_ERR]
|
||||
expected:
|
||||
if os == "android": FAIL
|
||||
|
||||
[%s instead of subdomain name should throw SECURITY_ERR]
|
||||
expected:
|
||||
if os == "android": FAIL
|
||||
|
||||
[attempting to override the file protocol should throw SECURITY_ERR]
|
||||
expected:
|
||||
if os == "android": FAIL
|
||||
|
||||
[attempting to override the vbscript protocol should throw SECURITY_ERR]
|
||||
expected:
|
||||
if os == "android": FAIL
|
||||
|
||||
[looping handlers should throw SECURITY_ERR]
|
||||
expected:
|
||||
if os == "android": FAIL
|
||||
|
||||
[a url argument without %s (but with %a) should throw SYNTAX_ERR]
|
||||
expected:
|
||||
if os == "android": FAIL
|
||||
|
||||
[attempting to override the attachment protocol should throw SECURITY_ERR]
|
||||
expected:
|
||||
if os == "android": FAIL
|
||||
|
||||
[attempting to override the shttp protocol should throw SECURITY_ERR]
|
||||
expected:
|
||||
if os == "android": FAIL
|
||||
|
||||
[a protocol argument containing a null character should throw SYNTAX_ERR]
|
||||
expected:
|
||||
if os == "android": FAIL
|
||||
|
||||
[attempting to override the livescript protocol should throw SECURITY_ERR]
|
||||
expected:
|
||||
if os == "android": FAIL
|
||||
|
||||
[attempting to override the https protocol should throw SECURITY_ERR]
|
||||
expected:
|
||||
if os == "android": FAIL
|
||||
|
||||
[a url argument pointing to a different domain name should throw SECURITY_ERR]
|
||||
expected:
|
||||
if os == "android": FAIL
|
||||
|
||||
[attempting to override the data protocol should throw SECURITY_ERR]
|
||||
expected:
|
||||
if os == "android": FAIL
|
||||
|
||||
[attempting to override the resource protocol should throw SECURITY_ERR]
|
||||
expected:
|
||||
if os == "android": FAIL
|
||||
|
||||
[attempting to override the ws protocol should throw SECURITY_ERR]
|
||||
expected:
|
||||
if os == "android": FAIL
|
||||
|
Загрузка…
Ссылка в новой задаче