Bug 1048579. Always sniff for media loads. r=bzbarsky
authorRobert O'Callahan <robert@ocallahan.org>
Sat, 23 Aug 2014 00:08:14 +1200
changeset 223037 35899dd747487c9379ad534dba62dae74116d46a
parent 222991 1fcffcc9fc4a9d25edb3ab6a4faccb0240d124f7
child 223038 2b03cc32da6e0ebd306ca40ff331ee1f9e91d309
push id3979
push userraliiev@mozilla.com
push dateMon, 13 Oct 2014 16:35:44 +0000
treeherdermozilla-beta@30f2cc610691 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbzbarsky
bugs1048579
milestone34.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 1048579. Always sniff for media loads. r=bzbarsky
content/html/content/src/HTMLMediaElement.cpp
content/media/test/test_chaining.html
content/media/test/test_contentDuration1.html
content/media/test/test_contentDuration2.html
content/media/test/test_contentDuration3.html
content/media/test/test_contentDuration4.html
content/media/test/test_contentDuration5.html
content/media/test/test_contentDuration6.html
content/media/test/test_contentDuration7.html
content/media/test/test_media_sniffer.html
content/media/test/test_networkState.html
content/media/test/test_seekLies.html
netwerk/base/public/nsIChannel.idl
netwerk/base/src/nsBaseChannel.cpp
netwerk/protocol/http/nsHttpChannel.cpp
netwerk/test/unit/test_force_sniffing.js
netwerk/test/unit/xpcshell.ini
toolkit/components/mediasniffer/nsMediaSniffer.cpp
toolkit/components/mediasniffer/test/unit/test_mediasniffer.js
--- a/content/html/content/src/HTMLMediaElement.cpp
+++ b/content/html/content/src/HTMLMediaElement.cpp
@@ -1196,17 +1196,18 @@ nsresult HTMLMediaElement::LoadResource(
   }
   nsCOMPtr<nsIChannel> channel;
   rv = NS_NewChannel(getter_AddRefs(channel),
                      mLoadingSrc,
                      nullptr,
                      loadGroup,
                      nullptr,
                      nsICachingChannel::LOAD_BYPASS_LOCAL_CACHE_IF_BUSY |
-                     nsIChannel::LOAD_TREAT_APPLICATION_OCTET_STREAM_AS_UNKNOWN,
+                     nsIChannel::LOAD_MEDIA_SNIFFER_OVERRIDES_CONTENT_TYPE |
+                     nsIChannel::LOAD_CALL_CONTENT_SNIFFERS,
                      channelPolicy);
   NS_ENSURE_SUCCESS(rv,rv);
 
   // The listener holds a strong reference to us.  This creates a
   // reference cycle, once we've set mChannel, which is manually broken
   // in the listener's OnStartRequest method after it is finished with
   // the element. The cycle will also be broken if we get a shutdown
   // notification before OnStartRequest fires.  Necko guarantees that
--- a/content/media/test/test_chaining.html
+++ b/content/media/test/test_chaining.html
@@ -1,17 +1,13 @@
 <!DOCTYPE HTML>
 <html>
 <head>
   <title>Media test: chained ogg files.</title>
   <meta charset='utf-8'>
-  <script type="text/javascript" src="/MochiKit/Base.js"></script>
-  <script type="text/javascript" src="/MochiKit/DOM.js"></script>
-  <script type="text/javascript" src="/MochiKit/Style.js"></script>
-  <script type="text/javascript" src="/MochiKit/Signal.js"></script>
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
   <script type="text/javascript" src="manifest.js"></script>
 </head>
 <body>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 var manager = new MediaTestManager;
--- a/content/media/test/test_contentDuration1.html
+++ b/content/media/test/test_contentDuration1.html
@@ -1,17 +1,14 @@
 <!DOCTYPE HTML>
 <html>
 <head>
   <title>Media test: seek test 1</title>
