Bug 906420 - Part 3: Either expose files or strings generated by system drag or clipboard events to content, not both, r=baku
authorMichael Layzell <michael@thelayzells.com>
Tue, 31 May 2016 15:03:44 -0400
changeset 300981 18b3c95f1a38ca9246b877a46c38723731a38885
parent 300980 e3615a8398218b1330ea3f6580022629aefdccc9
child 300982 f9a2e3de2a4afa13f1741ee61b5ef317915c531c
push id19599
push usercbook@mozilla.com
push dateWed, 08 Jun 2016 10:16:21 +0000
treeherderfx-team@81f4cc3f6f4c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbaku
bugs906420
milestone50.0a1
Bug 906420 - Part 3: Either expose files or strings generated by system drag or clipboard events to content, not both, r=baku
dom/events/DataTransfer.cpp
dom/events/DataTransfer.h
dom/events/DataTransferItem.cpp
dom/events/DataTransferItem.h
dom/events/DataTransferItemList.cpp
dom/events/DataTransferItemList.h
--- a/dom/events/DataTransfer.cpp
+++ b/dom/events/DataTransfer.cpp
@@ -318,16 +318,20 @@ DataTransfer::GetTypes(ErrorResult& aRv)
     return types.forget();
   }
 
   bool addFile = false;
   for (uint32_t i = 0; i < items->Length(); i++) {
     DataTransferItem* item = items->ElementAt(i);
     MOZ_ASSERT(item);
 
+    if (item->ChromeOnly() && !nsContentUtils::LegacyIsCallerChromeOrNativeCode()) {
+      continue;
+    }
+
     nsAutoString type;
     item->GetType(type);
     if (NS_WARN_IF(!types->Add(type))) {
       aRv.Throw(NS_ERROR_FAILURE);
       return nullptr;
     }
 
     if (!addFile) {
@@ -533,23 +537,36 @@ DataTransfer::MozTypesAt(uint32_t aIndex
     return nullptr;
   }
 
   RefPtr<DOMStringList> types = new DOMStringList();
   if (aIndex < MozItemCount()) {
     // note that you can retrieve the types regardless of their principal
     const nsTArray<RefPtr<DataTransferItem>>& items = *mItems->MozItemsAt(aIndex);
 
+    bool addFile = false;
     for (uint32_t i = 0; i < items.Length(); i++) {
+      if (items[i]->ChromeOnly() && !nsContentUtils::LegacyIsCallerChromeOrNativeCode()) {
+        continue;
+      }
+
       nsAutoString type;
       items[i]->GetType(type);
       if (NS_WARN_IF(!types->Add(type))) {
         aRv.Throw(NS_ERROR_FAILURE);
         return nullptr;
       }
+
+      if (items[i]->Kind() == DataTransferItem::KIND_FILE) {
+        addFile = true;
+      }
+    }
+
+    if (addFile) {
+      types->Add(NS_LITERAL_STRING("Files"));
     }
   }
 
   return types.forget();
 }
 
 NS_IMETHODIMP
 DataTransfer::MozTypesAt(uint32_t aIndex, nsISupports** aTypes)
@@ -589,26 +606,16 @@ DataTransfer::GetDataAtInternal(const ns
       (mEventMessage == eCut || mEventMessage == eCopy ||
        mEventMessage == ePaste)) {
     return NS_ERROR_DOM_INDEX_SIZE_ERR;
   }
 
   nsAutoString format;
   GetRealFormat(aFormat, format);
 
-  const nsTArray<RefPtr<DataTransferItem>>& items = *mItems->MozItemsAt(aIndex);
-  if (!aFormat.EqualsLiteral(kFileMime) &&
-      !nsContentUtils::IsSystemPrincipal(aSubjectPrincipal)) {
-    for (uint32_t i = 0; i < items.Length(); ++i) {
-      if (items[i]->IsFile()) {
-        return NS_OK;
-      }
-    }
-  }
-
   // Check if the caller is allowed to access the drag data. Callers with
   // chrome privileges can always read the data. During the
   // drop event, allow retrieving the data except in the case where the
   // source of the drag is in a child frame of the caller. In that case,
   // we only allow access to data of the same principal. During other events,
   // only allow access to the data with the same principal.
   bool checkFormatItemPrincipal = mIsCrossDomainSubFrameDrop ||
       (mEventMessage != eDrop && mEventMessage != eLegacyDragDrop &&
@@ -617,16 +624,21 @@ DataTransfer::GetDataAtInternal(const ns
 
   RefPtr<DataTransferItem> item = mItems->MozItemByTypeAt(format, aIndex);
   if (!item) {
     // The index exists but there's no data for the specified format, in this
     // case we just return undefined
     return NS_OK;
   }
 
+  // If we have chrome only content, and we aren't chrome, don't allow access
+  if (!nsContentUtils::IsSystemPrincipal(aSubjectPrincipal) && item->ChromeOnly()) {
+    return NS_OK;
+  }
+
   if (item->Principal() && checkFormatItemPrincipal &&
       !aSubjectPrincipal->Subsumes(item->Principal())) {
     return NS_ERROR_DOM_SECURITY_ERR;
   }
 
   nsCOMPtr<nsIVariant> data = item->Data();
   MOZ_ASSERT(data);
 
@@ -1239,17 +1251,20 @@ DataTransfer::SetDataWithPrincipal(const
                                    uint32_t aIndex,
                                    nsIPrincipal* aPrincipal)
 {
   nsAutoString format;
   GetRealFormat(aFormat, format);
 
   ErrorResult rv;
   RefPtr<DataTransferItem> item =
-    mItems->SetDataWithPrincipal(format, aData, aIndex, aPrincipal, false, rv);
+    mItems->SetDataWithPrincipal(format, aData, aIndex, aPrincipal,
+                                 /* aInsertOnly = */ false,
+                                 /* aHidden= */ false,
+                                 rv);
   return rv.StealNSResult();
 }
 
 void
 DataTransfer::SetDataWithPrincipalFromOtherProcess(const nsAString& aFormat,
                                                    nsIVariant* aData,
                                                    uint32_t aIndex,
                                                    nsIPrincipal* aPrincipal)
@@ -1277,34 +1292,49 @@ DataTransfer::GetRealFormat(const nsAStr
   if (lowercaseFormat.EqualsLiteral("url")) {
     aOutFormat.AssignLiteral("text/uri-list");
     return;
   }
 
   aOutFormat.Assign(lowercaseFormat);
 }
 
-void
+nsresult
 DataTransfer::CacheExternalData(const char* aFormat, uint32_t aIndex,
-                                nsIPrincipal* aPrincipal)
+                                nsIPrincipal* aPrincipal, bool aHidden)
 {
+  ErrorResult rv;
+  RefPtr<DataTransferItem> item;
+
   if (strcmp(aFormat, kUnicodeMime) == 0) {
-    SetDataWithPrincipal(NS_LITERAL_STRING("text/plain"), nullptr, aIndex,
-                         aPrincipal);
-    return;
+    item = mItems->SetDataWithPrincipal(NS_LITERAL_STRING("text/plain"), nullptr,
+                                        aIndex, aPrincipal, false, aHidden, rv);
+    if (NS_WARN_IF(rv.Failed())) {
+      return rv.StealNSResult();
+    }
+    return NS_OK;
   }
 
   if (strcmp(aFormat, kURLDataMime) == 0) {
-    SetDataWithPrincipal(NS_LITERAL_STRING("text/uri-list"), nullptr, aIndex,
-                         aPrincipal);
-    return;
+    item = mItems->SetDataWithPrincipal(NS_LITERAL_STRING("text/uri-list"), nullptr,
+                                        aIndex, aPrincipal, false, aHidden, rv);
+    if (NS_WARN_IF(rv.Failed())) {
+      return rv.StealNSResult();
+    }
+    return NS_OK;
   }
 
-  SetDataWithPrincipal(NS_ConvertUTF8toUTF16(aFormat), nullptr, aIndex,
-                       aPrincipal);
+  nsAutoString format;
+  GetRealFormat(NS_ConvertUTF8toUTF16(aFormat), format);
+  item = mItems->SetDataWithPrincipal(format, nullptr, aIndex,
+                                      aPrincipal, false, aHidden, rv);
+  if (NS_WARN_IF(rv.Failed())) {
+    return rv.StealNSResult();
+  }
+  return NS_OK;
 }
 
 // there isn't a way to get a list of the formats that might be available on
 // all platforms, so just check for the types that can actually be imported
 // XXXndeakin there are some other formats but those are platform specific.
 const char* kFormats[] = { kFileMime, kHTMLMime, kURLMime, kURLDataMime,
                            kUnicodeMime, kPNGImageMime, kJPEGImageMime,
                            kGIFImageMime };
@@ -1332,16 +1362,19 @@ DataTransfer::CacheExternalDragFormats()
   // all platforms, so just check for the types that can actually be imported
   // XXXndeakin there are some other formats but those are platform specific.
   const char* formats[] = { kFileMime, kHTMLMime, kRTFMime,
                             kURLMime, kURLDataMime, kUnicodeMime };
 
   uint32_t count;
   dragSession->GetNumDropItems(&count);
   for (uint32_t c = 0; c < count; c++) {
+    bool hasFileData = false;
+    dragSession->IsDataFlavorSupported(kFileMime, &hasFileData);
+
     // First, check for the special format that holds custom types.
     bool supported;
     dragSession->IsDataFlavorSupported(kCustomTypesMime, &supported);
     if (supported) {
       FillInExternalCustomTypes(c, sysPrincipal);
     }
 
     for (uint32_t f = 0; f < ArrayLength(formats); f++) {
@@ -1349,17 +1382,17 @@ DataTransfer::CacheExternalDragFormats()
       // checks if any of the items support a particular flavor, even though
       // the GetData method does take an index. Here, we just assume that
       // every item being dragged has the same set of flavors.
       bool supported;
       dragSession->IsDataFlavorSupported(kFormats[f], &supported);
       // if the format is supported, add an item to the array with null as
       // the data. When retrieved, GetRealData will read the data.
       if (supported) {
-        CacheExternalData(kFormats[f], c, sysPrincipal);
+        CacheExternalData(kFormats[f], c, sysPrincipal, /* hidden = */ f && hasFileData);
       }
     }
   }
 }
 
 void
 DataTransfer::CacheExternalClipboardFormats()
 {
@@ -1375,16 +1408,21 @@ DataTransfer::CacheExternalClipboardForm
   if (!clipboard || mClipboardType < 0) {
     return;
   }
 
   nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
   nsCOMPtr<nsIPrincipal> sysPrincipal;
   ssm->GetSystemPrincipal(getter_AddRefs(sysPrincipal));
 
+  // Check if the clipboard has any files
+  bool hasFileData = false;
+  const char *fileMime[] = { kFileMime };
+  clipboard->HasDataMatchingFlavors(fileMime, 1, mClipboardType, &hasFileData);
+
   // there isn't a way to get a list of the formats that might be available on
   // all platforms, so just check for the types that can actually be imported.
   // Note that the loop below assumes that kCustomTypesMime will be first.
   const char* formats[] = { kCustomTypesMime, kFileMime, kHTMLMime, kRTFMime,
                             kURLMime, kURLDataMime, kUnicodeMime, kPNGImageMime,
                             kJPEGImageMime, kGIFImageMime };
 
   for (uint32_t f = 0; f < mozilla::ArrayLength(formats); ++f) {
@@ -1393,17 +1431,18 @@ DataTransfer::CacheExternalClipboardForm
     clipboard->HasDataMatchingFlavors(&(formats[f]), 1, mClipboardType,
                                       &supported);
     // if the format is supported, add an item to the array with null as
     // the data. When retrieved, GetRealData will read the data.
     if (supported) {
       if (f == 0) {
         FillInExternalCustomTypes(0, sysPrincipal);
       } else {
-        CacheExternalData(formats[f], 0, sysPrincipal);
+        // If we aren't the file data, and we have file data, we want to be hidden
+        CacheExternalData(formats[f], 0, sysPrincipal, /* hidden = */ f != 1 && hasFileData);
       }
     }
   }
 }
 
 void
 DataTransfer::FillAllExternalData()
 {
--- a/dom/events/DataTransfer.h
+++ b/dom/events/DataTransfer.h
@@ -254,18 +254,18 @@ public:
   // converts some formats used for compatibility in aInFormat into aOutFormat.
   // Text and text/unicode become text/plain, and URL becomes text/uri-list
   void GetRealFormat(const nsAString& aInFormat, nsAString& aOutFormat) const;
 
 protected:
 
   // caches text and uri-list data formats that exist in the drag service or
   // clipboard for retrieval later.
-  void CacheExternalData(const char* aFormat, uint32_t aIndex,
-                         nsIPrincipal* aPrincipal);
+  nsresult CacheExternalData(const char* aFormat, uint32_t aIndex,
+                             nsIPrincipal* aPrincipal, bool aHidden);
 
   // caches the formats that exist in the drag service that were added by an
   // external drag
   void CacheExternalDragFormats();
 
   // caches the formats that exist in the clipboard
   void CacheExternalClipboardFormats();
 
--- a/dom/events/DataTransferItem.cpp
+++ b/dom/events/DataTransferItem.cpp
@@ -26,32 +26,16 @@ struct FileMimeNameData
 
 FileMimeNameData kFileMimeNameMap[] = {
   { kFileMime, "GenericFileName" },
   { kJPEGImageMime, "GenericImageNameJPEG" },
   { kGIFImageMime, "GenericImageNameGIF" },
   { kPNGImageMime, "GenericImageNamePNG" },
 };
 
-already_AddRefed<mozilla::dom::File>
-FileFromISupports(nsISupports* aSupports)
-{
-  MOZ_ASSERT(aSupports);
-
-  nsCOMPtr<nsIDOMBlob> domBlob = do_QueryInterface(aSupports);
-  if (domBlob) {
-    // Get out the blob - this is OK, because nsIDOMBlob is a builtinclass
-    // and the only implementer is Blob.
-    mozilla::dom::Blob* blob = static_cast<mozilla::dom::Blob*>(domBlob.get());
-    return blob->ToFile();
-  }
-
-  return nullptr;
-}
-
 } // anonymous namespace
 
 namespace mozilla {
 namespace dom {
 
 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(DataTransferItem, mData,
                                       mPrincipal, mParent)
 NS_IMPL_CYCLE_COLLECTING_ADDREF(DataTransferItem)
@@ -193,32 +177,16 @@ DataTransferItem::FillInExternalData()
   }
 
   if (Kind() == KIND_FILE) {
     // Because this is an external piece of data, mType is one of kFileMime,
     // kPNGImageMime, kJPEGImageMime, or kGIFImageMime. We want to convert
     // whatever type happens to actually be stored into a dom::File.
 
     RefPtr<File> file = FileFromISupports(data);
-    if (!file) {
-      if (nsCOMPtr<nsIFile> ifile = do_QueryInterface(data)) {
-        file = File::CreateFromFile(GetParentObject(), ifile);
-      } else if (nsCOMPtr<nsIInputStream> stream = do_QueryInterface(data)) {
-        // This consumes the stream object
-        ErrorResult rv;
-        file = CreateFileFromInputStream(GetParentObject(), stream, rv);
-        if (NS_WARN_IF(rv.Failed())) {
-          rv.SuppressException();
-        }
-      } else if (nsCOMPtr<BlobImpl> blobImpl = do_QueryInterface(data)) {
-        MOZ_ASSERT(blobImpl->IsFile());
-        file = File::Create(GetParentObject(), blobImpl);
-      }
-    }
-
     MOZ_ASSERT(file, "Invalid format for Kind() == KIND_FILE");
 
     data = do_QueryObject(file);
   }
 
   RefPtr<nsVariantCC> variant = new nsVariantCC();
 
   nsCOMPtr<nsISupportsString> supportsstr = do_QueryInterface(data);
@@ -276,16 +244,47 @@ DataTransferItem::GetAsFile(ErrorResult&
   // against it.
   MOZ_ASSERT(SameCOMIdentity(supports, NS_ISUPPORTS_CAST(nsIDOMBlob*, file)),
              "Got back a new File object from FileFromISupports in GetAsFile!");
 
   return file.forget();
 }
 
 already_AddRefed<File>
+DataTransferItem::FileFromISupports(nsISupports* aSupports)
+{
+  MOZ_ASSERT(aSupports);
+
+  RefPtr<File> file;
+
+  nsCOMPtr<nsIDOMBlob> domBlob = do_QueryInterface(aSupports);
+  if (domBlob) {
+    // Get out the blob - this is OK, because nsIDOMBlob is a builtinclass
+    // and the only implementer is Blob.
+    Blob* blob = static_cast<Blob*>(domBlob.get());
+    file = blob->ToFile();
+  } else if (nsCOMPtr<nsIFile> ifile = do_QueryInterface(aSupports)) {
+    printf("Creating a File from a nsIFile!\n");
+    file = File::CreateFromFile(GetParentObject(), ifile);
+  } else if (nsCOMPtr<nsIInputStream> stream = do_QueryInterface(aSupports)) {
+    // This consumes the stream object
+    ErrorResult rv;
+    file = CreateFileFromInputStream(GetParentObject(), stream, rv);
+    if (NS_WARN_IF(rv.Failed())) {
+      rv.SuppressException();
+    }
+  } else if (nsCOMPtr<BlobImpl> blobImpl = do_QueryInterface(aSupports)) {
+    MOZ_ASSERT(blobImpl->IsFile());
+    file = File::Create(GetParentObject(), blobImpl);
+  }
+
+  return file.forget();
+}
+
+already_AddRefed<File>
 DataTransferItem::CreateFileFromInputStream(nsISupports* aParent,
                                             nsIInputStream* aStream,
                                             ErrorResult& aRv)
 {
   const char* key = nullptr;
   for (uint32_t i = 0; i < ArrayLength(kFileMimeNameMap); ++i) {
     if (mType.EqualsASCII(kFileMimeNameMap[i].mMimeName)) {
       key = kFileMimeNameMap[i].mFileName;
@@ -316,17 +315,17 @@ DataTransferItem::CreateFileFromInputStr
     return nullptr;
   }
 
   return File::CreateMemoryFile(aParent, data, available, fileName,
                                 mType, PR_Now());
 }
 
 void
-DataTransferItem::GetAsString(const RefPtr<FunctionStringCallback>& aCallback,
+DataTransferItem::GetAsString(FunctionStringCallback* aCallback,
                               ErrorResult& aRv)
 {
   if (!aCallback || mKind != KIND_STRING) {
     return;
   }
 
   nsIVariant* data = Data();
   if (NS_WARN_IF(!data)) {
@@ -335,17 +334,17 @@ DataTransferItem::GetAsString(const RefP
 
   nsAutoString stringData;
   data->GetAsAString(stringData);
 
   // Dispatch the callback to the main thread
   class GASRunnable final : public Runnable
   {
   public:
-    GASRunnable(const RefPtr<FunctionStringCallback>& aCallback,
+    GASRunnable(FunctionStringCallback* aCallback,
                 const nsAString& aStringData)
       : mCallback(aCallback), mStringData(aStringData)
     {}
 
     NS_IMETHOD Run() override
     {
       ErrorResult rv;
       mCallback->Call(mStringData, rv);
--- a/dom/events/DataTransferItem.h
+++ b/dom/events/DataTransferItem.h
@@ -30,24 +30,23 @@ public:
   // marked as "other" and can only be produced throug the Moz* APIs.
   enum eKind {
     KIND_FILE,
     KIND_STRING,
     KIND_OTHER,
   };
 
   DataTransferItem(DataTransferItemList* aParent, const nsAString& aType)
-    : mIndex(0), mKind(KIND_OTHER), mType(aType), mParent(aParent)
+    : mIndex(0), mChromeOnly(false), mKind(KIND_OTHER), mType(aType), mParent(aParent)
   {}
 
   already_AddRefed<DataTransferItem> Clone(DataTransferItemList* aParent) const;
 
   virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
-  void GetAsString(const RefPtr<FunctionStringCallback>& aCallback,
-                   ErrorResult& aRv);
+  void GetAsString(FunctionStringCallback* aCallback, ErrorResult& aRv);
   void GetKind(nsAString& aKind) const
   {
     switch (mKind) {
     case KIND_FILE:
       aKind = NS_LITERAL_STRING("file");
       return;
     case KIND_STRING:
       aKind = NS_LITERAL_STRING("string");
@@ -103,25 +102,36 @@ public:
     return mIndex;
   }
   void SetIndex(uint32_t aIndex)
   {
     mIndex = aIndex;
   }
   void FillInExternalData();
 
+  bool ChromeOnly() const
+  {
+    return mChromeOnly;
+  }
+  void SetChromeOnly(bool aChromeOnly)
+  {
+    mChromeOnly = aChromeOnly;
+  }
+
 private:
   ~DataTransferItem() {}
+  already_AddRefed<File> FileFromISupports(nsISupports* aParent);
   already_AddRefed<File> CreateFileFromInputStream(nsISupports* aParent,
                                                    nsIInputStream* aStream,
                                                    ErrorResult& aRv);
 
   // The index in the 2d mIndexedItems array
   uint32_t mIndex;
 
+  bool mChromeOnly;
   eKind mKind;
   nsString mType;
   nsCOMPtr<nsIVariant> mData;
   nsCOMPtr<nsIPrincipal> mPrincipal;
   RefPtr<DataTransferItemList> mParent;
 };
 
 } // namespace dom
--- a/dom/events/DataTransferItemList.cpp
+++ b/dom/events/DataTransferItemList.cpp
@@ -207,17 +207,19 @@ DataTransferItemList::Add(const nsAStrin
   nsAutoString format;
   mParent->GetRealFormat(aType, format);
 
   // We add the textual data to index 0. We set aInsertOnly to true, as we don't
   // want to update an existing entry if it is already present, as per the spec.
   RefPtr<DataTransferItem> item =
     SetDataWithPrincipal(format, data, 0,
                          nsContentUtils::SubjectPrincipal(),
-                         true, aRv);
+                         /* aInsertOnly = */ true,
+                         /* aHidden = */ false,
+                         aRv);
   if (NS_WARN_IF(aRv.Failed())) {
     return nullptr;
   }
   MOZ_ASSERT(item->Kind() != DataTransferItem::KIND_FILE);
 
   return item;
 }
 
@@ -238,17 +240,17 @@ DataTransferItemList::Add(File& aData, E
 
   // We need to add this as a new item, as multiple files can't exist in the
   // same item in the Moz DataTransfer layout. It will be appended at the end of
   // the internal specced layout.
   uint32_t index = mIndexedItems.Length();
   RefPtr<DataTransferItem> item =
     SetDataWithPrincipal(type, data, index,
                          nsContentUtils::SubjectPrincipal(),
-                         true, aRv);
+                         true, false, aRv);
   if (NS_WARN_IF(aRv.Failed())) {
     return nullptr;
   }
   MOZ_ASSERT(item->Kind() == DataTransferItem::KIND_FILE);
 
   return item;
 }
 
@@ -327,16 +329,17 @@ DataTransferItemList::MozItemByTypeAt(co
 }
 
 already_AddRefed<DataTransferItem>
 DataTransferItemList::SetDataWithPrincipal(const nsAString& aType,
                                            nsIVariant* aData,
                                            uint32_t aIndex,
                                            nsIPrincipal* aPrincipal,
                                            bool aInsertOnly,
+                                           bool aHidden,
                                            ErrorResult& aRv)
 {
   if (aIndex < mIndexedItems.Length()) {
     nsTArray<RefPtr<DataTransferItem>>& items = mIndexedItems[aIndex];
     uint32_t count = items.Length();
     for (uint32_t i = 0; i < count; i++) {
       RefPtr<DataTransferItem> item = items[i];
       nsString type;
@@ -386,48 +389,50 @@ DataTransferItemList::SetDataWithPrincip
     }
   } else {
     // Make sure that we aren't adding past the end of the mIndexedItems array.
     // XXX Should this be a MOZ_ASSERT instead?
     aIndex = mIndexedItems.Length();
   }
 
   // Add the new item
-  RefPtr<DataTransferItem> item = AppendNewItem(aIndex, aType, aData, aPrincipal);
+  RefPtr<DataTransferItem> item = AppendNewItem(aIndex, aType, aData, aPrincipal, aHidden);
 
   if (item->Kind() == DataTransferItem::KIND_FILE) {
     RegenerateFiles();
   }
 
   return item.forget();
 }
 
 DataTransferItem*
 DataTransferItemList::AppendNewItem(uint32_t aIndex,
                                     const nsAString& aType,
                                     nsIVariant* aData,
-                                    nsIPrincipal* aPrincipal)
+                                    nsIPrincipal* aPrincipal,
+                                    bool aHidden)
 {
   if (mIndexedItems.Length() <= aIndex) {
     MOZ_ASSERT(mIndexedItems.Length() == aIndex);
     mIndexedItems.AppendElement();
   }
   RefPtr<DataTransferItem> item = new DataTransferItem(this, aType);
   item->SetIndex(aIndex);
   item->SetPrincipal(aPrincipal);
   item->SetData(aData);
+  item->SetChromeOnly(aHidden);
 
   mIndexedItems[aIndex].AppendElement(item);
 
   // We only want to add the item to the main mItems list if the index we are
   // adding to is 0, or the item we are adding is a file. If we add an item
   // which is not a file to a non-zero index, invariants could be broken.
   // (namely the invariant that there are not 2 non-file entries in the items
   // array with the same type)
-  if (item->Kind() == DataTransferItem::KIND_FILE || aIndex == 0) {
+  if (!aHidden && (item->Kind() == DataTransferItem::KIND_FILE || aIndex == 0)) {
     mItems.AppendElement(item);
   }
 
   return item;
 }
 
 const nsTArray<RefPtr<DataTransferItem>>*
 DataTransferItemList::MozItemsAt(uint32_t aIndex) // -- INDEXED
--- a/dom/events/DataTransferItemList.h
+++ b/dom/events/DataTransferItemList.h
@@ -70,17 +70,17 @@ public:
   // Accessors for data from ParentObject
   bool IsReadOnly() const;
   int32_t ClipboardType() const;
   EventMessage GetEventMessage() const;
 
   already_AddRefed<DataTransferItem>
   SetDataWithPrincipal(const nsAString& aType, nsIVariant* aData,
                        uint32_t aIndex, nsIPrincipal* aPrincipal,
-                       bool aInsertOnly, ErrorResult& aRv);
+                       bool aInsertOnly, bool aHidden, ErrorResult& aRv);
 
   FileList* Files();
 
   // Moz-style helper methods for interacting with the stored data
   void MozRemoveByTypeAt(const nsAString& aType, uint32_t aIndex,
                          ErrorResult& aRv);
   DataTransferItem* MozItemByTypeAt(const nsAString& aType, uint32_t aIndex);
   const nsTArray<RefPtr<DataTransferItem>>* MozItemsAt(uint32_t aIndex);
@@ -92,17 +92,18 @@ public:
   // Delete every item in the DataTransferItemList, without checking for
   // permissions or read-only status (for internal use only).
   void ClearAllItems();
 
 private:
   void ClearDataHelper(DataTransferItem* aItem, uint32_t aIndexHint,
                        uint32_t aMozOffsetHint, ErrorResult& aRv);
   DataTransferItem* AppendNewItem(uint32_t aIndex, const nsAString& aType,
-                                  nsIVariant* aData, nsIPrincipal* aPrincipal);
+                                  nsIVariant* aData, nsIPrincipal* aPrincipal,
+                                  bool aHidden);
   void RegenerateFiles();
 
   ~DataTransferItemList() {}
 
   RefPtr<DataTransfer> mParent;
   bool mIsCrossDomainSubFrameDrop;
   bool mIsExternal;
   RefPtr<FileList> mFiles;