Bug 1581512 - Use plain or octetStream as default mime for XTCO. r=ckerschb, a=jcristau
authorSebastian Streich <sstreich@mozilla.com>
Thu, 26 Sep 2019 10:06:05 +0000
changeset 552364 27a820b8753a1320bb724b7fd164fe487a3f1729
parent 552363 5d88242a100d287b7559b420ea0fe5952c7be425
child 552365 9e9523dd9fe95bac23c481080398341d688617e9
push id12155
push userjcristau@mozilla.com
push dateThu, 10 Oct 2019 14:13:03 +0000
treeherdermozilla-beta@2ce58a99cbfd [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersckerschb, jcristau
bugs1581512
milestone70.0
Bug 1581512 - Use plain or octetStream as default mime for XTCO. r=ckerschb, a=jcristau Differential Revision: https://phabricator.services.mozilla.com/D46004
dom/security/test/general/file_nosniff_navigation_mismatch.sjs
dom/security/test/general/test_nosniff_navigation.html
netwerk/base/nsNetUtil.cpp
netwerk/streamconv/converters/nsUnknownDecoder.cpp
--- a/dom/security/test/general/file_nosniff_navigation_mismatch.sjs
+++ b/dom/security/test/general/file_nosniff_navigation_mismatch.sjs
@@ -22,12 +22,12 @@ function getSniffableContent(selector){
   }
   return "Basic UTF-8 Text";
 }
 
 function handleRequest(request, response)
 {
   // avoid confusing cache behaviors
   response.setHeader('X-Content-Type-Options', 'nosniff'); // Disable Sniffing
-  response.setHeader("Content-Type","picture/png");  // Try Browser to force sniffing. 
+  response.setHeader("Content-Type","image/png");  // Send a wrong mime type
   response.write(getSniffableContent(request.queryString));
   return;
 }
--- a/dom/security/test/general/test_nosniff_navigation.html
+++ b/dom/security/test/general/test_nosniff_navigation.html
@@ -6,32 +6,38 @@
   <script src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
   <style>
     iframe{
       border: 1px solid orange;
     }
   </style>
 
-  <iframe src="file_nosniff_navigation.sjs?xml"> </iframe>
-  <iframe src="file_nosniff_navigation.sjs?html"></iframe>
-  <iframe src="file_nosniff_navigation.sjs?css" ></iframe>
-  <iframe src="file_nosniff_navigation.sjs?json"></iframe>
-  <iframe src="file_nosniff_navigation.sjs?img"></iframe>
+  <iframe class="no-mime" src="file_nosniff_navigation.sjs?xml"> </iframe>
+  <iframe class="no-mime" src="file_nosniff_navigation.sjs?html"></iframe>
+  <iframe class="no-mime" src="file_nosniff_navigation.sjs?css" ></iframe>
+  <iframe class="no-mime" src="file_nosniff_navigation.sjs?json"></iframe>
+  <iframe class="no-mime" src="file_nosniff_navigation.sjs?img"></iframe>
+  <iframe class="no-mime" src="file_nosniff_navigation.sjs"></iframe>
  
   <hr>
-  <iframe src="file_nosniff_navigation_mismatch.sjs?html"></iframe>
-  <iframe src="file_nosniff_navigation_mismatch.sjs?xml"></iframe>
-  <iframe src="file_nosniff_navigation_mismatch.sjs"></iframe>
+  <iframe class="mismatch-mime" src="file_nosniff_navigation_mismatch.sjs?html"></iframe>
+  <iframe class="mismatch-mime" src="file_nosniff_navigation_mismatch.sjs?xml"></iframe>
+  <iframe class="mismatch-mime" src="file_nosniff_navigation_mismatch.sjs?css"></iframe>
+  <iframe class="mismatch-mime" src="file_nosniff_navigation_mismatch.sjs?json"></iframe>
+  <iframe class="mismatch-mime" src="file_nosniff_navigation_mismatch.sjs?img"></iframe>
+  <iframe class="mismatch-mime" src="file_nosniff_navigation_mismatch.sjs"></iframe>
+  <hr>
 
