Bug 1242871 - add an originUrl property to every webRequest event details object + tests (extended & fixed + nits). r?kmag draft
authorGiorgio Maone <g.maone@informaction.com>
Fri, 01 Apr 2016 00:48:57 +0200
changeset 347457 22bd5fd39f4fd29f5aa91298f1a13017ce30b711
parent 347200 55d557f4d73ee58664bdf2fa85aaab555224722e
child 517632 d37203d7b3cc4871f5bae4b54a533534218b27ea
push id14583
push userg.maone@informaction.com
push dateMon, 04 Apr 2016 22:40:10 +0000
reviewerskmag
bugs1242871
milestone48.0a1
Bug 1242871 - add an originUrl property to every webRequest event details object + tests (extended & fixed + nits). r?kmag MozReview-Commit-ID: 6PeCwTeCuFs
toolkit/components/extensions/ext-webRequest.js
toolkit/components/extensions/test/mochitest/file_WebRequest_page1.html
toolkit/components/extensions/test/mochitest/file_WebRequest_page3.html
toolkit/components/extensions/test/mochitest/mochitest.ini
toolkit/components/extensions/test/mochitest/test_ext_webrequest.html
toolkit/modules/addons/WebRequest.jsm
toolkit/modules/addons/WebRequestContent.js
--- a/toolkit/components/extensions/ext-webRequest.js
+++ b/toolkit/components/extensions/ext-webRequest.js
@@ -29,16 +29,17 @@ function WebRequestEventManager(context,
       let tabId = TabManager.getBrowserId(data.browser);
       if (tabId == -1) {
         return;
       }
 
       let data2 = {
         requestId: data.requestId,
         url: data.url,
+        originUrl: data.originUrl,
         method: data.method,
         type: data.type,
         timeStamp: Date.now(),
         frameId: ExtensionManagement.getFrameId(data.windowId),
         parentFrameId: ExtensionManagement.getParentFrameId(data.parentWindowId, data.windowId),
       };
 
       if ("ip" in data) {
--- a/toolkit/components/extensions/test/mochitest/file_WebRequest_page1.html
+++ b/toolkit/components/extensions/test/mochitest/file_WebRequest_page1.html
@@ -23,10 +23,21 @@
 
 <script src="nonexistent_script_url.js"></script>
 
 <iframe src="file_WebRequest_page2.html" width="200" height="200"></iframe>
 <iframe src="redirection.sjs" width="200" height="200"></iframe>
 <iframe src="data:text/plain,webRequestTest" width="200" height="200"></iframe>
 <iframe src="data:text/plain,webRequestTest_bad" width="200" height="200"></iframe>
 <iframe src="https://invalid.localhost/" width="200" height="200"></iframe>
+<a href="file_WebRequest_page3.html?trigger=a" target="webrequest_link">link</a>
+<form method="post" action="file_WebRequest_page3.html?trigger=form" target="webrequest_form"></form>
+<script>
+"use strict";
+for (let a of document.links) {
+  a.click();
+}
+for (let f of document.forms) {
+  f.submit();
+}
+</script>
 </body>
 </html>
new file mode 100644
--- /dev/null
+++ b/toolkit/components/extensions/test/mochitest/file_WebRequest_page3.html
@@ -0,0 +1,11 @@
+<!DOCTYPE HTML>
+
+<html>
+<head>
+<meta charset="utf-8">
+<script>
+"use strict";
+window.close();
+</script>
+</head>
+</html>
--- a/toolkit/components/extensions/test/mochitest/mochitest.ini
+++ b/toolkit/components/extensions/test/mochitest/mochitest.ini
@@ -1,14 +1,15 @@
 [DEFAULT]
 skip-if = buildapp == 'mulet' || asan
 support-files =
   head.js
   file_WebRequest_page1.html
   file_WebRequest_page2.html
+  file_WebRequest_page3.html
   file_WebNavigation_page1.html
   file_WebNavigation_page2.html
   file_WebNavigation_page3.html
   file_image_good.png
   file_image_bad.png
   file_image_redirect.png
   file_style_good.css
   file_style_bad.css
--- a/toolkit/components/extensions/test/mochitest/test_ext_webrequest.html
+++ b/toolkit/components/extensions/test/mochitest/test_ext_webrequest.html
@@ -93,33 +93,40 @@ function compareLists(list1, list2, kind
   is(String(list1), String(list2), `${kind} URLs correct`);
 }
 
 function backgroundScript() {
   let checkCompleted = true;
   let savedTabId = -1;
 
   function shouldRecord(url) {
-    return url.startsWith(BASE) || /^data:.*\bwebRequestTest|\/invalid\./.test(url);
+    return url.startsWith(BASE) && !url.includes("_page3.html") ||
+           /^data:.*\bwebRequestTest|\/invalid\./.test(url);
   }
 
   let statuses = [
     {url: /_script_good\b/, code: 200, line: /^HTTP\/1.1 200 OK\b/i},
     {url: /\bredirection\b/, code: 302, line: /^HTTP\/1.1 302\b/},
     {url: /\bnonexistent_script_/, code: 404, line: /^HTTP\/1.1 404 Not Found\b/i},
   ];
   function checkStatus(details) {
     for (let {url, code, line} of statuses) {
       if (url.test(details.url)) {
         browser.test.assertEq(code, details.statusCode, `HTTP status code ${code} for ${details.url} (found ${details.statusCode})`);
         browser.test.assertTrue(line.test(details.statusLine), `HTTP status line ${line} for ${details.url} (found ${details.statusLine})`);
       }
     }
   }
 
+  function checkOrigin(details) {
+    let isCorrectOrigin = details.url.includes("_page1.html") ? details.originUrl.endsWith("/test_ext_webrequest.html")
+                                                              : /\/file_WebRequest_page\d\.html\b/.test(details.originUrl);
+    browser.test.assertTrue(isCorrectOrigin, `originUrl for ${details.url} is correct (${details.originUrl})`);
+  }
+
   function checkType(details) {
     let expected_type = "???";
     if (details.url.includes("style")) {
       expected_type = "stylesheet";
     } else if (details.url.includes("image")) {
       expected_type = "image";
     } else if (details.url.includes("script")) {
       expected_type = "script";
@@ -275,16 +282,17 @@ function backgroundScript() {
 
     let ids = requestIDs.get(details.url);
     if (ids) {
       ids.add(details.requestId);
     } else {
       requestIDs.set(details.url, new Set([details.requestId]));
     }
     checkResourceType(details.type);
+    checkOrigin(details);
     if (shouldRecord(details.url)) {
       recorded.requested.push(details.url);
 
       if (savedTabId == -1) {
         browser.test.assertTrue(details.tabId !== undefined, "tab ID defined");
         savedTabId = details.tabId;
       }
 
@@ -306,16 +314,17 @@ function backgroundScript() {
       return {cancel: true};
     }
     return {};
   }
 
   function onBeforeSendHeaders(details) {
     browser.test.log(`onBeforeSendHeaders ${details.url}`);
     checkRequestId(details);
+    checkOrigin(details);
     checkResourceType(details.type);
     processHeaders("request", details);
     if (shouldRecord(details.url)) {
       recorded.beforeSendHeaders.push(details.url);
 
       browser.test.assertEq(details.tabId, savedTabId, "correct tab ID");
       checkType(details);
 
@@ -326,16 +335,17 @@ function backgroundScript() {
       return {redirectUrl: details.url.replace("_redirect.", "_good.")};
     }
     return {requestHeaders: details.requestHeaders};
   }
 
   function onBeforeRedirect(details) {
     browser.test.log(`onBeforeRedirect ${details.url} -> ${details.redirectUrl}`);
     checkRequestId(details, "redirect");
+    checkOrigin(details);
     checkResourceType(details.type);
     if (shouldRecord(details.url)) {
       recorded.beforeRedirect.push(details.url);
 
       browser.test.assertEq(details.tabId, savedTabId, "correct tab ID");
       checkType(details);
       checkStatus(details);
 
@@ -349,16 +359,17 @@ function backgroundScript() {
     }
     return {};
   }
 
   function onRecord(kind, details) {
     browser.test.log(`${kind} ${details.requestId} ${details.url}`);
     checkResourceType(details.type);
     checkRequestId(details, kind);
+    checkOrigin(details);
     if (kind in recorded && shouldRecord(details.url)) {
       recorded[kind].push(details.url);
     }
   }
 
   function onSendHeaders(details) {
     onRecord("sendHeaders", details);
     checkHeaders("request", details);
--- a/toolkit/modules/addons/WebRequest.jsm
+++ b/toolkit/modules/addons/WebRequest.jsm
@@ -120,33 +120,28 @@ var ContentPolicyManager = {
 
     Services.ppmm.addMessageListener("WebRequest:ShouldLoad", this);
     Services.mm.addMessageListener("WebRequest:ShouldLoad", this);
   },
 
   receiveMessage(msg) {
     let browser = msg.target instanceof Ci.nsIDOMXULElement ? msg.target : null;
 
+    let requestId = RequestId.create();
     for (let id of msg.data.ids) {
       let callback = this.policies.get(id);
       if (!callback) {
         // It's possible that this listener has been removed and the
         // child hasn't learned yet.
         continue;
       }
       let response = null;
       let listenerKind = "onStop";
-      let data = {
-        url: msg.data.url,
-        windowId: msg.data.windowId,
-        parentWindowId: msg.data.parentWindowId,
-        type: msg.data.type,
-        browser: browser,
-        requestId: RequestId.create(),
-      };
+      let data = Object.assign({requestId, browser}, msg.data);
+      delete data.ids;
       try {
         response = callback(data);
         if (response) {
           if (response.cancel) {
             listenerKind = "onError";
             data.error = "NS_ERROR_ABORT";
             return {cancel: true};
           }
@@ -510,42 +505,61 @@ HttpObserverManager = {
     let requestHeaderNames;
     let responseHeaderNames;
 
     let includeStatus = kind === "headersReceived" ||
                         kind === "onRedirect" ||
                         kind === "onStart" ||
                         kind === "onStop";
 
+    let commonData = null;
+    let uri = channel.URI;
     for (let [callback, opts] of listeners.entries()) {
-      if (!this.shouldRunListener(policyType, channel.URI, opts.filter)) {
+      if (!this.shouldRunListener(policyType, uri, opts.filter)) {
         continue;
       }
 
-      let data = {
-        requestId: RequestId.get(channel),
-        url: channel.URI.spec,
-        method: channel.requestMethod,
-        browser: browser,
-        type: WebRequestCommon.typeForPolicyType(policyType),
-        windowId: loadInfo ? loadInfo.outerWindowID : 0,
-        parentWindowId: loadInfo ? loadInfo.parentOuterWindowID : 0,
-      };
+      if (!commonData) {
+        commonData = {
+          requestId: RequestId.get(channel),
+          url: uri.spec,
+          method: channel.requestMethod,
+          browser: browser,
+          type: WebRequestCommon.typeForPolicyType(policyType),
+        };
 
-      let httpChannel = channel.QueryInterface(Ci.nsIHttpChannelInternal);
-      try {
-        data.ip = httpChannel.remoteAddress;
-      } catch (e) {
-        // The remoteAddress getter throws if the address is unavailable,
-        // but ip is an optional property so just ignore the exception.
+        if (loadInfo) {
+          let originPrincipal = loadInfo.triggeringPrincipal || loadInfo.loadingPrincipal;
+          if (originPrincipal && originPrincipal.URI) {
+            commonData.originUrl = originPrincipal.URI.spec;
+          }
+          Object.assign(commonData, {
+            windowId: loadInfo.outerWindowID,
+            parentWindowId: loadInfo.parentOuterWindowID,
+          });
+        } else {
+          Object.assign(commonData, {
+            windowId: 0,
+            parentWindowId: 0,
+          });
+        }
+
+        if (channel instanceof Ci.nsIHttpChannelInternal) {
+          try {
+            commonData.ip = channel.remoteAddress;
+          } catch (e) {
+            // The remoteAddress getter throws if the address is unavailable,
+            // but ip is an optional property so just ignore the exception.
+          }
+        }
+        if (extraData) {
+          Object.assign(commonData, extraData);
+        }
       }
-
-      if (extraData) {
-        Object.assign(data, extraData);
-      }
+      let data = Object.assign({}, commonData);
       if (opts.requestHeaders) {
         data.requestHeaders = this.getHeaders(channel, "visitRequestHeaders", kind);
         requestHeaderNames = data.requestHeaders.map(h => h.name);
       }
       if (opts.responseHeaders) {
         data.responseHeaders = this.getHeaders(channel, "visitResponseHeaders", kind);
         responseHeaderNames = data.responseHeaders.map(h => h.name);
       }
--- a/toolkit/modules/addons/WebRequestContent.js
+++ b/toolkit/modules/addons/WebRequestContent.js
@@ -153,17 +153,19 @@ var ContentPolicy = {
       }
     }
 
     let data = {ids,
                 url,
                 type: WebRequestCommon.typeForPolicyType(policyType),
                 windowId,
                 parentWindowId};
-
+    if (requestOrigin) {
+      data.originUrl = requestOrigin.spec;
+    }
     if (block) {
       let rval = mm.sendSyncMessage("WebRequest:ShouldLoad", data);
       if (rval.length == 1 && rval[0].cancel) {
         return Ci.nsIContentPolicy.REJECT;
       }
     } else {
       mm.sendAsyncMessage("WebRequest:ShouldLoad", data);
     }