Bug 1345077 - Part 2 - Add telemetry on permission requests from third party origins, handling user input and insecure contexts. r=florian,liuche
MozReview-Commit-ID: 4ARIxa6gwCg
--- a/browser/components/nsBrowserGlue.js
+++ b/browser/components/nsBrowserGlue.js
@@ -2851,16 +2851,42 @@ ContentPermissionPrompt.prototype = {
combinedIntegration.createPermissionPrompt(type, request);
if (!permissionPrompt) {
throw Components.Exception(
`Failed to handle permission of type ${type}`,
Cr.NS_ERROR_FAILURE);
}
permissionPrompt.prompt();
+
+ let schemeHistogram = Services.telemetry.getKeyedHistogramById("PERMISSION_REQUEST_ORIGIN_SCHEME");
+ let scheme = 0;
+ // URI is null for system principals.
+ if (request.principal.URI) {
+ switch (request.principal.URI.scheme) {
+ case "http":
+ scheme = 1;
+ break;
+ case "https":
+ scheme = 2;
+ break;
+ }
+ }
+ schemeHistogram.add(type, scheme);
+
+ // request.element should be the browser element in e10s.
+ if (request.element && request.element.contentPrincipal) {
+ let thirdPartyHistogram = Services.telemetry.getKeyedHistogramById("PERMISSION_REQUEST_THIRD_PARTY_ORIGIN");
+ let isThirdParty = request.principal.origin != request.element.contentPrincipal.origin;
+ thirdPartyHistogram.add(type, isThirdParty);
+ }
+
+ let userInputHistogram = Services.telemetry.getKeyedHistogramById("PERMISSION_REQUEST_HANDLING_USER_INPUT");
+ userInputHistogram.add(type, request.isHandlingUserInput);
+
} catch (ex) {
Cu.reportError(ex);
request.cancel();
throw ex;
}
},
};
--- a/browser/components/tests/browser/browser_contentpermissionprompt.js
+++ b/browser/components/tests/browser/browser_contentpermissionprompt.js
@@ -56,16 +56,17 @@ MockContentPermissionRequest.prototype =
wrappedJSObject: this,
// For some of our tests, we want to make sure that the
// request is cancelled, so we add some instrumentation here
// to check that cancel() is called.
cancel() {
this.cancelled = true;
},
cancelled: false,
+ principal: Services.scriptSecurityManager.getSystemPrincipal(),
};
/**
* Tests that if the nsIContentPermissionRequest has an empty
* types array, that NS_ERROR_UNEXPECTED is thrown, and the
* request is cancelled.
*/
add_task(async function test_empty_types() {
--- a/browser/modules/ContentWebRTC.jsm
+++ b/browser/modules/ContentWebRTC.jsm
@@ -130,39 +130,40 @@ function handleGUMStop(aSubject, aTopic,
let mm = getMessageManagerForWindow(contentWindow);
if (mm)
mm.sendAsyncMessage("webrtc:StopRecording", request);
}
function handleGUMRequest(aSubject, aTopic, aData) {
let constraints = aSubject.getConstraints();
let secure = aSubject.isSecure;
+ let isHandlingUserInput = aSubject.isHandlingUserInput;
let contentWindow = Services.wm.getOuterWindowWithId(aSubject.windowID);
contentWindow.navigator.mozGetUserMediaDevices(
constraints,
function(devices) {
// If the window has been closed while we were waiting for the list of
// devices, there's nothing to do in the callback anymore.
if (contentWindow.closed)
return;
prompt(contentWindow, aSubject.windowID, aSubject.callID,
- constraints, devices, secure);
+ constraints, devices, secure, isHandlingUserInput);
},
function(error) {
// bug 827146 -- In the future, the UI should catch NotFoundError
// and allow the user to plug in a device, instead of immediately failing.
denyGUMRequest({callID: aSubject.callID}, error);
},
aSubject.innerWindowID,
aSubject.callID);
}
-function prompt(aContentWindow, aWindowID, aCallID, aConstraints, aDevices, aSecure) {
+function prompt(aContentWindow, aWindowID, aCallID, aConstraints, aDevices, aSecure, aIsHandlingUserInput) {
let audioDevices = [];
let videoDevices = [];
let devices = [];
// MediaStreamConstraints defines video as 'boolean or MediaTrackConstraints'.
let video = aConstraints.video || aConstraints.picture;
let audio = aConstraints.audio;
let sharingScreen = video && typeof(video) != "boolean" &&
@@ -208,22 +209,28 @@ function prompt(aContentWindow, aWindowI
return;
}
if (!aContentWindow.pendingGetUserMediaRequests) {
setupPendingListsInitially(aContentWindow);
}
aContentWindow.pendingGetUserMediaRequests.set(aCallID, devices);
+ // Record third party origins for telemetry.
+ let isThirdPartyOrigin =
+ aContentWindow.document.location.origin != aContentWindow.top.document.location.origin;
+
let request = {
callID: aCallID,
windowID: aWindowID,
origin: aContentWindow.origin,
documentURI: aContentWindow.document.documentURI,
secure: aSecure,
+ isHandlingUserInput: aIsHandlingUserInput,
+ isThirdPartyOrigin,
requestTypes,
sharingScreen,
sharingAudio,
audioDevices,
videoDevices
};
let mm = getMessageManagerForWindow(aContentWindow);
--- a/browser/modules/webrtcUI.jsm
+++ b/browser/modules/webrtcUI.jsm
@@ -840,16 +840,39 @@ function prompt(aBrowser, aRequest) {
notification =
chromeDoc.defaultView
.PopupNotifications
.show(aBrowser, "webRTC-shareDevices", message,
anchorId, mainAction, secondaryActions,
options);
notification.callID = aRequest.callID;
+
+ let schemeHistogram = Services.telemetry.getKeyedHistogramById("PERMISSION_REQUEST_ORIGIN_SCHEME");
+ let thirdPartyHistogram = Services.telemetry.getKeyedHistogramById("PERMISSION_REQUEST_THIRD_PARTY_ORIGIN");
+ let userInputHistogram = Services.telemetry.getKeyedHistogramById("PERMISSION_REQUEST_HANDLING_USER_INPUT");
+
+ let docURI = aRequest.documentURI;
+ let scheme = 0;
+ if (docURI.startsWith("https")) {
+ scheme = 2;
+ } else if (docURI.startsWith("http")) {
+ scheme = 1;
+ }
+
+ for (let requestType of requestTypes) {
+ if (requestType == "AudioCapture") {
+ requestType = "Microphone";
+ }
+ requestType = requestType.toLowerCase();
+
+ schemeHistogram.add(requestType, scheme);
+ thirdPartyHistogram.add(requestType, aRequest.isThirdPartyOrigin);
+ userInputHistogram.add(requestType, aRequest.isHandlingUserInput);
+ }
}
function removePrompt(aBrowser, aCallId) {
let chromeWin = aBrowser.ownerGlobal;
let notification =
chromeWin.PopupNotifications.getNotification("webRTC-shareDevices", aBrowser);
if (notification && notification.callID == aCallId)
notification.remove();
--- a/toolkit/components/telemetry/Histograms.json
+++ b/toolkit/components/telemetry/Histograms.json
@@ -13925,10 +13925,38 @@
"kind": "exponential",
"high": 10000,
"n_buckets": 20,
"keyed": true,
"description": "The number of prefs in each prefs file loaded, keyed by filename.",
"releaseChannelCollection": "opt-out",
"bug_numbers": [1426270],
"alert_emails": ["nnethercote@mozilla.com"]
+ },
+ "PERMISSION_REQUEST_ORIGIN_SCHEME": {
+ "record_in_processes": ["main"],
+ "alert_emails": ["jhofmann@mozilla.com"],
+ "bug_numbers": [1286118],
+ "expires_in_version": "64",
+ "kind": "enumerated",
+ "n_values": 10,
+ "keyed": true,
+ "description": "Permission requests (showing a permission prompt) by origin scheme (0=other,1=http,2=https)."
+ },
+ "PERMISSION_REQUEST_THIRD_PARTY_ORIGIN": {
+ "record_in_processes": ["main"],
+ "alert_emails": ["jhofmann@mozilla.com"],
+ "bug_numbers": [1286118],
+ "expires_in_version": "64",
+ "kind": "boolean",
+ "keyed": true,
+ "description": "Permission requests (showing a permission prompt) by whether they come from a third party origin."
+ },
+ "PERMISSION_REQUEST_HANDLING_USER_INPUT": {
+ "record_in_processes": ["main"],
+ "alert_emails": ["jhofmann@mozilla.com"],
+ "bug_numbers": [1286118],
+ "expires_in_version": "64",
+ "kind": "boolean",
+ "keyed": true,
+ "description": "Permission requests (showing a permission prompt) by whether they were requested from code handling a user input event."
}
}