Bug 1367478 support websocket ws/wss protocol in matchpattern, r?kmag draft
authorShane Caraveo <scaraveo@mozilla.com>
Wed, 07 Jun 2017 12:16:14 -0700
changeset 590386 78a851011ba0017974bfd32a64b2683d3a33b70f
parent 589150 cad53f061da634a16ea75887558301b77f65745d
child 632223 33fb6b217238cf16c3e350a6059b9940721e5bd1
push id62741
push usermixedpuppy@gmail.com
push dateWed, 07 Jun 2017 19:16:34 +0000
reviewerskmag
bugs1367478
milestone55.0a1
Bug 1367478 support websocket ws/wss protocol in matchpattern, r?kmag MozReview-Commit-ID: 6cnRyWRnRzT
toolkit/components/extensions/MatchPattern.cpp
toolkit/components/extensions/schemas/manifest.json
toolkit/components/extensions/test/mochitest/mochitest-common.ini
toolkit/components/extensions/test/mochitest/test_ext_webrequest_websocket.html
toolkit/modules/addons/WebRequest.jsm
--- a/toolkit/components/extensions/MatchPattern.cpp
+++ b/toolkit/components/extensions/MatchPattern.cpp
@@ -243,19 +243,19 @@ CookieInfo::RawHost() const
   return mRawHost;
 }
 
 
 /*****************************************************************************
  * MatchPattern
  *****************************************************************************/
 
-const char* PERMITTED_SCHEMES[] = {"http", "https", "file", "ftp", "data", nullptr};
+const char* PERMITTED_SCHEMES[] = {"http", "https", "ws", "wss", "file", "ftp", "data", nullptr};
 
-const char* WILDCARD_SCHEMES[] = {"http", "https", nullptr};
+const char* WILDCARD_SCHEMES[] = {"http", "https", "ws", "wss", nullptr};
 
 /* static */ already_AddRefed<MatchPattern>
 MatchPattern::Constructor(dom::GlobalObject& aGlobal,
                           const nsAString& aPattern,
                           const MatchPatternOptions& aOptions,
                           ErrorResult& aRv)
 {
   RefPtr<MatchPattern> pattern = new MatchPattern(aGlobal.GetAsSupports());
--- a/toolkit/components/extensions/schemas/manifest.json
+++ b/toolkit/components/extensions/schemas/manifest.json
@@ -304,17 +304,17 @@
         "id": "MatchPattern",
         "choices": [
           {
             "type": "string",
             "enum": ["<all_urls>"]
           },
           {
             "type": "string",
-            "pattern": "^(https?|file|ftp|\\*)://(\\*|\\*\\.[^*/]+|[^*/]+)/.*$"
+            "pattern": "^(https?|wss?|file|ftp|\\*)://(\\*|\\*\\.[^*/]+|[^*/]+)/.*$"
           },
           {
             "type": "string",
             "pattern": "^file:///.*$"
           }
         ]
       },
       {
--- a/toolkit/components/extensions/test/mochitest/mochitest-common.ini
+++ b/toolkit/components/extensions/test/mochitest/mochitest-common.ini
@@ -109,13 +109,14 @@ skip-if = os == 'android'
 [test_ext_webrequest_background_events.html]
 [test_ext_webrequest_basic.html]
 [test_ext_webrequest_filter.html]
 [test_ext_webrequest_frameId.html]
 [test_ext_webrequest_suspend.html]
 [test_ext_webrequest_upload.html]
 skip-if = os == 'android' # Currently fails in emulator tests
 [test_ext_webrequest_permission.html]
+[test_ext_webrequest_websocket.html]
 [test_ext_webnavigation.html]
 [test_ext_webnavigation_filters.html]
 [test_ext_window_postMessage.html]
 [test_ext_subframes_privileges.html]
 [test_ext_xhr_capabilities.html]
new file mode 100644
--- /dev/null
+++ b/toolkit/components/extensions/test/mochitest/test_ext_webrequest_websocket.html
@@ -0,0 +1,56 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+-->
+<head>
+  <title>Basic websocket test</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/ExtensionTestUtils.js"></script>
+  <script type="text/javascript" src="head.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+
+<script class="testbody" type="text/javascript">
+"use strict";
+
+add_task(async function test_webSocket() {
+  let extension = ExtensionTestUtils.loadExtension({
+    manifest: {
+      "permissions": [
+        "webRequest",
+        "webRequestBlocking",
+        "<all_urls>",
+      ],
+    },
+    background() {
+      browser.webRequest.onBeforeRequest.addListener(details => {
+        browser.test.assertEq("ws:", new URL(details.url).protocol, "ws protocol worked");
+        browser.test.notifyPass("websocket");
+      }, {urls: ["*://mochi.test/*"]}, ["blocking"]);
+
+      browser.test.onMessage.addListener(msg => {
+        let ws = new WebSocket("ws://mochi.test:8888/tests/dom/base/test/file_websocket_hello");
+        ws.onopen = (e) => {
+          ws.send("data");
+        };
+        ws.onclose = (e) => {};
+        ws.onerror = (e) => {};
+        ws.onmessage = (e) => {
+          ws.close();
+        };
+      });
+      browser.test.sendMessage("ready");
+    },
+  });
+  await extension.startup();
+  await extension.awaitMessage("ready");
+  extension.sendMessage("go");
+  await extension.awaitFinish();
+  await extension.unload();
+});
+
+</script>
+</head>
+<body>
+</body>
+</html>
--- a/toolkit/modules/addons/WebRequest.jsm
+++ b/toolkit/modules/addons/WebRequest.jsm
@@ -675,16 +675,20 @@ HttpObserverManager = {
       }
     } else if (lastActivity !== this.GOOD_LAST_ACTIVITY &&
                lastActivity !== nsIHttpActivityObserver.ACTIVITY_SUBTYPE_TRANSACTION_CLOSE) {
       channelData.lastActivity = activitySubtype;
     }
   },
 
   shouldRunListener(policyType, uri, filter) {
+    // force the protocol to be ws again.
+    if (policyType == "websocket" && uri.startsWith("http")) {
+      uri = `ws${uri.substring(4)}`;
+    }
     return WebRequestCommon.typeMatches(policyType, filter.types) &&
            WebRequestCommon.urlMatches(uri, filter.urls);
   },
 
   get resultsMap() {
     delete this.resultsMap;
     this.resultsMap = new Map(Object.keys(Cr).map(name => [Cr[name], name]));
     return this.resultsMap;
@@ -756,16 +760,21 @@ HttpObserverManager = {
       browser: loadContext && loadContext.topFrameElement,
       type: WebRequestCommon.typeForPolicyType(policyType),
       fromCache: getData(channel).fromCache,
       // Defaults for a top level request
       windowId: 0,
       parentWindowId: -1,
     };
 
+    // force the protocol to be ws again.
+    if (data.type == "websocket" && data.url.startsWith("http")) {
+      data.url = `ws${data.url.substring(4)}`;
+    }
+
     if (loadInfo) {
       let originPrincipal = loadInfo.triggeringPrincipal;
       if (originPrincipal.URI) {
         data.originUrl = originPrincipal.URI.spec;
       }
       let docPrincipal = loadInfo.loadingPrincipal;
       if (docPrincipal && docPrincipal.URI) {
         data.documentUrl = docPrincipal.URI.spec;