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 489552 7035f4405e02b2dbcea1934aef9efe534e9ad549
parent 489551 c4a64c83582060ffc3c30501a47cfa59ecc8fab3
child 489553 3ad88a9f8f35bbb61b1b6063a3e39450f8b78d43
push id247
push userfmarier@mozilla.com
push dateSat, 27 Oct 2018 01:06:44 +0000
reviewersHonza
bugs1396680
milestone64.0a1
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;