Bug 1396680 - Add HLS M3U8 MIME types to netmonitor "media" request filter. r=Honza
authortossj <tossj@outlook.com>
Wed, 10 Oct 2018 11:10:28 -0400
changeset 499730 7035f4405e02b2dbcea1934aef9efe534e9ad549
parent 499729 c4a64c83582060ffc3c30501a47cfa59ecc8fab3
child 499731 3ad88a9f8f35bbb61b1b6063a3e39450f8b78d43
push id1864
push userffxbld-merge
push dateMon, 03 Dec 2018 15:51:40 +0000
treeherdermozilla-release@f040763d99ad [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersHonza
bugs1396680
milestone64.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 1396680 - Add HLS M3U8 MIME types to netmonitor "media" request filter. r=Honza
devtools/client/netmonitor/src/utils/filter-predicates.js
devtools/client/netmonitor/test/browser_net_filter-01.js
devtools/client/netmonitor/test/sjs_content-type-test-server.sjs
--- a/devtools/client/netmonitor/src/utils/filter-predicates.js
+++ b/devtools/client/netmonitor/src/utils/filter-predicates.js
@@ -53,17 +53,19 @@ function isImage({ mimeType }) {
   return mimeType && mimeType.includes("image/");
 }
 
 function isMedia({ mimeType }) {
   // Not including images.
   return mimeType && (
     mimeType.includes("audio/") ||
     mimeType.includes("video/") ||
-    mimeType.includes("model/"));
+    mimeType.includes("model/") ||
+    mimeType === "application/vnd.apple.mpegurl" ||
+    mimeType === "application/x-mpegurl");
 }
 
 function isWS({ requestHeaders, responseHeaders }) {
   // Detect a websocket upgrade if request has an Upgrade header with value 'websocket'
   if (!requestHeaders || !Array.isArray(requestHeaders.headers)) {
     return false;
   }
 
--- a/devtools/client/netmonitor/test/browser_net_filter-01.js
+++ b/devtools/client/netmonitor/test/browser_net_filter-01.js
@@ -23,16 +23,18 @@ const BASIC_REQUESTS = [
   { url: `sjs_content-type-test-server.sjs?fmt=js&text=${ENCODED_CHARS_IN_URI_COMP}` },
 ];
 
 const REQUESTS_WITH_MEDIA = BASIC_REQUESTS.concat([
   { url: getSjsURLInUnicodeIdn() + "?fmt=font" },
   { url: "sjs_content-type-test-server.sjs?fmt=image" },
   { url: "sjs_content-type-test-server.sjs?fmt=audio" },
   { url: "sjs_content-type-test-server.sjs?fmt=video" },
+  { url: "sjs_content-type-test-server.sjs?fmt=hls-m3u8" },
+  { url: "sjs_content-type-test-server.sjs?fmt=hls-m3u8-alt-mime-type" },
 ]);
 
 const REQUESTS_WITH_MEDIA_AND_FLASH = REQUESTS_WITH_MEDIA.concat([
   { url: "sjs_content-type-test-server.sjs?fmt=flash" },
 ]);
 
 const REQUESTS_WITH_MEDIA_AND_FLASH_AND_WS = REQUESTS_WITH_MEDIA_AND_FLASH.concat([
   /* "Upgrade" is a reserved header and can not be set on XMLHttpRequest */
@@ -147,16 +149,38 @@ const EXPECTED_REQUESTS = [
       status: 200,
       statusText: "OK",
       type: "webm",
       fullMimeType: "video/webm"
     },
   },
   {
     method: "GET",
+    url: CONTENT_TYPE_SJS + "?fmt=hls-m3u8",
+    data: {
+      fuzzyUrl: true,
+      status: 200,
+      statusText: "OK",
+      type: "x-mpegurl",
+      fullMimeType: "application/x-mpegurl"
+    },
+  },
+  {
+    method: "GET",
+    url: CONTENT_TYPE_SJS + "?fmt=hls-m3u8-alt-mime-type",
+    data: {
+      fuzzyUrl: true,
+      status: 200,
+      statusText: "OK",
+      type: "vnd.apple.mpegurl",
+      fullMimeType: "application/vnd.apple.mpegurl"
+    },
+  },
+  {
+    method: "GET",
     url: CONTENT_TYPE_SJS + "?fmt=flash",
     data: {
       fuzzyUrl: true,
       status: 200,
       statusText: "OK",
       type: "x-shockwave-flash",
       fullMimeType: "application/x-shockwave-flash"
     }
@@ -203,174 +227,174 @@ add_task(async function() {
     "There should be a selected item in the requests menu.");
   is(getSelectedIndex(store.getState()), 0,
     "The first item should be selected in the requests menu.");
   is(!!document.querySelector(".network-details-panel"), true,
     "The network details panel should render correctly.");
 
   // First test with single filters...
   testFilterButtons(monitor, "all");
-  await testContents([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]);
+  await testContents([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]);
 
   EventUtils.sendMouseEvent({ type: "click" },
     document.querySelector(".requests-list-filter-html-button"));
   testFilterButtons(monitor, "html");
-  await testContents([1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0]);
+  await testContents([1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
 
   // Reset filters
   EventUtils.sendMouseEvent({ type: "click" },
     document.querySelector(".requests-list-filter-all-button"));
   EventUtils.sendMouseEvent({ type: "click" },
     document.querySelector(".requests-list-filter-css-button"));
   testFilterButtons(monitor, "css");
-  await testContents([0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0]);
+  await testContents([0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
 
   EventUtils.sendMouseEvent({ type: "click" },
     document.querySelector(".requests-list-filter-all-button"));
   EventUtils.sendMouseEvent({ type: "click" },
     document.querySelector(".requests-list-filter-js-button"));
   testFilterButtons(monitor, "js");
-  await testContents([0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0]);
+  await testContents([0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0]);
 
   EventUtils.sendMouseEvent({ type: "click" },
     document.querySelector(".requests-list-filter-all-button"));
   EventUtils.sendMouseEvent({ type: "click" },
     document.querySelector(".requests-list-filter-xhr-button"));
   testFilterButtons(monitor, "xhr");
-  await testContents([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0]);
+  await testContents([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0]);
 
   EventUtils.sendMouseEvent({ type: "click" },
     document.querySelector(".requests-list-filter-all-button"));
   EventUtils.sendMouseEvent({ type: "click" },
      document.querySelector(".requests-list-filter-fonts-button"));
   testFilterButtons(monitor, "fonts");
-  await testContents([0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0]);
+  await testContents([0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0]);
 
   EventUtils.sendMouseEvent({ type: "click" },
     document.querySelector(".requests-list-filter-all-button"));
   EventUtils.sendMouseEvent({ type: "click" },
     document.querySelector(".requests-list-filter-images-button"));
   testFilterButtons(monitor, "images");
-  await testContents([0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0]);
+  await testContents([0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0]);
 
   EventUtils.sendMouseEvent({ type: "click" },
     document.querySelector(".requests-list-filter-all-button"));
   EventUtils.sendMouseEvent({ type: "click" },
     document.querySelector(".requests-list-filter-media-button"));
   testFilterButtons(monitor, "media");
-  await testContents([0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0]);
+  await testContents([0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0]);
 
   EventUtils.sendMouseEvent({ type: "click" },
     document.querySelector(".requests-list-filter-all-button"));
   EventUtils.sendMouseEvent({ type: "click" },
     document.querySelector(".requests-list-filter-ws-button"));
   testFilterButtons(monitor, "ws");
-  await testContents([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]);
+  await testContents([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]);
 
   EventUtils.sendMouseEvent({ type: "click" },
     document.querySelector(".requests-list-filter-all-button"));
 
   testFilterButtons(monitor, "all");
-  await testContents([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]);
+  await testContents([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]);
 
   // Text in filter box that matches nothing should hide all.
   EventUtils.sendMouseEvent({ type: "click" },
     document.querySelector(".requests-list-filter-all-button"));
   setFreetextFilter("foobar");
-  await testContents([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
+  await testContents([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
 
   // ASCII text in filter box that matches should filter out everything else.
   EventUtils.sendMouseEvent({ type: "click" },
     document.querySelector(".requests-list-filter-all-button"));
   setFreetextFilter("sample");
-  await testContents([1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
+  await testContents([1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
 
   // ASCII text in filter box that matches should filter out everything else.
   EventUtils.sendMouseEvent({ type: "click" },
     document.querySelector(".requests-list-filter-all-button"));
   setFreetextFilter("SAMPLE");
-  await testContents([1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
+  await testContents([1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
 
   // Test negative filtering ASCII text(only show unmatched items)
   EventUtils.sendMouseEvent({ type: "click" },
     document.querySelector(".requests-list-filter-all-button"));
   setFreetextFilter("-sample");
-  await testContents([0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1]);
+  await testContents([0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]);
 
   // Unicode text in filter box that matches should filter out everything else.
   EventUtils.sendMouseEvent({ type: "click" },
     document.querySelector(".requests-list-filter-all-button"));
   setFreetextFilter(UNICODE_IN_URI_COMPONENT);
-  await testContents([0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0]);
+  await testContents([0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0]);
 
   // Ditto, except the above is for a Unicode URI component, and this one is for
   // a Unicode domain name.
   EventUtils.sendMouseEvent({ type: "click" },
     document.querySelector(".requests-list-filter-all-button"));
   setFreetextFilter(UNICODE_IN_IDN);
-  await testContents([1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0]);
+  await testContents([1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0]);
 
   // Test negative filtering Unicode text(only show unmatched items)
   EventUtils.sendMouseEvent({ type: "click" },
     document.querySelector(".requests-list-filter-all-button"));
   setFreetextFilter(`-${UNICODE_IN_URI_COMPONENT}`);
-  await testContents([1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1]);
+  await testContents([1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1]);
 
   // Ditto, except the above is for a Unicode URI component, and this one is for
   // a Unicode domain name.
   EventUtils.sendMouseEvent({ type: "click" },
     document.querySelector(".requests-list-filter-all-button"));
   setFreetextFilter(`-${UNICODE_IN_IDN}`);
-  await testContents([0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1]);
+  await testContents([0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1]);
 
   // ...then combine multiple filters together.
 
   // Enable filtering for html and css; should show request of both type.
   setFreetextFilter("");
   EventUtils.sendMouseEvent({ type: "click" },
     document.querySelector(".requests-list-filter-html-button"));
   EventUtils.sendMouseEvent({ type: "click" },
     document.querySelector(".requests-list-filter-css-button"));
   testFilterButtonsCustom(monitor, [0, 1, 1, 0, 0, 0, 0, 0, 0, 0]);
-  await testContents([1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0]);
+  await testContents([1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
 
   // Html and css filter enabled and text filter should show just the html and css match.
   // Should not show both the items matching the button plus the items matching the text.
   setFreetextFilter("sample");
-  await testContents([1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
+  await testContents([1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
   setFreetextFilter(UNICODE_IN_URI_COMPONENT);
-  await testContents([0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0]);
+  await testContents([0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
   setFreetextFilter("");
   testFilterButtonsCustom(monitor, [0, 1, 1, 0, 0, 0, 0, 0, 0, 0]);
-  await testContents([1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0]);
+  await testContents([1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
 
   // Disable some filters. Only one left active.
   EventUtils.sendMouseEvent({ type: "click" },
     document.querySelector(".requests-list-filter-css-button"));
   testFilterButtons(monitor, "html");
-  await testContents([1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0]);
+  await testContents([1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
 
   // Disable last active filter. Should toggle to all.
   EventUtils.sendMouseEvent({ type: "click" },
     document.querySelector(".requests-list-filter-html-button"));
   testFilterButtons(monitor, "all");
-  await testContents([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]);
+  await testContents([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]);
 
   // Enable few filters and click on all. Only "all" should be checked.
   EventUtils.sendMouseEvent({ type: "click" },
     document.querySelector(".requests-list-filter-html-button"));
   EventUtils.sendMouseEvent({ type: "click" },
     document.querySelector(".requests-list-filter-css-button"));
   EventUtils.sendMouseEvent({ type: "click" },
     document.querySelector(".requests-list-filter-ws-button"));
   testFilterButtonsCustom(monitor, [0, 1, 1, 0, 0, 0, 0, 0, 1, 0]);
   EventUtils.sendMouseEvent({ type: "click" },
     document.querySelector(".requests-list-filter-all-button"));
   testFilterButtons(monitor, "all");
-  await testContents([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]);
+  await testContents([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]);
 
   await teardown(monitor);
 
   function getSelectedIndex(state) {
     if (!state.requests.selectedId) {
       return -1;
     }
     return getSortedRequests(state).findIndex(r => r.id === state.requests.selectedId);
--- a/devtools/client/netmonitor/test/sjs_content-type-test-server.sjs
+++ b/devtools/client/netmonitor/test/sjs_content-type-test-server.sjs
@@ -261,16 +261,24 @@ function handleRequest(request, response
       case "hls-m3u8": {
         response.setStatusLine(request.httpVersion, status, "OK");
         response.setHeader("Content-Type", "application/x-mpegurl", false);
         setCacheHeaders();
         response.write("#EXTM3U\n");
         response.finish();
         break;
       }
+      case "hls-m3u8-alt-mime-type": {
+        response.setStatusLine(request.httpVersion, status, "OK");
+        response.setHeader("Content-Type", "application/vnd.apple.mpegurl", false);
+        setCacheHeaders();
+        response.write("#EXTM3U\n");
+        response.finish();
+        break;
+      }
       case "mpeg-dash": {
         response.setStatusLine(request.httpVersion, status, "OK");
         response.setHeader("Content-Type", "video/vnd.mpeg.dash.mpd", false);
         setCacheHeaders();
         response.write('<?xml version="1.0" encoding="UTF-8"?>\n');
         response.write('<MPD xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"></MPD>\n');
         response.finish();
         break;