-  <iframe src="file_nosniff_navigation_garbage.sjs?xml"> </iframe>
-  <iframe src="file_nosniff_navigation_garbage.sjs?html"></iframe>
-  <iframe src="file_nosniff_navigation_garbage.sjs?css" ></iframe>
-  <iframe src="file_nosniff_navigation_garbage.sjs?json"></iframe>
-  <iframe src="file_nosniff_navigation_garbage.sjs?img"></iframe>
+  <iframe class="garbage-mime" src="file_nosniff_navigation_garbage.sjs?xml"> </iframe>
+  <iframe class="garbage-mime" src="file_nosniff_navigation_garbage.sjs?html"></iframe>
+  <iframe class="garbage-mime" src="file_nosniff_navigation_garbage.sjs?css" ></iframe>
+  <iframe class="garbage-mime" src="file_nosniff_navigation_garbage.sjs?json"></iframe>
+  <iframe class="garbage-mime" src="file_nosniff_navigation_garbage.sjs?img"></iframe>
+  <iframe class="garbage-mime" src="file_nosniff_navigation_garbage.sjs"></iframe>
  
 
 </head>
 <body>
 
 <!-- add the two script tests -->
 <script id="scriptCorrectType"></script>
 <script id="scriptWrongType"></script>
@@ -45,21 +51,42 @@
  * So we will try to open different content send with
  * no-mime, mismatched-mime and garbage-mime types.
  * 
  */
 
 SimpleTest.waitForExplicitFinish();
 
 window.addEventListener("load", ()=>{
-  let iframes = Array.from(document.querySelectorAll("iframe"));
+  let noMimeFrames = Array.from(document.querySelectorAll(".no-mime"));
+
+  noMimeFrames.forEach( frame => {
+    // In case of no Provided Content Type, not rendering or assuming text/plain is valid
+    let result = frame.contentWindow.document.URL == "about:blank" || frame.contentWindow.document.contentType == "text/plain";
+    let sniffTarget = (new URL(frame.src)).search;
+    ok(result, `${sniffTarget} without MIME - was not Sniffed`);
+  });
 
-  iframes.forEach( frame => {
+  let mismatchedMimes = Array.from(document.querySelectorAll(".mismatch-mime"));
+  mismatchedMimes.forEach(frame => {
+    // In case the Server mismatches the Mime Type (sends content X as image/png)
+    // assert that we do not sniff and correct this.
+    let result = frame.contentWindow.document.contentType == "image/png";
+    let sniffTarget = (new URL(frame.src)).search;
+    ok(result, `${sniffTarget} send as image/png - was not Sniffed`);
+  });
+
+  let badMimeFrames = Array.from(document.querySelectorAll(".garbage-mime"));
+
+  badMimeFrames.forEach( frame => {
+    // In the case we got a bogous mime, assert that we dont sniff. 
+    // We must not default here to text/plain
+    // as the Server at least provided a mime type. 
     let result = frame.contentWindow.document.URL == "about:blank";
     let sniffTarget = (new URL(frame.src)).search;
-    ok(result, `${sniffTarget} - was not Sniffed`);
+    ok(result, `${sniffTarget} send as garbage/garbage - was not Sniffed`);
   });
   
   SimpleTest.finish();
 });
 </script>
 </body>
 </html>
--- a/netwerk/base/nsNetUtil.cpp
+++ b/netwerk/base/nsNetUtil.cpp
@@ -2723,45 +2723,16 @@ void NS_SniffContent(const char* aSniffe
     nsresult rv = sniffers[i]->GetMIMETypeFromContent(aRequest, aData, aLength,
                                                       aSniffedType);
     if (NS_SUCCEEDED(rv) && !aSniffedType.IsEmpty()) {
       return;
     }
   }
 
   aSniffedType.Truncate();
-
-  // If the Sniffers did not hit and NoSniff is set
-  // Check if we have any MIME Type at all or report an
-  // Error to the Console
-  nsCOMPtr<nsIHttpChannel> channel = do_QueryInterface(aRequest);
-  if (channel) {
-    nsCOMPtr<nsILoadInfo> loadInfo = channel->LoadInfo();
-
-    if (loadInfo->GetSkipContentSniffing()) {
-      nsAutoCString type;
-      channel->GetContentType(type);
-
-      if (type.Equals(nsCString("application/x-unknown-content-type"))) {
-        nsCOMPtr<nsIURI> requestUri;
-        channel->GetURI(getter_AddRefs(requestUri));
-        nsAutoCString spec;
-        requestUri->GetSpec(spec);
-        if (spec.Length() > 50) {
-          spec.Truncate(50);
-          spec.AppendLiteral("...");
-        }
-        channel->LogMimeTypeMismatch(
-            nsCString("XTCOWithMIMEValueMissing"), false,
-            NS_ConvertUTF8toUTF16(spec),
-            // Type is not used in the Error Message but required
-            NS_ConvertUTF8toUTF16(type));
-      }
-    }
-  }
 }
 
 bool NS_IsSrcdocChannel(nsIChannel* aChannel) {
   bool isSrcdoc;
   nsCOMPtr<nsIInputStreamChannel> isr = do_QueryInterface(aChannel);
   if (isr) {
     isr->GetIsSrcdocChannel(&isSrcdoc);
     return isSrcdoc;
--- a/netwerk/streamconv/converters/nsUnknownDecoder.cpp
+++ b/netwerk/streamconv/converters/nsUnknownDecoder.cpp
@@ -407,18 +407,41 @@ void nsUnknownDecoder::DetermineContentT
     NS_ASSERTION(mContentType.IsEmpty(), "Content type is already known.");
     if (!mContentType.IsEmpty()) return;
   }
 
   nsCOMPtr<nsIHttpChannel> channel(do_QueryInterface(aRequest));
   if (channel) {
     nsCOMPtr<nsILoadInfo> loadInfo = channel->LoadInfo();
     if (loadInfo->GetSkipContentSniffing()) {
-      MutexAutoLock lock(mMutex);
-      mContentType = UNKNOWN_CONTENT_TYPE;
+      /*
+       * If we did not get a useful Content-Type from the server
+       * but also have sniffing disabled, just determine whether
+       * to use text/plain or octetstream and log an error to the Console
+       */
+      LastDitchSniff(aRequest);
+
+      nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aRequest));
+      if (httpChannel) {
+        nsAutoCString type;
+        httpChannel->GetContentType(type);
+        nsCOMPtr<nsIURI> requestUri;
+        httpChannel->GetURI(getter_AddRefs(requestUri));
+        nsAutoCString spec;
+        requestUri->GetSpec(spec);
+        if (spec.Length() > 50) {
+          spec.Truncate(50);
+          spec.AppendLiteral("...");
+        }
+        httpChannel->LogMimeTypeMismatch(
+            NS_LITERAL_CSTRING("XTCOWithMIMEValueMissing"), false,
+            NS_ConvertUTF8toUTF16(spec),
+            // Type is not used in the Error Message but required
+            NS_ConvertUTF8toUTF16(type));
+      }
       return;
     }
   }
 
   const char* testData = mBuffer;
   uint32_t testDataLen = mBufferLen;
   // Check if data are compressed.
   nsAutoCString decodedData;
