Bug 1333994 - The network tab should flag resources on the tracking protection list; r=ochameau
authorJan Odvarko <odvarko@gmail.com>
Thu, 23 Aug 2018 07:36:08 +0000
changeset 481445 8221a40c73b09c4fd013cae2afd6e641b1a82541
parent 481444 443c8f1e261efdd616aed67765d181a483a674ff
child 481446 5c0edfef06dd997312d977fbe69fa6feceb4a43b
push id232
push userfmarier@mozilla.com
push dateWed, 05 Sep 2018 20:45:54 +0000
reviewersochameau
bugs1333994
milestone63.0a1
Bug 1333994 - The network tab should flag resources on the tracking protection list; r=ochameau Differential Revision: https://phabricator.services.mozilla.com/D3862
devtools/client/jar.mn
devtools/client/locales/en-US/netmonitor.properties
devtools/client/netmonitor/src/assets/icons/shield.svg
devtools/client/netmonitor/src/assets/styles/RequestList.css
devtools/client/netmonitor/src/components/RequestListColumnDomain.js
devtools/client/netmonitor/src/connector/firefox-data-provider.js
devtools/client/netmonitor/src/constants.js
devtools/client/netmonitor/test/browser.ini
devtools/client/netmonitor/test/browser_net_tracking-resources.js
devtools/client/netmonitor/test/html_tracking-protection.html
devtools/client/webconsole/test/fixtures/stubs/networkEvent.js
devtools/server/actors/network-event.js
devtools/server/actors/network-monitor/network-observer.js
devtools/shared/webconsole/client.js
--- a/devtools/client/jar.mn
+++ b/devtools/client/jar.mn
@@ -298,16 +298,17 @@ devtools.jar:
     content/netmonitor/src/assets/styles/netmonitor.css (netmonitor/src/assets/styles/netmonitor.css)
     content/netmonitor/src/assets/styles/NetworkDetailsPanel.css (netmonitor/src/assets/styles/NetworkDetailsPanel.css)
     content/netmonitor/src/assets/styles/RequestList.css (netmonitor/src/assets/styles/RequestList.css)
     content/netmonitor/src/assets/styles/StatisticsPanel.css (netmonitor/src/assets/styles/StatisticsPanel.css)
     content/netmonitor/src/assets/styles/StatusBar.css (netmonitor/src/assets/styles/StatusBar.css)
     content/netmonitor/src/assets/styles/Toolbar.css (netmonitor/src/assets/styles/Toolbar.css)
     content/netmonitor/src/assets/styles/variables.css (netmonitor/src/assets/styles/variables.css)
     content/netmonitor/src/assets/icons/play.svg (netmonitor/src/assets/icons/play.svg)
+    content/netmonitor/src/assets/icons/shield.svg (netmonitor/src/assets/icons/shield.svg)
     content/netmonitor/index.html (netmonitor/index.html)
 
     # Application panel
     content/application/index.html (application/index.html)
 
     # Devtools-components
     skin/images/devtools-components/arrow.svg (themes/images/devtools-components/arrow.svg)
 
--- a/devtools/client/locales/en-US/netmonitor.properties
+++ b/devtools/client/locales/en-US/netmonitor.properties
@@ -863,16 +863,20 @@ netmonitor.security.hpkp=Public Key Pinn
 # in the security tab describing the section containing information related to
 # the secure connection.
 netmonitor.security.connection=Connection:
 
 # LOCALIZATION NOTE (netmonitor.security.certificate): This is the label displayed
 # in the security tab describing the server certificate section.
 netmonitor.security.certificate=Certificate:
 
+# LOCALIZATION NOTE (netmonitor.trackingResource.tooltip): This is the label used
+# in the Network monitor panel as a tooltip for tracking resource icon.
+netmonitor.trackingResource.tooltip=This URL matches a known tracker and it would be blocked with Content Blocking enabled.
+
 # LOCALIZATION NOTE (netmonitor.context.copy): This is the label displayed
 # for the copy sub-menu in the context menu for a request
 netmonitor.context.copy=Copy
 
 # LOCALIZATION NOTE (netmonitor.context.copy.accesskey): This is the access key
 # for the copy sub-menu displayed in the context menu for a request
 netmonitor.context.copy.accesskey=C
 
