зеркало из https://github.com/mozilla/gecko-dev.git
Bug 666809 - Support SecurityUI in e10s mode. r=felipe f=gavin
This commit is contained in:
Родитель
de7ceb67d2
Коммит
8713e6bb02
|
@ -3668,10 +3668,6 @@ var XULBrowserWindow = {
|
|||
init: function () {
|
||||
this.throbberElement = document.getElementById("navigator-throbber");
|
||||
|
||||
// Bug 666809 - SecurityUI support for e10s
|
||||
if (gMultiProcessBrowser)
|
||||
return;
|
||||
|
||||
// Initialize the security button's state and tooltip text. Remember to reset
|
||||
// _hostChanged, otherwise onSecurityChange will short circuit.
|
||||
var securityUI = gBrowser.securityUI;
|
||||
|
@ -4077,26 +4073,11 @@ var XULBrowserWindow = {
|
|||
gURLBar.removeAttribute("level");
|
||||
}
|
||||
|
||||
if (gMultiProcessBrowser)
|
||||
return;
|
||||
|
||||
// Don't pass in the actual location object, since it can cause us to
|
||||
// hold on to the window object too long. Just pass in the fields we
|
||||
// care about. (bug 424829)
|
||||
var location = gBrowser.contentWindow.location;
|
||||
var locationObj = {};
|
||||
let uri = gBrowser.currentURI;
|
||||
try {
|
||||
// about:blank can be used by webpages so pretend it is http
|
||||
locationObj.protocol = location == "about:blank" ? "http:" : location.protocol;
|
||||
locationObj.host = location.host;
|
||||
locationObj.hostname = location.hostname;
|
||||
locationObj.port = location.port;
|
||||
} catch (ex) {
|
||||
// Can sometimes throw if the URL being visited has no host/hostname,
|
||||
// e.g. about:blank. The _state for these pages means we won't need these
|
||||
// properties anyways, though.
|
||||
}
|
||||
gIdentityHandler.checkIdentity(this._state, locationObj);
|
||||
uri = Services.uriFixup.createExposableURI(uri);
|
||||
} catch (e) {}
|
||||
gIdentityHandler.checkIdentity(this._state, uri);
|
||||
},
|
||||
|
||||
// simulate all change notifications after switching tabs
|
||||
|
@ -6395,7 +6376,7 @@ var gIdentityHandler = {
|
|||
|
||||
// Cache the most recent SSLStatus and Location seen in checkIdentity
|
||||
_lastStatus : null,
|
||||
_lastLocation : null,
|
||||
_lastUri : null,
|
||||
_mode : "unknownIdentity",
|
||||
|
||||
// smart getters
|
||||
|
@ -6553,19 +6534,29 @@ var gIdentityHandler = {
|
|||
* be called by onSecurityChange
|
||||
*
|
||||
* @param PRUint32 state
|
||||
* @param JS Object location that mirrors an nsLocation (i.e. has .host and
|
||||
* .hostname and .port)
|
||||
* @param nsIURI uri The address for which the UI should be updated.
|
||||
*/
|
||||
checkIdentity : function(state, location) {
|
||||
checkIdentity : function(state, uri) {
|
||||
var currentStatus = gBrowser.securityUI
|
||||
.QueryInterface(Components.interfaces.nsISSLStatusProvider)
|
||||
.SSLStatus;
|
||||
this._lastStatus = currentStatus;
|
||||
this._lastLocation = location;
|
||||
this._lastUri = uri;
|
||||
|
||||
let nsIWebProgressListener = Ci.nsIWebProgressListener;
|
||||
if (location.protocol == "chrome:" || location.protocol == "about:") {
|
||||
|
||||
// For some URIs like data: we can't get a host and so can't do
|
||||
// anything useful here. Chrome URIs however get special treatment.
|
||||
let unknown = false;
|
||||
try {
|
||||
uri.host;
|
||||
} catch (e) { unknown = true; }
|
||||
|
||||
if ((uri.scheme == "chrome" || uri.scheme == "about") &&
|
||||
uri.spec !== "about:blank") {
|
||||
this.setMode(this.IDENTITY_MODE_CHROMEUI);
|
||||
} else if (unknown) {
|
||||
this.setMode(this.IDENTITY_MODE_UNKNOWN);
|
||||
} else if (state & nsIWebProgressListener.STATE_IDENTITY_EV_TOPLEVEL) {
|
||||
this.setMode(this.IDENTITY_MODE_IDENTIFIED);
|
||||
} else if (state & nsIWebProgressListener.STATE_IS_SECURE) {
|
||||
|
@ -6636,12 +6627,12 @@ var gIdentityHandler = {
|
|||
.getService(Ci.nsIIDNService);
|
||||
try {
|
||||
let baseDomain =
|
||||
Services.eTLD.getBaseDomainFromHost(this._lastLocation.hostname);
|
||||
Services.eTLD.getBaseDomainFromHost(this._lastUri.host);
|
||||
return this._IDNService.convertToDisplayIDN(baseDomain, {});
|
||||
} catch (e) {
|
||||
// If something goes wrong (e.g. hostname is an IP address) just fail back
|
||||
// If something goes wrong (e.g. host is an IP address) just fail back
|
||||
// to the full domain.
|
||||
return this._lastLocation.hostname;
|
||||
return this._lastUri.host;
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -6688,19 +6679,17 @@ var gIdentityHandler = {
|
|||
tooltip = gNavigatorBundle.getFormattedString("identity.identified.verifier",
|
||||
[iData.caOrg]);
|
||||
|
||||
// Check whether this site is a security exception. XPConnect does the right
|
||||
// thing here in terms of converting _lastLocation.port from string to int, but
|
||||
// the overrideService doesn't like undefined ports, so make sure we have
|
||||
// something in the default case (bug 432241).
|
||||
// .hostname can return an empty string in some exceptional cases -
|
||||
// hasMatchingOverride does not handle that, so avoid calling it.
|
||||
// Updating the tooltip value in those cases isn't critical.
|
||||
// FIXME: Fixing bug 646690 would probably makes this check unnecessary
|
||||
if (this._lastLocation.hostname &&
|
||||
this._overrideService.hasMatchingOverride(this._lastLocation.hostname,
|
||||
(this._lastLocation.port || 443),
|
||||
iData.cert, {}, {}))
|
||||
// This can't throw, because URI's with a host that throw don't end up in this case.
|
||||
let host = this._lastUri.host;
|
||||
let port = 443;
|
||||
try {
|
||||
if (this._lastUri.port > 0)
|
||||
port = this._lastUri.port;
|
||||
} catch (e) {}
|
||||
|
||||
if (this._overrideService.hasMatchingOverride(host, port, iData.cert, {}, {}))
|
||||
tooltip = gNavigatorBundle.getString("identity.identified.verified_by_you");
|
||||
|
||||
break; }
|
||||
case this.IDENTITY_MODE_IDENTIFIED: {
|
||||
// If it's identified, then we can populate the dialog with credentials
|
||||
|
|
|
@ -16,54 +16,45 @@ var tests = [
|
|||
{
|
||||
name: "normal domain",
|
||||
location: "http://test1.example.org/",
|
||||
host: "test1.example.org",
|
||||
effectiveHost: "example.org"
|
||||
},
|
||||
{
|
||||
name: "view-source",
|
||||
location: "view-source:http://example.com/",
|
||||
// TODO: these should not be blank, bug 646690
|
||||
host: "",
|
||||
effectiveHost: ""
|
||||
effectiveHost: null
|
||||
},
|
||||
{
|
||||
name: "normal HTTPS",
|
||||
location: "https://example.com/",
|
||||
host: "example.com",
|
||||
effectiveHost: "example.com",
|
||||
isHTTPS: true
|
||||
},
|
||||
{
|
||||
name: "IDN subdomain",
|
||||
location: "http://sub1." + idnDomain + "/",
|
||||
host: "sub1." + idnDomain,
|
||||
effectiveHost: idnDomain
|
||||
},
|
||||
{
|
||||
name: "subdomain with port",
|
||||
location: "http://sub1.test1.example.org:8000/",
|
||||
host: "sub1.test1.example.org:8000",
|
||||
effectiveHost: "example.org"
|
||||
},
|
||||
{
|
||||
name: "subdomain HTTPS",
|
||||
location: "https://test1.example.com",
|
||||
host: "test1.example.com",
|
||||
location: "https://test1.example.com/",
|
||||
|
||||
effectiveHost: "example.com",
|
||||
isHTTPS: true
|
||||
},
|
||||
{
|
||||
name: "view-source HTTPS",
|
||||
location: "view-source:https://example.com/",
|
||||
// TODO: these should not be blank, bug 646690
|
||||
host: "",
|
||||
effectiveHost: "",
|
||||
effectiveHost: null,
|
||||
isHTTPS: true
|
||||
},
|
||||
{
|
||||
name: "IP address",
|
||||
location: "http://127.0.0.1:8888/",
|
||||
host: "127.0.0.1:8888",
|
||||
effectiveHost: "127.0.0.1"
|
||||
},
|
||||
]
|
||||
|
@ -112,8 +103,12 @@ function nextTest() {
|
|||
|
||||
function checkResult() {
|
||||
// Sanity check other values, and the value of gIdentityHandler.getEffectiveHost()
|
||||
is(gIdentityHandler._lastLocation.host, gCurrentTest.host, "host matches for test " + gTestDesc);
|
||||
is(gIdentityHandler.getEffectiveHost(), gCurrentTest.effectiveHost, "effectiveHost matches for test " + gTestDesc);
|
||||
is(gIdentityHandler._lastUri.spec, gCurrentTest.location, "location matches for test " + gTestDesc);
|
||||
// getEffectiveHost can't be called for all modes
|
||||
if (gCurrentTest.effectiveHost === null)
|
||||
is(gIdentityHandler._mode == gIdentityHandler.IDENTITY_MODE_UNKNOWN || gIdentityHandler._mode == gIdentityHandler.IDENTITY_MODE_CHROMEUI, true, "mode matched");
|
||||
else
|
||||
is(gIdentityHandler.getEffectiveHost(), gCurrentTest.effectiveHost, "effectiveHost matches for test " + gTestDesc);
|
||||
|
||||
executeSoon(nextTest);
|
||||
}
|
||||
|
|
|
@ -65,6 +65,7 @@ let WebProgressListener = {
|
|||
onSecurityChange: function onSecurityChange(aWebProgress, aRequest, aState) {
|
||||
let json = this._setupJSON(aWebProgress, aRequest);
|
||||
json.state = aState;
|
||||
json.status = SecurityUI.getSSLStatusAsString();
|
||||
|
||||
sendAsyncMessage("Content:SecurityChange", json);
|
||||
},
|
||||
|
@ -149,6 +150,22 @@ let WebNavigation = {
|
|||
|
||||
WebNavigation.init();
|
||||
|
||||
let SecurityUI = {
|
||||
getSSLStatusAsString: function() {
|
||||
let status = docShell.securityUI.QueryInterface(Ci.nsISSLStatusProvider).SSLStatus;
|
||||
|
||||
if (status) {
|
||||
let helper = Cc["@mozilla.org/network/serialization-helper;1"]
|
||||
.getService(Ci.nsISerializationHelper);
|
||||
|
||||
status.QueryInterface(Ci.nsISerializable);
|
||||
return helper.serializeToString(status);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
addEventListener("DOMTitleChanged", function (aEvent) {
|
||||
let document = content.document;
|
||||
switch (aEvent.type) {
|
||||
|
|
|
@ -12,8 +12,24 @@
|
|||
|
||||
<implementation type="application/javascript" implements="nsIAccessibleProvider, nsIObserver, nsIDOMEventListener, nsIMessageListener, nsIMessageListener">
|
||||
|
||||
<field name="_securityUI">null</field>
|
||||
|
||||
<property name="securityUI"
|
||||
onget="return null;"/>
|
||||
readonly="true">
|
||||
<getter><![CDATA[
|
||||
if (!this._securityUI) {
|
||||
let jsm = "resource://gre/modules/RemoteSecurityUI.jsm";
|
||||
let RemoteSecurityUI = Components.utils.import(jsm, {}).RemoteSecurityUI;
|
||||
this._securityUI = new RemoteSecurityUI();
|
||||
}
|
||||
|
||||
// We want to double-wrap the JS implemented interface, so that QI and instanceof works.
|
||||
var ptr = Cc["@mozilla.org/supports-interface-pointer;1"].
|
||||
createInstance(Ci.nsISupportsInterfacePointer);
|
||||
ptr.data = this._securityUI;
|
||||
return ptr.data.QueryInterface(Ci.nsISecureBrowserUI);
|
||||
]]></getter>
|
||||
</property>
|
||||
|
||||
<property name="webNavigation"
|
||||
onget="return this._remoteWebNavigation;"
|
||||
|
@ -22,16 +38,16 @@
|
|||
<field name="_remoteWebProgress">null</field>
|
||||
|
||||
<property name="webProgress" readonly="true">
|
||||
<getter>
|
||||
<![CDATA[
|
||||
<getter>
|
||||
<![CDATA[
|
||||
if (!this._remoteWebProgress) {
|
||||
let RemoteWebProgress = Components.utils.import("resource://gre/modules/RemoteWebProgress.jsm",
|
||||
{}).RemoteWebProgress;
|
||||
let jsm = "resource://gre/modules/RemoteWebProgress.jsm";
|
||||
let RemoteWebProgress = Components.utils.import(jsm, {}).RemoteWebProgress;
|
||||
this._remoteWebProgress = new RemoteWebProgress(this);
|
||||
}
|
||||
return this._remoteWebProgress;
|
||||
]]>
|
||||
</getter>
|
||||
]]>
|
||||
</getter>
|
||||
</property>
|
||||
|
||||
<field name="_contentTitle">null</field>
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
// -*- Mode: javascript; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
// 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/.
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["RemoteSecurityUI"];
|
||||
|
||||
const Ci = Components.interfaces;
|
||||
const Cc = Components.classes;
|
||||
const Cu = Components.utils;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
function RemoteSecurityUI()
|
||||
{
|
||||
this._state = 0;
|
||||
this._SSLStatus = null;
|
||||
}
|
||||
|
||||
RemoteSecurityUI.prototype = {
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsISSLStatusProvider, Ci.nsISecureBrowserUI]),
|
||||
|
||||
// nsISecureBrowserUI
|
||||
get state() { return this._state; },
|
||||
get tooltipText() { return ""; },
|
||||
|
||||
// nsISSLStatusProvider
|
||||
get SSLStatus() { return this._SSLStatus; },
|
||||
|
||||
_update: function (state, status) {
|
||||
let deserialized = null;
|
||||
if (status) {
|
||||
let helper = Cc["@mozilla.org/network/serialization-helper;1"]
|
||||
.getService(Components.interfaces.nsISerializationHelper);
|
||||
|
||||
deserialized = helper.deserializeObject(status)
|
||||
deserialized.QueryInterface(Ci.nsISSLStatus);
|
||||
}
|
||||
|
||||
// We must check the Extended Validation (EV) state here, on the chrome
|
||||
// process, because NSS is needed for that determination.
|
||||
if (deserialized && deserialized.isExtendedValidation)
|
||||
state |= Ci.nsIWebProgressListener.STATE_IDENTITY_EV_TOPLEVEL;
|
||||
|
||||
this._state = state;
|
||||
this._SSLStatus = deserialized;
|
||||
}
|
||||
};
|
|
@ -106,8 +106,16 @@ RemoteWebProgress.prototype = {
|
|||
break;
|
||||
|
||||
case "Content:SecurityChange":
|
||||
// Invoking this getter triggers the generation of the underlying object,
|
||||
// which we need to access with ._securityUI, because .securityUI returns
|
||||
// a wrapper that makes _update inaccessible.
|
||||
void this._browser.securityUI;
|
||||
this._browser._securityUI._update(aMessage.json.state, aMessage.json.status);
|
||||
|
||||
// The state passed might not be correct due to checks performed
|
||||
// on the chrome side. _update fixes that.
|
||||
for each (let p in this._progressListeners) {
|
||||
p.onSecurityChange(this, req, aMessage.json.state);
|
||||
p.onSecurityChange(this, req, this._browser.securityUI.state);
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ EXTRA_JS_MODULES += [
|
|||
'PrivateBrowsingUtils.jsm',
|
||||
'Promise.jsm',
|
||||
'PropertyListUtils.jsm',
|
||||
'RemoteSecurityUI.jsm',
|
||||
'RemoteWebProgress.jsm',
|
||||
'Sqlite.jsm',
|
||||
'Task.jsm',
|
||||
|
|
Загрузка…
Ссылка в новой задаче