Bug 1367478 support websocket ws/wss protocol in matchpattern, r=kmag
authorShane Caraveo <scaraveo@mozilla.com>
Wed, 07 Jun 2017 12:16:14 -0700
changeset 411207 62e44a82730804257046e8fe9aafd8d53652d6ea
parent 411206 c608727501c7c6c4c11904b68a3b6963a23af464
child 411208 76a620a287bfa2bf79971613d2a28093c687c65b
push id7391
push usermtabara@mozilla.com
push dateMon, 12 Jun 2017 13:08:53 +0000
treeherdermozilla-beta@2191d7f87e2e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskmag
bugs1367478
milestone55.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
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;