@@ -622,22 +645,16 @@ bool nsUnknownDecoder::SniffURI(nsIReque
 // encodings like Shift_JIS) as non-text
 #define IS_TEXT_CHAR(ch) \
   (((unsigned char)(ch)) > 31 || (9 <= (ch) && (ch) <= 13) || (ch) == 27)
 
 bool nsUnknownDecoder::LastDitchSniff(nsIRequest* aRequest) {
   // All we can do now is try to guess whether this is text/plain or
   // application/octet-stream
 
-  nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest));
-  nsCOMPtr<nsILoadInfo> loadInfo = channel->LoadInfo();
-  if (loadInfo->GetSkipContentSniffing()) {
-    return false;
-  }
-
   MutexAutoLock lock(mMutex);
 
   const char* testData;
   uint32_t testDataLen;
   if (mDecodedData.IsEmpty()) {
     testData = mBuffer;
     testDataLen = mBufferLen;
   } else {
@@ -851,16 +868,17 @@ nsUnknownDecoder::CheckListenerChain() {
 void nsBinaryDetector::DetermineContentType(nsIRequest* aRequest) {
   nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aRequest);
   if (!httpChannel) {
     return;
   }
 
   nsCOMPtr<nsILoadInfo> loadInfo = httpChannel->LoadInfo();
   if (loadInfo->GetSkipContentSniffing()) {
+    LastDitchSniff(aRequest);
     return;
   }
   // It's an HTTP channel.  Check for the text/plain mess
   nsAutoCString contentTypeHdr;
   Unused << httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("Content-Type"),
                                            contentTypeHdr);
   nsAutoCString contentType;
   httpChannel->GetContentType(contentType);