-  <script type="text/javascript" src="/MochiKit/Base.js"></script>
-  <script type="text/javascript" src="/MochiKit/DOM.js"></script>
-  <script type="text/javascript" src="/MochiKit/Style.js"></script>
-  <script type="text/javascript" src="/MochiKit/Signal.js"></script>
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="manifest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body onunload="mediaTestCleanup();">
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 function on_metadataloaded() {
   var v = document.getElementById('v');
--- a/content/media/test/test_contentDuration2.html
+++ b/content/media/test/test_contentDuration2.html
@@ -1,17 +1,14 @@
 <!DOCTYPE HTML>
 <html>
 <head>
   <title>Media test: seek test 1</title>
-  <script type="text/javascript" src="/MochiKit/Base.js"></script>
-  <script type="text/javascript" src="/MochiKit/DOM.js"></script>
-  <script type="text/javascript" src="/MochiKit/Style.js"></script>
-  <script type="text/javascript" src="/MochiKit/Signal.js"></script>
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="manifest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body onunload="mediaTestCleanup();">
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 function on_metadataloaded() {
   var v = document.getElementById('v');
--- a/content/media/test/test_contentDuration3.html
+++ b/content/media/test/test_contentDuration3.html
@@ -1,17 +1,14 @@
 <!DOCTYPE HTML>
 <html>
 <head>
   <title>Media test: seek test 1</title>
-  <script type="text/javascript" src="/MochiKit/Base.js"></script>
-  <script type="text/javascript" src="/MochiKit/DOM.js"></script>
-  <script type="text/javascript" src="/MochiKit/Style.js"></script>
-  <script type="text/javascript" src="/MochiKit/Signal.js"></script>
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="manifest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body onunload="mediaTestCleanup();">
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 function on_metadataloaded() {
   var v = document.getElementById('v');
--- a/content/media/test/test_contentDuration4.html
+++ b/content/media/test/test_contentDuration4.html
@@ -1,17 +1,14 @@
 <!DOCTYPE HTML>
 <html>
 <head>
   <title>Media test: seek test 1</title>
-  <script type="text/javascript" src="/MochiKit/Base.js"></script>
-  <script type="text/javascript" src="/MochiKit/DOM.js"></script>
-  <script type="text/javascript" src="/MochiKit/Style.js"></script>
-  <script type="text/javascript" src="/MochiKit/Signal.js"></script>
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="manifest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body onunload="mediaTestCleanup();">
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 function on_metadataloaded() {
   var v = document.getElementById('v');
--- a/content/media/test/test_contentDuration5.html
+++ b/content/media/test/test_contentDuration5.html
@@ -1,17 +1,14 @@
 <!DOCTYPE HTML>
 <html>
 <head>
   <title>Media test: seek test 1</title>
-  <script type="text/javascript" src="/MochiKit/Base.js"></script>
-  <script type="text/javascript" src="/MochiKit/DOM.js"></script>
-  <script type="text/javascript" src="/MochiKit/Style.js"></script>
-  <script type="text/javascript" src="/MochiKit/Signal.js"></script>
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="manifest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body onunload="mediaTestCleanup();">
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 function on_metadataloaded() {
   var v = document.getElementById('v');
--- a/content/media/test/test_contentDuration6.html
+++ b/content/media/test/test_contentDuration6.html
@@ -1,17 +1,14 @@
 <!DOCTYPE HTML>
 <html>
 <head>
   <title>Media test: seek test 1</title>
-  <script type="text/javascript" src="/MochiKit/Base.js"></script>
-  <script type="text/javascript" src="/MochiKit/DOM.js"></script>
-  <script type="text/javascript" src="/MochiKit/Style.js"></script>
-  <script type="text/javascript" src="/MochiKit/Signal.js"></script>
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="manifest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body onunload="mediaTestCleanup();">
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 function on_metadataloaded() {
   var v = document.getElementById('v');
--- a/content/media/test/test_contentDuration7.html
+++ b/content/media/test/test_contentDuration7.html
@@ -1,19 +1,15 @@
 <!DOCTYPE HTML>
 <html>
 <head>
   <title>Media test: X-Content-Duration</title>
-  <script type="text/javascript" src="/MochiKit/Base.js"></script>
-  <script type="text/javascript" src="/MochiKit/DOM.js"></script>
-  <script type="text/javascript" src="/MochiKit/Style.js"></script>
-  <script type="text/javascript" src="/MochiKit/Signal.js"></script>
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="manifest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
-  <script type="text/javascript" src="manifest.js"></script>
 </head>
 <body onunload="mediaTestCleanup();">
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 function on_metadataloaded() {
   var v = document.getElementById('v');
   var d = Math.round(v.duration*1000);
--- a/content/media/test/test_media_sniffer.html
+++ b/content/media/test/test_media_sniffer.html
@@ -1,64 +1,61 @@
 <!DOCTYPE HTML>
 <html>
 <head>
-  <title>Media test: mozStopDownload</title>
+  <title>Media test: sniffing</title>
   <meta charset='utf-8'>
-  <script type="text/javascript" src="/MochiKit/Base.js"></script>
-  <script type="text/javascript" src="/MochiKit/DOM.js"></script>
-  <script type="text/javascript" src="/MochiKit/Style.js"></script>
-  <script type="text/javascript" src="/MochiKit/Signal.js"></script>
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
   <script type="text/javascript" src="manifest.js"></script>
 </head>
 <body>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 var manager = new MediaTestManager;
 
 function finish_test(element) {
   element.removeEventListener("error", onerror, false);
   removeNodeAndSource(element);
   manager.finished(element.token);
 }
 
-function onApplicationOctetStreamLoaded(e) {
-  var t = e.target;
-  t.removeEventListener('loadedmetadata', onApplicationOctetStreamLoaded);
-  ok(true, "The media loads when served with application/octet-stream.");
-  finish_test(t);
-}
-
-function checkApplicationOctetStream(t) {
-  t.src = t.src.replace("&nomime", "&type=application/octet-stream");
-  t.addEventListener("loadedmetadata", onApplicationOctetStreamLoaded);
-}
-
 function onmetadataloaded(e) {
   var t = e.target;
-  t.removeEventListener('loadedmetadata', onmetadataloaded)
-  ok(true, "The media loads when served without a Content-Type.");
-  checkApplicationOctetStream(t);
+  ++t.srcIndex;
+  ok(true, "The media loads when loaded via " + t.src);
+  if (t.srcIndex < t.srcList.length) {
+    t.src = t.srcList[t.srcIndex];
+  } else {
+    finish_test(t);
+  }
 }
 
 function onerror(e) {
   var t = e.target;
   t.removeEventListener('error', onerror);
   ok(false, "The media could not be loaded." + t.src + "\n");
   finish_test(t);
 }
 
 function startTest(test, token) {
   var elemType = /^audio/.test(test.type) ? "audio" : "video";
   var element = document.createElement(elemType);
   // This .sjs file serve the media file without Content-Type header, or with a
   // specific Content-Type header.
-  element.src = 'contentType.sjs?file=' + test.name + "&nomime";
+  var baseSrc = 'contentType.sjs?file=' + test.name;
+  element.srcList = [
+    baseSrc + "&nomime",
+    baseSrc + "&type=application/octet-stream",
+    baseSrc + "&type=audio/wav",
+    baseSrc + "&type=text/html",
+    baseSrc + "&type=absolute_nonsense"
+  ];
+  element.srcIndex = 0;
+  element.src = element.srcList[element.srcIndex];
   element.token = token;
   element.controls = true;
   element.preload = "metadata";
   document.body.appendChild(element);
   manager.started(token);
   element.addEventListener("loadedmetadata", onmetadataloaded);
   element.addEventListener("error", onerror);
 }
--- a/content/media/test/test_networkState.html
+++ b/content/media/test/test_networkState.html
@@ -1,16 +1,12 @@
 <!DOCTYPE HTML>
 <html>
 <head>
   <title>Media test: networkState</title>
-  <script type="text/javascript" src="/MochiKit/Base.js"></script>
-  <script type="text/javascript" src="/MochiKit/DOM.js"></script>
-  <script type="text/javascript" src="/MochiKit/Style.js"></script>
-  <script type="text/javascript" src="/MochiKit/Signal.js"></script>
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
   <script type="text/javascript" src="manifest.js"></script>
 </head>
 <body onunload="mediaTestCleanup();">
 <video id='v1'></video><audio id='a1'></audio>
 <pre id="test">
 <script class="testbody" type="text/javascript">
--- a/content/media/test/test_seekLies.html
+++ b/content/media/test/test_seekLies.html
@@ -1,17 +1,14 @@
 <!DOCTYPE HTML>
 <html>
 <head>
   <title>Media test: server lies about range requests</title>
-  <script type="text/javascript" src="/MochiKit/Base.js"></script>
-  <script type="text/javascript" src="/MochiKit/DOM.js"></script>
-  <script type="text/javascript" src="/MochiKit/Style.js"></script>
-  <script type="text/javascript" src="/MochiKit/Signal.js"></script>
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="manifest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body onunload="mediaTestCleanup();">
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 function on_metadataloaded() {
   var v = document.getElementById('v');
--- a/netwerk/base/public/nsIChannel.idl
+++ b/netwerk/base/public/nsIChannel.idl
@@ -236,22 +236,21 @@ interface nsIChannel : nsIRequest
 
     /**
      * This flag tells the channel to use URI classifier service to check
      * the URI when opening the channel.
      */
     const unsigned long LOAD_CLASSIFY_URI = 1 << 22;
 
     /**
-     * If this flag is set and a server's response is Content-Type
-     * application/octet-steam, the server's Content-Type will be ignored and
-     * the channel content will be sniffed as though no Content-Type had been
-     * passed.
+     * If this flag is set, the media-type content sniffer will be allowed
+     * to override any server-set content-type. Otherwise it will only
+     * be allowed to override "no content type" and application/octet-stream.
      */
-    const unsigned long LOAD_TREAT_APPLICATION_OCTET_STREAM_AS_UNKNOWN = 1 << 23;
+    const unsigned long LOAD_MEDIA_SNIFFER_OVERRIDES_CONTENT_TYPE = 1 << 23;
 
     /**
      * Set to let explicitely provided credentials be used over credentials
      * we have cached previously. In some situations like form login using HTTP
      * auth via XMLHttpRequest we need to let consumers override the cached
      * credentials explicitely. For form login 403 response instead of 401 is
      * usually used to prevent an auth dialog. But any code other then 401/7
      * will leave original credentials in the cache and there is then no way
--- a/netwerk/base/src/nsBaseChannel.cpp
+++ b/netwerk/base/src/nsBaseChannel.cpp
@@ -714,25 +714,21 @@ CallUnknownTypeSniffer(void *aClosure, c
     chan->SetContentType(detected);
 }
 
 NS_IMETHODIMP
 nsBaseChannel::OnStartRequest(nsIRequest *request, nsISupports *ctxt)
 {
   MOZ_ASSERT(request == mPump);
 
-  // If our content type is unknown or if the content type is
-  // application/octet-stream and the caller requested it, use the content type
+  // If our content type is unknown, use the content type
   // sniffer. If the sniffer is not available for some reason, then we just keep
   // going as-is.
-  bool shouldSniff = mContentType.EqualsLiteral(UNKNOWN_CONTENT_TYPE) ||
-            ((mLoadFlags & LOAD_TREAT_APPLICATION_OCTET_STREAM_AS_UNKNOWN) &&
-            mContentType.EqualsLiteral(APPLICATION_OCTET_STREAM));
-
-  if (NS_SUCCEEDED(mStatus) && shouldSniff) {
+  if (NS_SUCCEEDED(mStatus) &&
+      mContentType.EqualsLiteral(UNKNOWN_CONTENT_TYPE)) {
     mPump->PeekStream(CallUnknownTypeSniffer, static_cast<nsIChannel*>(this));
   }
 
   // Now, the general type sniffers. Skip this if we have none.
   if (mLoadFlags & LOAD_CALL_CONTENT_SNIFFERS)
     mPump->PeekStream(CallTypeSniffers, static_cast<nsIChannel*>(this));
 
   SUSPEND_PUMP_FOR_SCOPE();
--- a/netwerk/protocol/http/nsHttpChannel.cpp
+++ b/netwerk/protocol/http/nsHttpChannel.cpp
@@ -858,22 +858,18 @@ nsHttpChannel::CallOnStartRequest()
             NS_SUCCEEDED(mCachePump->PeekStream(CallTypeSniffers, thisChannel));
         }
 
         if (!typeSniffersCalled && mTransactionPump) {
           mTransactionPump->PeekStream(CallTypeSniffers, thisChannel);
         }
     }
 
-    bool shouldSniff = mResponseHead && (mResponseHead->ContentType().IsEmpty() ||
-        ((mResponseHead->ContentType().EqualsLiteral(APPLICATION_OCTET_STREAM) &&
-        (mLoadFlags & LOAD_TREAT_APPLICATION_OCTET_STREAM_AS_UNKNOWN))));
-
     bool unknownDecoderStarted = false;
-    if (shouldSniff) {
+    if (mResponseHead && mResponseHead->ContentType().IsEmpty()) {
         MOZ_ASSERT(mConnectionInfo, "Should have connection info here");
         if (!mContentTypeHint.IsEmpty())
             mResponseHead->SetContentType(mContentTypeHint);
         else if (mResponseHead->Version() == NS_HTTP_VERSION_0_9 &&
                  mConnectionInfo->Port() != mConnectionInfo->DefaultPort())
             mResponseHead->SetContentType(NS_LITERAL_CSTRING(TEXT_PLAIN));
         else {
             // Uh-oh.  We had better find out what type we are!
deleted file mode 100644
--- a/netwerk/test/unit/test_force_sniffing.js
+++ /dev/null
@@ -1,90 +0,0 @@
-// This file tests the flag LOAD_TREAT_APPLICATION_OCTET_STREAM_AS_UNKNOWN.
-
-Cu.import("resource://testing-common/httpd.js");
-
-const octetStreamType = "application/octet-stream";
-const sniffedType = "application/x-sniffed";
-
-const snifferCID = Components.ID("{954f3fdd-d717-4c02-9464-7c2da617d21d}");
-const snifferContract = "@mozilla.org/network/unittest/contentsniffer;1";
-const categoryName = "content-sniffing-services";
-
-var sniffer = {
-  QueryInterface: function sniffer_qi(iid) {
-    if (iid.equals(Components.interfaces.nsISupports) ||
-        iid.equals(Components.interfaces.nsIFactory) ||
-        iid.equals(Components.interfaces.nsIContentSniffer))
-      return this;
-    throw Components.results.NS_ERROR_NO_INTERFACE;
-  },
-  createInstance: function sniffer_ci(outer, iid) {
-    if (outer)
-      throw Components.results.NS_ERROR_NO_AGGREGATION;
-    return this.QueryInterface(iid);
-  },
-  lockFactory: function sniffer_lockf(lock) {
-    throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
-  },
-  getMIMETypeFromContent: function (request, data, length) {
-    return sniffedType;
-  }
-};
-
-var listener = {
-  onStartRequest: function test_onStartR(request, ctx) {
-    // We should have sniffed the type of the file.
-    var chan = request.QueryInterface(Components.interfaces.nsIChannel);
-    do_check_eq(chan.contentType, sniffedType);
-  },
-
-  onDataAvailable: function test_ODA() {
-    throw Components.results.NS_ERROR_UNEXPECTED;
-  },
-
-  onStopRequest: function test_onStopR(request, ctx, status) {
-    do_test_finished();
-  }
-};
-
-function handler(metadata, response) {
-  response.setHeader("Content-Type", octetStreamType);
-}
-
-function makeChan(url) {
-  var ios = Components.classes["@mozilla.org/network/io-service;1"]
-                      .getService(Components.interfaces.nsIIOService);
-  var chan = ios.newChannel(url, null, null);
-  // Force sniffing if we have "application/octet-stream" as Content-Type
-  chan.loadFlags |= Components.interfaces
-                              .nsIChannel
-                              .LOAD_TREAT_APPLICATION_OCTET_STREAM_AS_UNKNOWN;
-
-  return chan;
-}
-
-XPCOMUtils.defineLazyGetter(this, "url", function() {
-  return "http://localhost:" + httpserv.identity.primaryPort + "/test";
-});
-
-var httpserv = null;
-
-function run_test() {
-  httpserv = new HttpServer();
-  httpserv.registerPathHandler("/test", handler);
-  httpserv.start(-1);
-
-  // Register our fake sniffer that always returns the content-type we want.
-  Components.manager.nsIComponentRegistrar.registerFactory(snifferCID,
-                       "Unit test content sniffer", snifferContract, sniffer);
-
-  var catMan = Components.classes["@mozilla.org/categorymanager;1"]
-                         .getService(Components.interfaces.nsICategoryManager);
-  catMan.nsICategoryManager.addCategoryEntry(categoryName, snifferContract,
-                                             snifferContract, false, true);
-
-  var chan = makeChan(url);
-  chan.asyncOpen(listener, null);
-
-  do_test_pending();
-}
-
--- a/netwerk/test/unit/xpcshell.ini
+++ b/netwerk/test/unit/xpcshell.ini
@@ -165,17 +165,16 @@ skip-if = bits != 32
 [test_dns_service.js]
 [test_dns_localredirect.js]
 [test_dns_proxy_bypass.js]
 [test_duplicate_headers.js]
 [test_chunked_responses.js]
 [test_content_length_underrun.js]
 [test_event_sink.js]
 [test_extract_charset_from_content_type.js]
-[test_force_sniffing.js]
 [test_fallback_no-cache-entry_canceled.js]
 [test_fallback_no-cache-entry_passing.js]
 [test_fallback_redirect-to-different-origin_canceled.js]
 [test_fallback_redirect-to-different-origin_passing.js]
 [test_fallback_request-error_canceled.js]
 [test_fallback_request-error_passing.js]
 [test_fallback_response-error_canceled.js]
 [test_fallback_response-error_passing.js]
--- a/toolkit/components/mediasniffer/nsMediaSniffer.cpp
+++ b/toolkit/components/mediasniffer/nsMediaSniffer.cpp
@@ -97,27 +97,31 @@ static bool MatchesMP3(const uint8_t* aD
 }
 
 NS_IMETHODIMP
 nsMediaSniffer::GetMIMETypeFromContent(nsIRequest* aRequest,
                                        const uint8_t* aData,
                                        const uint32_t aLength,
                                        nsACString& aSniffedType)
 {
-  // For media, we want to sniff only if the Content-Type is unknown, or if it
-  // is application/octet-stream.
   nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest);
   if (channel) {
-    nsAutoCString contentType;
-    nsresult rv = channel->GetContentType(contentType);
-    NS_ENSURE_SUCCESS(rv, rv);
-    if (!contentType.IsEmpty() &&
-        !contentType.EqualsLiteral(APPLICATION_OCTET_STREAM) &&
-        !contentType.EqualsLiteral(UNKNOWN_CONTENT_TYPE)) {
-      return NS_ERROR_NOT_AVAILABLE;
+    nsLoadFlags loadFlags = 0;
+    channel->GetLoadFlags(&loadFlags);
+    if (!(loadFlags & nsIChannel::LOAD_MEDIA_SNIFFER_OVERRIDES_CONTENT_TYPE)) {
+      // For media, we want to sniff only if the Content-Type is unknown, or if it
+      // is application/octet-stream.
+      nsAutoCString contentType;
+      nsresult rv = channel->GetContentType(contentType);
+      NS_ENSURE_SUCCESS(rv, rv);
+      if (!contentType.IsEmpty() &&
+          !contentType.EqualsLiteral(APPLICATION_OCTET_STREAM) &&
+          !contentType.EqualsLiteral(UNKNOWN_CONTENT_TYPE)) {
+        return NS_ERROR_NOT_AVAILABLE;
+      }
     }
   }
 
   const uint32_t clampedLength = std::min(aLength, MAX_BYTES_SNIFFED);
 
   for (uint32_t i = 0; i < mozilla::ArrayLength(sSnifferEntries); ++i) {
     const nsMediaSnifferEntry& currentEntry = sSnifferEntries[i];
     if (clampedLength < currentEntry.mLength || currentEntry.mLength == 0) {
--- a/toolkit/components/mediasniffer/test/unit/test_mediasniffer.js
+++ b/toolkit/components/mediasniffer/test/unit/test_mediasniffer.js
@@ -14,34 +14,37 @@ var httpserver = new HttpServer();
 const data = "OggS\0meeeh.";
 var testRan = 0;
 
 // If the content-type is not present, or if it's application/octet-stream, it
 // should be sniffed to application/ogg by the media sniffer. Otherwise, it
 // should not be changed.
 const tests = [
   // Those three first case are the case of a media loaded in a media element.
-  // The first two should be sniffeed.
+  // All three should be sniffed.
   { contentType: "",
     expectedContentType: "application/ogg",
-    flags: Ci.nsIChannel.LOAD_TREAT_APPLICATION_OCTET_STREAM_AS_UNKNOWN },
+    flags: Ci.nsIChannel.LOAD_CALL_CONTENT_SNIFFERS | Ci.nsIChannel.LOAD_MEDIA_SNIFFER_OVERRIDES_CONTENT_TYPE },
   { contentType: "application/octet-stream",
     expectedContentType: "application/ogg",
-    flags: Ci.nsIChannel.LOAD_TREAT_APPLICATION_OCTET_STREAM_AS_UNKNOWN },
+    flags: Ci.nsIChannel.LOAD_CALL_CONTENT_SNIFFERS | Ci.nsIChannel.LOAD_MEDIA_SNIFFER_OVERRIDES_CONTENT_TYPE },
   { contentType: "application/something",
-    expectedContentType: "application/something",
-    flags: Ci.nsIChannel.LOAD_TREAT_APPLICATION_OCTET_STREAM_AS_UNKNOWN },
-  // This last case tests the case of a channel opened while allowing content
+    expectedContentType: "application/ogg",
+    flags: Ci.nsIChannel.LOAD_CALL_CONTENT_SNIFFERS | Ci.nsIChannel.LOAD_MEDIA_SNIFFER_OVERRIDES_CONTENT_TYPE },
+  // This last cases test the case of a channel opened while allowing content
   // sniffers to override the content-type, like in the docshell.
   { contentType: "application/octet-stream",
     expectedContentType: "application/ogg",
     flags: Ci.nsIChannel.LOAD_CALL_CONTENT_SNIFFERS },
   { contentType: "",
     expectedContentType: "application/ogg",
     flags: Ci.nsIChannel.LOAD_CALL_CONTENT_SNIFFERS },
+  { contentType: "application/something",
+    expectedContentType: "application/something",
+    flags: Ci.nsIChannel.LOAD_CALL_CONTENT_SNIFFERS },
 ];
 
 // A basic listener that reads checks the if we sniffed properly.
 var listener = {
   onStartRequest: function(request, context) {
     do_check_eq(request.QueryInterface(Ci.nsIChannel).contentType,
                 tests[testRan].expectedContentType);
   },