Bug 781782 part 2. Lowercase the content type in the Blob and File constructors and Blob.slice. r=baku
authorBoris Zbarsky <bzbarsky@mit.edu>
Mon, 28 Nov 2016 15:58:15 -0500
changeset 324474 9acaf2d4db150126a2670e6a1a284b3d7fcb73c1
parent 324473 60d9b4f5054439f892ecf5f524d2fdd188d793e6
child 324475 1e5621e43ac66ff8e06fe9a682780c3a187996d3
push id24
push usermaklebus@msu.edu
push dateTue, 20 Dec 2016 03:11:33 +0000
reviewersbaku
bugs781782
milestone53.0a1
Bug 781782 part 2. Lowercase the content type in the Blob and File constructors and Blob.slice. r=baku
dom/base/File.cpp
dom/base/File.h
testing/web-platform/meta/FileAPI/blob/Blob-constructor.html.ini
testing/web-platform/meta/FileAPI/blob/Blob-slice.html.ini
testing/web-platform/meta/FileAPI/file/File-constructor.html.ini
--- a/dom/base/File.cpp
+++ b/dom/base/File.cpp
@@ -153,46 +153,52 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(
   NS_INTERFACE_MAP_ENTRY(nsIXHRSendable)
   NS_INTERFACE_MAP_ENTRY(nsIMutable)
   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(Blob)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(Blob)
 
+// A utility function that enforces the spec constraints on the type of a blob:
+// no codepoints outside the ASCII range (otherwise type becomes empty) and
+// lowercase ASCII only.  We can't just use our existing nsContentUtils
+// ASCII-related helpers because we need the "outside ASCII range" check, and we
+// can't use NS_IsAscii because its definition of "ASCII" (chars all <= 0x7E)
+// differs from the file API definition (which excludes control chars).
+static void
+MakeValidBlobType(nsAString& aType)
+{
+  char16_t* iter = aType.BeginWriting();
+  char16_t* end = aType.EndWriting();
+
+  for ( ; iter != end; ++iter) {
+    char16_t c = *iter;
+    if (c < 0x20 || c > 0x7E) {
+      // Non-ASCII char, bail out.
+      aType.Truncate();
+      return;
+    }
+
+    if (c >= 'A' && c <= 'Z') {
+      *iter = c + ('a' - 'A');
+    }
+  }
+}
+
 /* static */ Blob*
 Blob::Create(nsISupports* aParent, BlobImpl* aImpl)
 {
   MOZ_ASSERT(aImpl);
 
   return aImpl->IsFile() ? new File(aParent, aImpl)
                          : new Blob(aParent, aImpl);
 }
 
 /* static */ already_AddRefed<Blob>
-Blob::Create(nsISupports* aParent, const nsAString& aContentType,
-             uint64_t aLength)
-{
-  RefPtr<Blob> blob = Blob::Create(aParent,
-    new BlobImplBase(aContentType, aLength));
-  MOZ_ASSERT(!blob->mImpl->IsFile());
-  return blob.forget();
-}
-
-/* static */ already_AddRefed<Blob>
-Blob::Create(nsISupports* aParent, const nsAString& aContentType,
-             uint64_t aStart, uint64_t aLength)
-{
-  RefPtr<Blob> blob = Blob::Create(aParent,
-    new BlobImplBase(aContentType, aStart, aLength));
-  MOZ_ASSERT(!blob->mImpl->IsFile());
-  return blob.forget();
-}
-
-/* static */ already_AddRefed<Blob>
 Blob::CreateStringBlob(nsISupports* aParent, const nsACString& aData,
                        const nsAString& aContentType)
 {
   RefPtr<BlobImpl> blobImpl = BlobImplString::Create(aData, aContentType);
   RefPtr<Blob> blob = Blob::Create(aParent, blobImpl);
   MOZ_ASSERT(!blob->mImpl->IsFile());
   return blob.forget();
 }
@@ -355,17 +361,19 @@ Blob::WrapObject(JSContext* aCx, JS::Han
 Blob::Constructor(const GlobalObject& aGlobal,
                   const Optional<Sequence<BlobPart>>& aData,
                   const BlobPropertyBag& aBag,
                   ErrorResult& aRv)
 {
   RefPtr<MultipartBlobImpl> impl = new MultipartBlobImpl();
 
   if (aData.WasPassed()) {
-    impl->InitializeBlob(aGlobal.Context(), aData.Value(), aBag.mType,
+    nsAutoString type(aBag.mType);
+    MakeValidBlobType(type);
+    impl->InitializeBlob(aGlobal.Context(), aData.Value(), type,
                          aBag.mEndings == EndingTypes::Native, aRv);
   } else {
     impl->InitializeBlob(aRv);
   }
 
   if (NS_WARN_IF(aRv.Failed())) {
     return nullptr;
   }
@@ -544,17 +552,19 @@ ParseSize(int64_t aSize, int64_t& aStart
 File::Constructor(const GlobalObject& aGlobal,
                   const Sequence<BlobPart>& aData,
                   const nsAString& aName,
                   const FilePropertyBag& aBag,
                   ErrorResult& aRv)
 {
   RefPtr<MultipartBlobImpl> impl = new MultipartBlobImpl(aName);
 
-  impl->InitializeBlob(aGlobal.Context(), aData, aBag.mType, false, aRv);
+  nsAutoString type(aBag.mType);
+  MakeValidBlobType(type);
+  impl->InitializeBlob(aGlobal.Context(), aData, type, false, aRv);
   if (aRv.Failed()) {
     return nullptr;
   }
   MOZ_ASSERT(impl->IsFile());
 
   if (aBag.mLastModified.WasPassed()) {
     impl->SetLastModified(aBag.mLastModified.Value());
   }
@@ -635,18 +645,19 @@ BlobImpl::Slice(const Optional<int64_t>&
     return nullptr;
   }
 
   int64_t start = aStart.WasPassed() ? aStart.Value() : 0;
   int64_t end = aEnd.WasPassed() ? aEnd.Value() : (int64_t)thisLength;
 
   ParseSize((int64_t)thisLength, start, end);
 
-  return CreateSlice((uint64_t)start, (uint64_t)(end - start),
-                     aContentType, aRv);
+  nsAutoString type(aContentType);
+  MakeValidBlobType(type);
+  return CreateSlice((uint64_t)start, (uint64_t)(end - start), type, aRv);
 }
 
 ////////////////////////////////////////////////////////////////////////////
 // BlobImpl implementation
 
 NS_IMPL_ISUPPORTS(BlobImpl, BlobImpl)
 
 ////////////////////////////////////////////////////////////////////////////
--- a/dom/base/File.h
+++ b/dom/base/File.h
@@ -60,24 +60,16 @@ public:
 
   typedef OwningArrayBufferOrArrayBufferViewOrBlobOrUSVString BlobPart;
 
   // This creates a Blob or a File based on the type of BlobImpl.
   static Blob*
   Create(nsISupports* aParent, BlobImpl* aImpl);
 
   static already_AddRefed<Blob>
-  Create(nsISupports* aParent, const nsAString& aContentType,
-         uint64_t aLength);
-
-  static already_AddRefed<Blob>
-  Create(nsISupports* aParent, const nsAString& aContentType, uint64_t aStart,
-         uint64_t aLength);
-
-  static already_AddRefed<Blob>
   CreateStringBlob(nsISupports* aParent, const nsACString& aData,
                    const nsAString& aContentType);
 
   // The returned Blob takes ownership of aMemoryBuffer. aMemoryBuffer will be
   // freed by free so it must be allocated by malloc or something
   // compatible with it.
   static already_AddRefed<Blob>
   CreateMemoryBlob(nsISupports* aParent, void* aMemoryBuffer, uint64_t aLength,
--- a/testing/web-platform/meta/FileAPI/blob/Blob-constructor.html.ini
+++ b/testing/web-platform/meta/FileAPI/blob/Blob-constructor.html.ini
@@ -1,50 +1,6 @@
 [Blob-constructor.html]
-  type: testharness
-  [A plain object should be treated as a sequence for the blobParts argument.]
-    expected: FAIL
-
-  [A plain object with a length property should be treated as a sequence for the blobParts argument.]
-    expected: FAIL
-
-  [Passing an element as the blobParts array should work.]
-    expected: FAIL
-
-  [Passing an platform object that supports indexed properties as the blobParts array should work (window).]
-    expected: FAIL
-
-  [Passing an platform object that supports indexed properties as the blobParts array should work (window with custom toString).]
-    expected: FAIL
-
   [The 'endings' property should be ignored.]
     expected: FAIL
 
   [Newlines should not change when endings is 'native'.]
     expected: FAIL
-
-  [Blob with type "A"]
-    expected: FAIL
-
-  [Blob with type "TEXT/HTML"]
-    expected: FAIL
-
-  [Blob with type "å"]
-    expected: FAIL
-
-  [Blob with type "𐑾"]
-    expected: FAIL
-
-  [Blob with type "\\timage/gif\\t"]
-    expected: FAIL
-
-  [Blob with type "image/gif;"]
-    expected: FAIL
-
-  [Blob with type "İmage/gif"]
-    expected: FAIL
-
-  [Blob with type "ımage/gif"]
-    expected: FAIL
-
-  [Blob with type "image/gif\\0"]
-    expected: FAIL
-
deleted file mode 100644
--- a/testing/web-platform/meta/FileAPI/blob/Blob-slice.html.ini
+++ /dev/null
@@ -1,80 +0,0 @@
-[Blob-slice.html]
-  type: testharness
-  [Invalid contentType ("ÿ")]
-    expected: FAIL
-
-  [Invalid contentType ("te(xt/plain")]
-    expected: FAIL
-
-  [Invalid contentType ("te)xt/plain")]
-    expected: FAIL
-
-  [Invalid contentType ("te<xt/plain")]
-    expected: FAIL
-
-  [Invalid contentType ("te>xt/plain")]
-    expected: FAIL
-
-  [Invalid contentType ("te@xt/plain")]
-    expected: FAIL
-
-  [Invalid contentType ("te,xt/plain")]
-    expected: FAIL
-
-  [Invalid contentType ("te;xt/plain")]
-    expected: FAIL
-
-  [Invalid contentType ("te:xt/plain")]
-    expected: FAIL
-
-  [Invalid contentType ("te\\\\xt/plain")]
-    expected: FAIL
-
-  [Invalid contentType ("te\\"xt/plain")]
-    expected: FAIL
-
-  [Invalid contentType ("te/xt/plain")]
-    expected: FAIL
-
-  [Invalid contentType ("te[xt/plain")]
-    expected: FAIL
-
-  [Invalid contentType ("te\]xt/plain")]
-    expected: FAIL
-
-  [Invalid contentType ("te?xt/plain")]
-    expected: FAIL
-
-  [Invalid contentType ("te=xt/plain")]
-    expected: FAIL
-
-  [Invalid contentType ("te{xt/plain")]
-    expected: FAIL
-
-  [Invalid contentType ("te}xt/plain")]
-    expected: FAIL
-
-  [Invalid contentType ("te xt/plain")]
-    expected: FAIL
-
-  [Invalid contentType ("te\\txt/plain")]
-    expected: FAIL
-
-  [Invalid contentType ("te\\0xt/plain")]
-    expected: FAIL
-
-  [Invalid contentType ("te\\x1fxt/plain")]
-    expected: FAIL
-
-  [Invalid contentType ("text/plain")]
-    expected: FAIL
-
-  [Valid contentType ("TEXT/PLAIN")]
-    expected: FAIL
-
-  [Valid contentType ("text/plain;charset = UTF-8")]
-    expected: FAIL
-
-  [Valid contentType ("text/plain;charset=UTF-8")]
-    expected: FAIL
-
--- a/testing/web-platform/meta/FileAPI/file/File-constructor.html.ini
+++ b/testing/web-platform/meta/FileAPI/file/File-constructor.html.ini
@@ -1,11 +1,4 @@
 [File-constructor.html]
   type: testharness
   [Using special character in fileName]
     expected: FAIL
-
-  [Using uppercase characters in type]
-    expected: FAIL
-
-  [Using illegal character for type]
-    expected: FAIL
-