new file mode 100644
--- /dev/null
+++ b/devtools/client/netmonitor/src/assets/icons/shield.svg
@@ -0,0 +1,7 @@
+<!-- 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/. -->
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
+  <defs><style>.cls-1{fill:#737373;}</style></defs>
+  <path class="cls-1" d="M12.08,7.21a7.27,7.27,0,0,1-1.39,4.18A4.42,4.42,0,0,1,8,13.07a4.48,4.48,0,0,1-2.29-1.21l-.65.65A5.17,5.17,0,0,0,7.94,14h.11a5.22,5.22,0,0,0,3.38-2.05A8.16,8.16,0,0,0,13,7.29c.05-.61.07-1.85.07-2.79l-.93.93C12.13,6.11,12.12,6.81,12.08,7.21Z"/><path class="cls-1" d="M8,11.84V9.57L6.65,10.92A2.87,2.87,0,0,0,8,11.84Zm5.86-9.7a.46.46,0,0,0-.65,0l-.73.72A1.3,1.3,0,0,0,12,2.69L8,2,4,2.69a1.24,1.24,0,0,0-1,1.23c0,.93,0,2.62.07,3.37a8.69,8.69,0,0,0,1.11,4l-2,2a.46.46,0,1,0,.65.66h0L13.86,2.79A.46.46,0,0,0,13.86,2.14ZM5.23,4.67c0,1,0,1.83.07,2.21a9.66,9.66,0,0,0,.52,2.65l-1,1a8.12,8.12,0,0,1-.87-3.35c-.07-.74-.07-2.55-.07-3.29A.32.32,0,0,1,4.1,3.6L8,2.93l3.77.65L8,7.35V4.19Z"/>
+</svg>
--- a/devtools/client/netmonitor/src/assets/styles/RequestList.css
+++ b/devtools/client/netmonitor/src/assets/styles/RequestList.css
@@ -381,16 +381,26 @@
 .security-state-broken {
   background-image: url(chrome://devtools/skin/images/security-state-broken.svg);
 }
 
 .security-state-local {
   background-image: url(chrome://devtools/skin/images/globe.svg);
 }
 
+.tracking-resource {
+  display: inline-block;
+  width: 16px;
+  height: 16px;
+  margin: 0 3px 0 -3px;
+  vertical-align: text-bottom;
+  background-image: url(chrome://devtools/content/netmonitor/src/assets/icons/shield.svg);
+  background-repeat: no-repeat;
+}
+
 /* RemoteIP column */
 
 .requests-list-remoteip {
   width: 9%;
 }
 
 /* Cause column */
 
--- a/devtools/client/netmonitor/src/components/RequestListColumnDomain.js
+++ b/devtools/client/netmonitor/src/components/RequestListColumnDomain.js
@@ -50,15 +50,19 @@ class RequestListColumnDomain extends Co
 
     return (
       div({ className: "requests-list-column requests-list-domain", title },
         div({
           className: iconClassList.join(" "),
           onMouseDown: onSecurityIconMouseDown,
           title: iconTitle,
         }),
+        item.isTrackingResource && div({
+          className: "tracking-resource",
+          title: L10N.getStr("netmonitor.trackingResource.tooltip"),
+        }),
         host,
       )
     );
   }
 }
 
 module.exports = RequestListColumnDomain;
--- a/devtools/client/netmonitor/src/connector/firefox-data-provider.js
+++ b/devtools/client/netmonitor/src/connector/firefox-data-provider.js
@@ -66,16 +66,17 @@ class FirefoxDataProvider {
     const {
       method,
       url,
       isXHR,
       cause,
       startedDateTime,
       fromCache,
       fromServiceWorker,
+      isTrackingResource,
     } = data;
 
     if (this.actionsEnabled && this.actions.addRequest) {
       await this.actions.addRequest(id, {
         // Convert the received date/time string to a unix timestamp.
         startedMillis: Date.parse(startedDateTime),
         method,
         url,
@@ -84,16 +85,17 @@ class FirefoxDataProvider {
 
         // Compatibility code to support Firefox 58 and earlier that always
         // send stack-trace immediately on networkEvent message.
         // FF59+ supports fetching the traces lazily via requestData.
         stacktrace: cause.stacktrace,
 
         fromCache,
         fromServiceWorker,
+        isTrackingResource,
       }, true);
     }
 
     this.emit(EVENTS.REQUEST_ADDED, id);
   }
 
   /**
    * Update a network request if it already exists in application state.
@@ -318,26 +320,28 @@ class FirefoxDataProvider {
       fromCache,
       fromServiceWorker,
       isXHR,
       request: {
         method,
         url,
       },
       startedDateTime,
+      isTrackingResource,
     } = networkInfo;
 
     await this.addRequest(actor, {
       cause,
       fromCache,
       fromServiceWorker,
       isXHR,
       method,
       startedDateTime,
       url,
+      isTrackingResource,
     });
 
     this.emit(EVENTS.NETWORK_EVENT, actor);
   }
 
   /**
    * The "networkEventUpdate" message type handler.
    *
@@ -346,17 +350,19 @@ class FirefoxDataProvider {
    */
   onNetworkEventUpdate(data) {
     const { packet, networkInfo } = data;
     const { actor } = networkInfo;
     const { updateType } = packet;
 
     switch (updateType) {
       case "securityInfo":
-        this.pushRequestToQueue(actor, { securityState: networkInfo.securityState });
+        this.pushRequestToQueue(actor, {
+          securityState: networkInfo.securityState
+        });
         break;
       case "responseStart":
         this.pushRequestToQueue(actor, {
           httpVersion: networkInfo.response.httpVersion,
           remoteAddress: networkInfo.response.remoteAddress,
           remotePort: networkInfo.response.remotePort,
           status: networkInfo.response.status,
           statusText: networkInfo.response.statusText,
--- a/devtools/client/netmonitor/src/constants.js
+++ b/devtools/client/netmonitor/src/constants.js
@@ -141,16 +141,17 @@ const UPDATE_PROPS = [
   "responseCookies",
   "responseCookiesAvailable",
   "responseContent",
   "responseContentAvailable",
   "responseCache",
   "responseCacheAvailable",
   "formDataSections",
   "stacktrace",
+  "isTrackingResource",
 ];
 
 const PANELS = {
   COOKIES: "cookies",
   HEADERS: "headers",
   PARAMS: "params",
   RESPONSE: "response",
   CACHE: "cache",
--- a/devtools/client/netmonitor/test/browser.ini
+++ b/devtools/client/netmonitor/test/browser.ini
@@ -32,16 +32,17 @@ support-files =
   html_post-raw-test-page.html
   html_post-raw-with-headers-test-page.html
   html_simple-test-page.html
   html_single-get-page.html
   html_send-beacon.html
   html_sorting-test-page.html
   html_statistics-test-page.html
   html_status-codes-test-page.html
+  html_tracking-protection.html
   html_api-calls-test-page.html
   html_copy-as-curl.html
   html_curl-utils.html
   html_open-request-in-tab.html
   sjs_content-type-test-server.sjs
   sjs_cors-test-server.sjs
   sjs_https-redirect-test-server.sjs
   sjs_hsts-test-server.sjs
@@ -189,11 +190,12 @@ skip-if = true # Bug 1373558
 [browser_net_telemetry_edit_resend.js]
 [browser_net_telemetry_filters_changed.js]
 [browser_net_telemetry_sidepanel_changed.js]
 [browser_net_telemetry_throttle_changed.js]
 [browser_net_throttle.js]
 [browser_net_timeline_ticks.js]
 skip-if = true # TODO: fix the test
 [browser_net_timing-division.js]
+[browser_net_tracking-resources.js]
 [browser_net_truncate.js]
 [browser_net_view-source-debugger.js]
 [browser_net_waterfall-click.js]
new file mode 100644
--- /dev/null
+++ b/devtools/client/netmonitor/test/browser_net_tracking-resources.js
@@ -0,0 +1,39 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+const { UrlClassifierTestUtils } =
+  ChromeUtils.import("resource://testing-common/UrlClassifierTestUtils.jsm", {});
+
+const TEST_URI = "http://tracking.example.org/browser/devtools/client/" +
+                 "netmonitor/test/html_tracking-protection.html";
+
+registerCleanupFunction(function() {
+  UrlClassifierTestUtils.cleanupTestTrackers();
+});
+
+/**
+ * Test that tracking resources are properly marked in the Network panel.
+ */
+add_task(async function() {
+  await UrlClassifierTestUtils.addTestTrackers();
+
+  const { tab, monitor } = await initNetMonitor(TEST_URI);
+  info("Starting  test...");
+
+  const { document, store, windowRequire } = monitor.panelWin;
+  const Actions = windowRequire("devtools/client/netmonitor/src/actions/index");
+
+  store.dispatch(Actions.batchEnable(false));
+
+  // Reload the page
+  const wait = waitForAllRequestsFinished(monitor);
+  tab.linkedBrowser.reload();
+  await wait;
+
+  const requests = document.querySelectorAll(".request-list-item .tracking-resource");
+  is(requests.length, 1, "There should be one tracking request");
+
+  await teardown(monitor);
+});
new file mode 100644
--- /dev/null
+++ b/devtools/client/netmonitor/test/html_tracking-protection.html
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML>
+<!-- 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/. -->
+<html dir="ltr" xml:lang="en-US" lang="en-US">
+  <head>
+    <meta charset="utf8">
+  </head>
+  <body>
+    <iframe src="http://tracking.example.com/"></iframe>
+  </body>
+</html>
--- a/devtools/client/webconsole/test/fixtures/stubs/networkEvent.js
+++ b/devtools/client/webconsole/test/fixtures/stubs/networkEvent.js
@@ -261,16 +261,17 @@ stubPackets.set(`GET request`, {
     "type": "img",
     "loadingDocumentUri": "http://example.com/browser/devtools/client/webconsole/test/fixtures/stub-generators/test-network-event.html",
     "stacktraceAvailable": true
   },
   "response": {},
   "timings": {},
   "updates": [],
   "private": false,
+  "isTrackingResource": false,
   "from": "server1.conn0.child1/consoleActor2"
 });
 
 stubPackets.set(`GET request update`, {
   "networkInfo": {
     "_type": "NetworkEvent",
     "actor": "server1.conn0.child1/netEvent30",
     "request": {
@@ -312,16 +313,17 @@ stubPackets.set(`XHR GET request`, {
     "type": "xhr",
     "loadingDocumentUri": "http://example.com/browser/devtools/client/webconsole/test/fixtures/stub-generators/test-network-event.html",
     "stacktraceAvailable": true
   },
   "response": {},
   "timings": {},
   "updates": [],
   "private": false,
+  "isTrackingResource": false,
   "from": "server1.conn1.child1/consoleActor2"
 });
 
 stubPackets.set(`XHR GET request update`, {
   "networkInfo": {
     "_type": "NetworkEvent",
     "actor": "server1.conn0.child1/netEvent31",
     "request": {
@@ -363,16 +365,17 @@ stubPackets.set(`XHR POST request`, {
     "type": "xhr",
     "loadingDocumentUri": "http://example.com/browser/devtools/client/webconsole/test/fixtures/stub-generators/test-network-event.html",
     "stacktraceAvailable": true
   },
   "response": {},
   "timings": {},
   "updates": [],
   "private": false,
+  "isTrackingResource": false,
   "from": "server1.conn2.child1/consoleActor2"
 });
 
 stubPackets.set(`XHR POST request update`, {
   "networkInfo": {
     "_type": "NetworkEvent",
     "actor": "server1.conn0.child1/netEvent32",
     "request": {
--- a/devtools/server/actors/network-event.js
+++ b/devtools/server/actors/network-event.js
@@ -60,16 +60,17 @@ const NetworkEventActor = protocol.Actor
       timeStamp: Date.parse(this._startedDateTime),
       url: this._request.url,
       method: this._request.method,
       isXHR: this._isXHR,
       cause: this._cause,
       fromCache: this._fromCache,
       fromServiceWorker: this._fromServiceWorker,
       private: this._private,
+      isTrackingResource: this._isTrackingResource,
     };
   },
 
   /**
    * Releases this actor from the pool.
    */
   destroy(conn) {
     if (!this.netMonitorActor) {
@@ -98,16 +99,17 @@ const NetworkEventActor = protocol.Actor
    *        The network event associated with this actor.
    */
   init(networkEvent) {
     this._startedDateTime = networkEvent.startedDateTime;
     this._isXHR = networkEvent.isXHR;
     this._cause = networkEvent.cause;
     this._fromCache = networkEvent.fromCache;
     this._fromServiceWorker = networkEvent.fromServiceWorker;
+    this._isTrackingResource = networkEvent.isTrackingResource;
     this._channelId = networkEvent.channelId;
 
     // Stack trace info isn't sent automatically. The client
     // needs to request it explicitly using getStackTrace
     // packet. NetmonitorActor may pass just a boolean instead of the stack
     // when the actor is in parent process and stack is in the content process.
     this._stackTrace = networkEvent.cause.stacktrace;
     delete networkEvent.cause.stacktrace;
--- a/devtools/server/actors/network-monitor/network-observer.js
+++ b/devtools/server/actors/network-monitor/network-observer.js
@@ -308,17 +308,17 @@ NetworkObserver.prototype = {
     response.status = channel.responseStatus;
     response.statusText = channel.responseStatusText;
     response.httpVersion = "HTTP/" + httpVersionMaj.value + "." +
                                      httpVersionMin.value;
 
     this.openResponses.set(channel, response);
 
     if (topic === "http-on-examine-cached-response") {
-      // Service worker requests emits cached-reponse notification on non-e10s,
+      // Service worker requests emits cached-response notification on non-e10s,
       // and we fake one on e10s.
       const fromServiceWorker = this.interceptedChannels.has(channel);
       this.interceptedChannels.delete(channel);
 
       // If this is a cached response, there never was a request event
       // so we need to construct one here so the frontend gets all the
       // expected events.
       const httpActivity = this._createNetworkEvent(channel, {
@@ -486,16 +486,17 @@ NetworkObserver.prototype = {
     event.url = channel.URI.spec;
     event.private = httpActivity.private;
     event.headersSize = 0;
     event.startedDateTime =
       (timestamp ? new Date(Math.round(timestamp / 1000)) : new Date())
       .toISOString();
     event.fromCache = fromCache;
     event.fromServiceWorker = fromServiceWorker;
+    event.isTrackingResource = channel.isTrackingResource;
     httpActivity.fromServiceWorker = fromServiceWorker;
 
     if (extraStringData) {
       event.headersSize = extraStringData.length;
     }
 
     // Determine the cause and if this is an XHR request.
     let causeType = Ci.nsIContentPolicy.TYPE_OTHER;
--- a/devtools/shared/webconsole/client.js
+++ b/devtools/shared/webconsole/client.js
@@ -105,17 +105,18 @@ WebConsoleClient.prototype = {
         isXHR: actor.isXHR,
         cause: actor.cause,
         response: {},
         timings: {},
         // track the list of network event updates
         updates: [],
         private: actor.private,
         fromCache: actor.fromCache,
-        fromServiceWorker: actor.fromServiceWorker
+        fromServiceWorker: actor.fromServiceWorker,
+        isTrackingResource: actor.isTrackingResource,
       };
       this._networkRequests.set(actor.actor, networkInfo);
 
       this.emit("networkEvent", networkInfo);
     }
   },
 
   /**