tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

DataTransferItemList.cpp (21834B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "DataTransferItemList.h"
      8 
      9 #include "mozilla/BasePrincipal.h"
     10 #include "mozilla/ContentEvents.h"
     11 #include "mozilla/EventForwards.h"
     12 #include "mozilla/dom/DataTransferItemListBinding.h"
     13 #include "mozilla/storage/Variant.h"
     14 #include "nsContentUtils.h"
     15 #include "nsIGlobalObject.h"
     16 #include "nsIScriptContext.h"
     17 #include "nsIScriptGlobalObject.h"
     18 #include "nsIScriptObjectPrincipal.h"
     19 #include "nsQueryObject.h"
     20 #include "nsVariant.h"
     21 
     22 namespace mozilla::dom {
     23 
     24 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(DataTransferItemList, mDataTransfer,
     25                                      mItems, mIndexedItems, mFiles)
     26 NS_IMPL_CYCLE_COLLECTING_ADDREF(DataTransferItemList)
     27 NS_IMPL_CYCLE_COLLECTING_RELEASE(DataTransferItemList)
     28 
     29 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DataTransferItemList)
     30  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
     31  NS_INTERFACE_MAP_ENTRY(nsISupports)
     32 NS_INTERFACE_MAP_END
     33 
     34 JSObject* DataTransferItemList::WrapObject(JSContext* aCx,
     35                                           JS::Handle<JSObject*> aGivenProto) {
     36  return DataTransferItemList_Binding::Wrap(aCx, this, aGivenProto);
     37 }
     38 
     39 already_AddRefed<DataTransferItemList> DataTransferItemList::Clone(
     40    DataTransfer* aDataTransfer) const {
     41  RefPtr<DataTransferItemList> list = new DataTransferItemList(aDataTransfer);
     42 
     43  // We need to clone the mItems and mIndexedItems lists while keeping the same
     44  // correspondences between the mIndexedItems and mItems lists (namely, if an
     45  // item is in mIndexedItems, and mItems it must have the same new identity)
     46 
     47  // First, we copy over indexedItems, and clone every entry. Then, we go over
     48  // mItems. For every entry, we use its mIndex property to locate it in
     49  // mIndexedItems on the original DataTransferItemList, and then copy over the
     50  // reference from the same index pair on the new DataTransferItemList
     51 
     52  list->mIndexedItems.SetLength(mIndexedItems.Length());
     53  list->mItems.SetLength(mItems.Length());
     54 
     55  // Copy over mIndexedItems, cloning every entry
     56  for (uint32_t i = 0; i < mIndexedItems.Length(); i++) {
     57    const nsTArray<RefPtr<DataTransferItem>>& items = mIndexedItems[i];
     58    nsTArray<RefPtr<DataTransferItem>>& newItems = list->mIndexedItems[i];
     59    newItems.SetLength(items.Length());
     60    for (uint32_t j = 0; j < items.Length(); j++) {
     61      newItems[j] = items[j]->Clone(aDataTransfer);
     62    }
     63  }
     64 
     65  // Copy over mItems, getting the actual entries from mIndexedItems
     66  for (uint32_t i = 0; i < mItems.Length(); i++) {
     67    uint32_t index = mItems[i]->Index();
     68    MOZ_ASSERT(index < mIndexedItems.Length());
     69    uint32_t subIndex = mIndexedItems[index].IndexOf(mItems[i]);
     70 
     71    // Copy over the reference
     72    list->mItems[i] = list->mIndexedItems[index][subIndex];
     73  }
     74 
     75  return list.forget();
     76 }
     77 
     78 void DataTransferItemList::Remove(uint32_t aIndex,
     79                                  nsIPrincipal& aSubjectPrincipal,
     80                                  ErrorResult& aRv) {
     81  if (mDataTransfer->IsReadOnly()) {
     82    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     83    return;
     84  }
     85 
     86  if (aIndex >= Length()) {
     87    return;
     88  }
     89 
     90  ClearDataHelper(mItems[aIndex], aIndex, -1, aSubjectPrincipal, aRv);
     91 }
     92 
     93 DataTransferItem* DataTransferItemList::IndexedGetter(uint32_t aIndex,
     94                                                      bool& aFound) const {
     95  if (aIndex >= mItems.Length()) {
     96    aFound = false;
     97    return nullptr;
     98  }
     99 
    100  MOZ_ASSERT(mItems[aIndex]);
    101  aFound = true;
    102  return mItems[aIndex];
    103 }
    104 
    105 uint32_t DataTransferItemList::MozItemCount() const {
    106  uint32_t length = mIndexedItems.Length();
    107  // XXX: Compat hack - Index 0 always exists due to changes in internals, but
    108  // if it is empty, scripts using the moz* APIs should see it as not existing.
    109  if (length == 1 && mIndexedItems[0].IsEmpty()) {
    110    return 0;
    111  }
    112  return length;
    113 }
    114 
    115 void DataTransferItemList::Clear(nsIPrincipal& aSubjectPrincipal,
    116                                 ErrorResult& aRv) {
    117  if (NS_WARN_IF(mDataTransfer->IsReadOnly())) {
    118    return;
    119  }
    120 
    121  uint32_t count = Length();
    122  for (uint32_t i = 0; i < count; i++) {
    123    // We always remove the last item first, to avoid moving items around in
    124    // memory as much
    125    Remove(Length() - 1, aSubjectPrincipal, aRv);
    126    if (NS_WARN_IF(aRv.Failed())) {
    127      return;
    128    }
    129  }
    130 
    131  MOZ_ASSERT(Length() == 0);
    132 }
    133 
    134 DataTransferItem* DataTransferItemList::Add(const nsAString& aData,
    135                                            const nsAString& aType,
    136                                            nsIPrincipal& aSubjectPrincipal,
    137                                            ErrorResult& aRv) {
    138  if (NS_WARN_IF(mDataTransfer->IsReadOnly())) {
    139    return nullptr;
    140  }
    141 
    142  RefPtr<nsVariantCC> data(new nsVariantCC());
    143  data->SetAsAString(aData);
    144 
    145  nsAutoString format;
    146  mDataTransfer->GetRealFormat(aType, format);
    147 
    148  if (!DataTransfer::PrincipalMaySetData(format, data, &aSubjectPrincipal)) {
    149    aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
    150    return nullptr;
    151  }
    152 
    153  // We add the textual data to index 0. We set aInsertOnly to true, as we don't
    154  // want to update an existing entry if it is already present, as per the spec.
    155  RefPtr<DataTransferItem> item =
    156      SetDataWithPrincipal(format, data, 0, &aSubjectPrincipal,
    157                           /* aInsertOnly = */ true,
    158                           /* aHidden = */ false, aRv);
    159  if (NS_WARN_IF(aRv.Failed())) {
    160    return nullptr;
    161  }
    162  MOZ_ASSERT(item->Kind() != DataTransferItem::KIND_FILE);
    163 
    164  return item;
    165 }
    166 
    167 DataTransferItem* DataTransferItemList::Add(File& aData,
    168                                            nsIPrincipal& aSubjectPrincipal,
    169                                            ErrorResult& aRv) {
    170  if (mDataTransfer->IsReadOnly()) {
    171    return nullptr;
    172  }
    173 
    174  nsCOMPtr<nsISupports> supports = do_QueryObject(&aData);
    175  nsCOMPtr<nsIWritableVariant> data = new nsVariantCC();
    176  data->SetAsISupports(supports);
    177 
    178  nsAutoString type;
    179  aData.GetType(type);
    180 
    181  if (!DataTransfer::PrincipalMaySetData(type, data, &aSubjectPrincipal)) {
    182    aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
    183    return nullptr;
    184  }
    185 
    186  // We need to add this as a new item, as multiple files can't exist in the
    187  // same item in the Moz DataTransfer layout. It will be appended at the end of
    188  // the internal specced layout.
    189  uint32_t index = mIndexedItems.Length();
    190  RefPtr<DataTransferItem> item =
    191      SetDataWithPrincipal(type, data, index, &aSubjectPrincipal,
    192                           /* aInsertOnly = */ true,
    193                           /* aHidden = */ false, aRv);
    194  if (NS_WARN_IF(aRv.Failed())) {
    195    return nullptr;
    196  }
    197  MOZ_ASSERT(item->Kind() == DataTransferItem::KIND_FILE);
    198 
    199  return item;
    200 }
    201 
    202 already_AddRefed<FileList> DataTransferItemList::Files(
    203    nsIPrincipal* aPrincipal) {
    204  // The DataTransfer can hold data with varying principals, coming from
    205  // different windows. This means that permissions checks need to be made when
    206  // accessing data from the DataTransfer. With the accessor methods, this is
    207  // checked by DataTransferItem::Data(), however with files, we keep a cached
    208  // live copy of the files list for spec compliance.
    209  //
    210  // A DataTransfer is only exposed to one webpage, chrome code and expanded
    211  // principals related to WebExtensions content scripts or user scripts.
    212  // The chrome code should be able to see all files on the DataTransfer, while
    213  // the webpage and WebExtensions content scripts and user scripts should only
    214  // be able to see the files they can see.
    215  //
    216  // As chrome code doesn't need as strict spec compliance as web visible code,
    217  // we generate a new FileList object every time you access the Files list from
    218  // chrome code, but re-use the cached one when accessing from content code.
    219  //
    220  // For WebExtensions content scripts (expanded principals subsuming both
    221  // the attached web page principal and the extension principal) and
    222  // WebExtensions user scripts (expanded principals subsuming the attached
    223  // web page principal but not the extension principal) we also don't cache
    224  // the FileList as for chrome code (because the webpage principal and other
    225  // extension content scripts/user scripts principals would not be able to
    226  // access the cached FileList when accessed by a different expanded principal
    227  // first, see Bug 1707214).
    228  //
    229  // It is not legal to expose an identical DataTransfer object is to multiple
    230  // different principals without using the `Clone` method or similar to copy it
    231  // first. If that happens, this method will assert, and return nullptr in
    232  // release builds. If this functionality is required in the future, a more
    233  // advanced caching mechanism for the FileList objects will be required.
    234  RefPtr<FileList> files;
    235  if (aPrincipal->IsSystemPrincipal() ||
    236      // WebExtensions content scripts and user scripts.
    237      nsContentUtils::IsExpandedPrincipal(aPrincipal)) {
    238    files = new FileList(mDataTransfer);
    239    GenerateFiles(files, aPrincipal);
    240    return files.forget();
    241  }
    242 
    243  if (!mFiles) {
    244    mFiles = new FileList(mDataTransfer);
    245    mFilesPrincipal = aPrincipal;
    246    RegenerateFiles();
    247  }
    248 
    249  if (!aPrincipal->Subsumes(mFilesPrincipal)) {
    250    MOZ_ASSERT(false,
    251               "This DataTransfer should only be accessed by the system "
    252               "and a single principal");
    253    return nullptr;
    254  }
    255 
    256  files = mFiles;
    257  return files.forget();
    258 }
    259 
    260 void DataTransferItemList::MozRemoveByTypeAt(const nsAString& aType,
    261                                             uint32_t aIndex,
    262                                             nsIPrincipal& aSubjectPrincipal,
    263                                             ErrorResult& aRv) {
    264  if (NS_WARN_IF(mDataTransfer->IsReadOnly() ||
    265                 aIndex >= mIndexedItems.Length())) {
    266    return;
    267  }
    268 
    269  bool removeAll = aType.IsEmpty();
    270 
    271  nsTArray<RefPtr<DataTransferItem>>& items = mIndexedItems[aIndex];
    272  uint32_t count = items.Length();
    273  // We remove the last item of the list repeatedly - that way we don't
    274  // have to worry about modifying the loop iterator
    275  if (removeAll) {
    276    for (uint32_t i = 0; i < count; ++i) {
    277      uint32_t index = items.Length() - 1;
    278      MOZ_ASSERT(index == count - i - 1);
    279 
    280      ClearDataHelper(items[index], -1, index, aSubjectPrincipal, aRv);
    281      if (NS_WARN_IF(aRv.Failed())) {
    282        return;
    283      }
    284    }
    285 
    286    // items is no longer a valid reference, as removing the last element from
    287    // it via ClearDataHelper invalidated it. so we can't MOZ_ASSERT that the
    288    // length is now 0.
    289    return;
    290  }
    291 
    292  for (uint32_t i = 0; i < count; ++i) {
    293    // NOTE: As this is a moz-prefixed API, it works based on internal types.
    294    nsAutoString type;
    295    items[i]->GetInternalType(type);
    296    if (type == aType) {
    297      ClearDataHelper(items[i], -1, i, aSubjectPrincipal, aRv);
    298      return;
    299    }
    300  }
    301 }
    302 
    303 DataTransferItem* DataTransferItemList::MozItemByTypeAt(const nsAString& aType,
    304                                                        uint32_t aIndex) {
    305  if (NS_WARN_IF(aIndex >= mIndexedItems.Length())) {
    306    return nullptr;
    307  }
    308 
    309  uint32_t count = mIndexedItems[aIndex].Length();
    310  for (uint32_t i = 0; i < count; i++) {
    311    RefPtr<DataTransferItem> item = mIndexedItems[aIndex][i];
    312    // NOTE: As this is a moz-prefixed API it works on internal types
    313    nsString type;
    314    item->GetInternalType(type);
    315    if (type.Equals(aType)) {
    316      return item;
    317    }
    318  }
    319 
    320  return nullptr;
    321 }
    322 
    323 already_AddRefed<DataTransferItem> DataTransferItemList::SetDataWithPrincipal(
    324    const nsAString& aType, nsIVariant* aData, uint32_t aIndex,
    325    nsIPrincipal* aPrincipal, bool aInsertOnly, bool aHidden,
    326    ErrorResult& aRv) {
    327  if (aIndex < mIndexedItems.Length()) {
    328    nsTArray<RefPtr<DataTransferItem>>& items = mIndexedItems[aIndex];
    329    uint32_t count = items.Length();
    330    for (uint32_t i = 0; i < count; i++) {
    331      RefPtr<DataTransferItem> item = items[i];
    332      nsString type;
    333      item->GetInternalType(type);
    334      if (type.Equals(aType)) {
    335        if (NS_WARN_IF(aInsertOnly)) {
    336          aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
    337          return nullptr;
    338        }
    339 
    340        // don't allow replacing data that has a stronger principal
    341        bool subsumes;
    342        if (NS_WARN_IF(item->Principal() && aPrincipal &&
    343                       (NS_FAILED(aPrincipal->Subsumes(item->Principal(),
    344                                                       &subsumes)) ||
    345                        !subsumes))) {
    346          aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
    347          return nullptr;
    348        }
    349        item->SetPrincipal(aPrincipal);
    350 
    351        DataTransferItem::eKind oldKind = item->Kind();
    352        item->SetData(aData);
    353 
    354        mDataTransfer->TypesListMayHaveChanged();
    355 
    356        if (aIndex != 0) {
    357          // If the item changes from being a file to not a file or vice-versa,
    358          // its presence in the mItems array may need to change.
    359          if (item->Kind() == DataTransferItem::KIND_FILE &&
    360              oldKind != DataTransferItem::KIND_FILE) {
    361            // not file => file
    362            mItems.AppendElement(item);
    363          } else if (item->Kind() != DataTransferItem::KIND_FILE &&
    364                     oldKind == DataTransferItem::KIND_FILE) {
    365            // file => not file
    366            mItems.RemoveElement(item);
    367          }
    368        }
    369 
    370        // Regenerate the Files array if we have modified a file's status
    371        if (item->Kind() == DataTransferItem::KIND_FILE ||
    372            oldKind == DataTransferItem::KIND_FILE) {
    373          RegenerateFiles();
    374        }
    375 
    376        return item.forget();
    377      }
    378    }
    379  } else {
    380    // Make sure that we aren't adding past the end of the mIndexedItems array.
    381    // XXX Should this be a MOZ_ASSERT instead?
    382    aIndex = mIndexedItems.Length();
    383  }
    384 
    385  // Add the new item
    386  RefPtr<DataTransferItem> item =
    387      AppendNewItem(aIndex, aType, aData, aPrincipal, aHidden);
    388 
    389  if (item->Kind() == DataTransferItem::KIND_FILE) {
    390    RegenerateFiles();
    391  }
    392 
    393  return item.forget();
    394 }
    395 
    396 DataTransferItem* DataTransferItemList::AppendNewItem(uint32_t aIndex,
    397                                                      const nsAString& aType,
    398                                                      nsIVariant* aData,
    399                                                      nsIPrincipal* aPrincipal,
    400                                                      bool aHidden) {
    401  if (mIndexedItems.Length() <= aIndex) {
    402    MOZ_ASSERT(mIndexedItems.Length() == aIndex);
    403    mIndexedItems.AppendElement();
    404  }
    405  RefPtr<DataTransferItem> item = new DataTransferItem(mDataTransfer, aType);
    406  item->SetIndex(aIndex);
    407  item->SetPrincipal(aPrincipal);
    408  item->SetData(aData);
    409  item->SetChromeOnly(aHidden);
    410 
    411  mIndexedItems[aIndex].AppendElement(item);
    412 
    413  // We only want to add the item to the main mItems list if the index we are
    414  // adding to is 0, or the item we are adding is a file. If we add an item
    415  // which is not a file to a non-zero index, invariants could be broken.
    416  // (namely the invariant that there are not 2 non-file entries in the items
    417  // array with the same type).
    418  //
    419  // We also want to update our DataTransfer's type list any time we're adding a
    420  // KIND_FILE item, or an item at index 0.
    421  if (item->Kind() == DataTransferItem::KIND_FILE || aIndex == 0) {
    422    if (!aHidden) {
    423      mItems.AppendElement(item);
    424    }
    425    mDataTransfer->TypesListMayHaveChanged();
    426  }
    427 
    428  return item;
    429 }
    430 
    431 void DataTransferItemList::GetTypes(nsTArray<nsString>& aTypes,
    432                                    CallerType aCallerType) const {
    433  MOZ_ASSERT(aTypes.IsEmpty());
    434 
    435  if (mIndexedItems.IsEmpty()) {
    436    return;
    437  }
    438 
    439  bool foundFile = false;
    440  for (const RefPtr<DataTransferItem>& item : mIndexedItems[0]) {
    441    MOZ_ASSERT(item);
    442 
    443    // XXX Why don't we check the caller type with item's permission only
    444    //     for "Files"?
    445    if (!foundFile) {
    446      foundFile = item->Kind() == DataTransferItem::KIND_FILE;
    447    }
    448 
    449    if (item->ChromeOnly() && aCallerType != CallerType::System) {
    450      continue;
    451    }
    452 
    453    // NOTE: The reason why we get the internal type here is because we want
    454    // kFileMime to appear in the types list for backwards compatibility
    455    // reasons.
    456    nsAutoString type;
    457    item->GetInternalType(type);
    458    if (item->Kind() != DataTransferItem::KIND_FILE ||
    459        type.EqualsASCII(kFileMime)) {
    460      aTypes.AppendElement(type);
    461    }
    462  }
    463 
    464  // Additional files will be added at a non-zero index.
    465  if (!foundFile) {
    466    for (uint32_t i = 1; i < mIndexedItems.Length(); i++) {
    467      for (const RefPtr<DataTransferItem>& item : mIndexedItems[i]) {
    468        MOZ_ASSERT(item);
    469 
    470        foundFile = item->Kind() == DataTransferItem::KIND_FILE;
    471        if (foundFile) {
    472          break;
    473        }
    474      }
    475    }
    476  }
    477 
    478  if (foundFile) {
    479    aTypes.AppendElement(u"Files"_ns);
    480  }
    481 }
    482 
    483 bool DataTransferItemList::HasType(const nsAString& aType) const {
    484  MOZ_ASSERT(!aType.EqualsASCII("Files"), "Use HasFile instead");
    485  if (mIndexedItems.IsEmpty()) {
    486    return false;
    487  }
    488 
    489  for (const RefPtr<DataTransferItem>& item : mIndexedItems[0]) {
    490    if (item->IsInternalType(aType)) {
    491      return true;
    492    }
    493  }
    494  return false;
    495 }
    496 
    497 bool DataTransferItemList::HasFile() const {
    498  if (mIndexedItems.IsEmpty()) {
    499    return false;
    500  }
    501 
    502  for (const RefPtr<DataTransferItem>& item : mIndexedItems[0]) {
    503    if (item->Kind() == DataTransferItem::KIND_FILE) {
    504      return true;
    505    }
    506  }
    507  return false;
    508 }
    509 
    510 const nsTArray<RefPtr<DataTransferItem>>* DataTransferItemList::MozItemsAt(
    511    uint32_t aIndex)  // -- INDEXED
    512 {
    513  if (aIndex >= mIndexedItems.Length()) {
    514    return nullptr;
    515  }
    516 
    517  return &mIndexedItems[aIndex];
    518 }
    519 
    520 void DataTransferItemList::PopIndexZero() {
    521  MOZ_ASSERT(mIndexedItems.Length() > 1);
    522  MOZ_ASSERT(mIndexedItems[0].IsEmpty());
    523 
    524  mIndexedItems.RemoveElementAt(0);
    525 
    526  // Update the index of every element which has now been shifted
    527  for (uint32_t i = 0; i < mIndexedItems.Length(); i++) {
    528    nsTArray<RefPtr<DataTransferItem>>& items = mIndexedItems[i];
    529    for (uint32_t j = 0; j < items.Length(); j++) {
    530      items[j]->SetIndex(i);
    531    }
    532  }
    533 }
    534 
    535 void DataTransferItemList::ClearAllItems() {
    536  // We always need to have index 0, so don't delete that one
    537  mItems.Clear();
    538  mIndexedItems.Clear();
    539  mIndexedItems.SetLength(1);
    540  mDataTransfer->TypesListMayHaveChanged();
    541 
    542  // Re-generate files (into an empty list)
    543  RegenerateFiles();
    544 }
    545 
    546 void DataTransferItemList::ClearDataHelper(DataTransferItem* aItem,
    547                                           uint32_t aIndexHint,
    548                                           uint32_t aMozOffsetHint,
    549                                           nsIPrincipal& aSubjectPrincipal,
    550                                           ErrorResult& aRv) {
    551  MOZ_ASSERT(aItem);
    552  if (NS_WARN_IF(mDataTransfer->IsReadOnly())) {
    553    return;
    554  }
    555 
    556  if (aItem->Principal() && !aSubjectPrincipal.Subsumes(aItem->Principal())) {
    557    aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
    558    return;
    559  }
    560 
    561  // Check if the aIndexHint is actually the index, and then remove the item
    562  // from aItems
    563  bool found;
    564  if (IndexedGetter(aIndexHint, found) == aItem) {
    565    mItems.RemoveElementAt(aIndexHint);
    566  } else {
    567    mItems.RemoveElement(aItem);
    568  }
    569 
    570  // Check if the aMozIndexHint and aMozOffsetHint are actually the index and
    571  // offset, and then remove them from mIndexedItems
    572  MOZ_ASSERT(aItem->Index() < mIndexedItems.Length());
    573  nsTArray<RefPtr<DataTransferItem>>& items = mIndexedItems[aItem->Index()];
    574  if (aMozOffsetHint < items.Length() && aItem == items[aMozOffsetHint]) {
    575    items.RemoveElementAt(aMozOffsetHint);
    576  } else {
    577    items.RemoveElement(aItem);
    578  }
    579 
    580  mDataTransfer->TypesListMayHaveChanged();
    581 
    582  // Check if we should remove the index. We never remove index 0.
    583  if (items.Length() == 0 && aItem->Index() != 0) {
    584    mIndexedItems.RemoveElementAt(aItem->Index());
    585 
    586    // Update the index of every element which has now been shifted
    587    for (uint32_t i = aItem->Index(); i < mIndexedItems.Length(); i++) {
    588      nsTArray<RefPtr<DataTransferItem>>& items = mIndexedItems[i];
    589      for (uint32_t j = 0; j < items.Length(); j++) {
    590        items[j]->SetIndex(i);
    591      }
    592    }
    593  }
    594 
    595  // Give the removed item the invalid index
    596  aItem->SetIndex(-1);
    597 
    598  if (aItem->Kind() == DataTransferItem::KIND_FILE) {
    599    RegenerateFiles();
    600  }
    601 }
    602 
    603 void DataTransferItemList::RegenerateFiles() {
    604  // We don't want to regenerate the files list unless we already have a files
    605  // list. That way we can avoid the unnecessary work if the user never touches
    606  // the files list.
    607  if (mFiles) {
    608    // We clear the list rather than performing smaller updates, because it
    609    // simplifies the logic greatly on this code path, which should be very
    610    // infrequently used.
    611    mFiles->Clear();
    612 
    613    DataTransferItemList::GenerateFiles(mFiles, mFilesPrincipal);
    614  }
    615 }
    616 
    617 void DataTransferItemList::GenerateFiles(FileList* aFiles,
    618                                         nsIPrincipal* aFilesPrincipal) {
    619  MOZ_ASSERT(aFiles);
    620  MOZ_ASSERT(aFilesPrincipal);
    621 
    622  // For non-system principals, the Files list should be empty if the
    623  // DataTransfer is protected.
    624  if (!aFilesPrincipal->IsSystemPrincipal() && mDataTransfer->IsProtected()) {
    625    return;
    626  }
    627 
    628  uint32_t count = Length();
    629  for (uint32_t i = 0; i < count; i++) {
    630    bool found;
    631    RefPtr<DataTransferItem> item = IndexedGetter(i, found);
    632    MOZ_ASSERT(found);
    633 
    634    if (item->Kind() == DataTransferItem::KIND_FILE) {
    635      RefPtr<File> file = item->GetAsFile(*aFilesPrincipal, IgnoreErrors());
    636      if (NS_WARN_IF(!file)) {
    637        continue;
    638      }
    639      aFiles->Append(file);
    640    }
    641  }
    642 }
    643 
    644 }  // namespace mozilla::dom