dom/events/DataTransfer.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     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/. */
     7 #include "mozilla/ArrayUtils.h"
     8 #include "mozilla/BasicEvents.h"
    10 #include "DataTransfer.h"
    12 #include "nsIDOMDocument.h"
    13 #include "nsIVariant.h"
    14 #include "nsISupportsPrimitives.h"
    15 #include "nsIScriptSecurityManager.h"
    16 #include "mozilla/dom/DOMStringList.h"
    17 #include "nsError.h"
    18 #include "nsIDragService.h"
    19 #include "nsIClipboard.h"
    20 #include "nsContentUtils.h"
    21 #include "nsIContent.h"
    22 #include "nsCRT.h"
    23 #include "nsIScriptObjectPrincipal.h"
    24 #include "nsIScriptContext.h"
    25 #include "nsIDocument.h"
    26 #include "nsIScriptGlobalObject.h"
    27 #include "mozilla/dom/DataTransferBinding.h"
    28 #include "mozilla/dom/Element.h"
    29 #include "mozilla/dom/BindingUtils.h"
    31 namespace mozilla {
    32 namespace dom {
    34 NS_IMPL_CYCLE_COLLECTION_CLASS(DataTransfer)
    36 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(DataTransfer)
    37   NS_IMPL_CYCLE_COLLECTION_UNLINK(mParent)
    38   if (tmp->mFiles) {
    39     tmp->mFiles->Disconnect();
    40     NS_IMPL_CYCLE_COLLECTION_UNLINK(mFiles)
    41   }
    42   NS_IMPL_CYCLE_COLLECTION_UNLINK(mDragTarget)
    43   NS_IMPL_CYCLE_COLLECTION_UNLINK(mDragImage)
    44   NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
    45 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
    46 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(DataTransfer)
    47   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParent)
    48   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFiles)
    49   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDragTarget)
    50   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDragImage)
    51   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
    52 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
    53 NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(DataTransfer)
    55 NS_IMPL_CYCLE_COLLECTING_ADDREF(DataTransfer)
    56 NS_IMPL_CYCLE_COLLECTING_RELEASE(DataTransfer)
    58 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DataTransfer)
    59   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
    60   NS_INTERFACE_MAP_ENTRY(mozilla::dom::DataTransfer)
    61   NS_INTERFACE_MAP_ENTRY(nsIDOMDataTransfer)
    62   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMDataTransfer)
    63 NS_INTERFACE_MAP_END
    65 // the size of the array
    66 const char DataTransfer::sEffects[8][9] = {
    67   "none", "copy", "move", "copyMove", "link", "copyLink", "linkMove", "all"
    68 };
    70 DataTransfer::DataTransfer(nsISupports* aParent, uint32_t aEventType,
    71                            bool aIsExternal, int32_t aClipboardType)
    72   : mParent(aParent),
    73     mEventType(aEventType),
    74     mDropEffect(nsIDragService::DRAGDROP_ACTION_NONE),
    75     mEffectAllowed(nsIDragService::DRAGDROP_ACTION_UNINITIALIZED),
    76     mCursorState(false),
    77     mReadOnly(true),
    78     mIsExternal(aIsExternal),
    79     mUserCancelled(false),
    80     mIsCrossDomainSubFrameDrop(false),
    81     mClipboardType(aClipboardType),
    82     mDragImageX(0),
    83     mDragImageY(0)
    84 {
    85   MOZ_ASSERT(mParent);
    86   SetIsDOMBinding();
    87   // For these events, we want to be able to add data to the data transfer, so
    88   // clear the readonly state. Otherwise, the data is already present. For
    89   // external usage, cache the data from the native clipboard or drag.
    90   if (aEventType == NS_CUT ||
    91       aEventType == NS_COPY ||
    92       aEventType == NS_DRAGDROP_START ||
    93       aEventType == NS_DRAGDROP_GESTURE) {
    94     mReadOnly = false;
    95   } else if (mIsExternal) {
    96     if (aEventType == NS_PASTE) {
    97       CacheExternalClipboardFormats();
    98     } else if (aEventType >= NS_DRAGDROP_EVENT_START && aEventType <= NS_DRAGDROP_LEAVE_SYNTH) {
    99       CacheExternalDragFormats();
   100     }
   101   }
   102 }
   104 DataTransfer::DataTransfer(nsISupports* aParent,
   105                            uint32_t aEventType,
   106                            const uint32_t aEffectAllowed,
   107                            bool aCursorState,
   108                            bool aIsExternal,
   109                            bool aUserCancelled,
   110                            bool aIsCrossDomainSubFrameDrop,
   111                            int32_t aClipboardType,
   112                            nsTArray<nsTArray<TransferItem> >& aItems,
   113                            Element* aDragImage,
   114                            uint32_t aDragImageX,
   115                            uint32_t aDragImageY)
   116   : mParent(aParent),
   117     mEventType(aEventType),
   118     mDropEffect(nsIDragService::DRAGDROP_ACTION_NONE),
   119     mEffectAllowed(aEffectAllowed),
   120     mCursorState(aCursorState),
   121     mReadOnly(true),
   122     mIsExternal(aIsExternal),
   123     mUserCancelled(aUserCancelled),
   124     mIsCrossDomainSubFrameDrop(aIsCrossDomainSubFrameDrop),
   125     mClipboardType(aClipboardType),
   126     mItems(aItems),
   127     mDragImage(aDragImage),
   128     mDragImageX(aDragImageX),
   129     mDragImageY(aDragImageY)
   130 {
   131   MOZ_ASSERT(mParent);
   132   SetIsDOMBinding();
   133   // The items are copied from aItems into mItems. There is no need to copy
   134   // the actual data in the items as the data transfer will be read only. The
   135   // draggesture and dragstart events are the only times when items are
   136   // modifiable, but those events should have been using the first constructor
   137   // above.
   138   NS_ASSERTION(aEventType != NS_DRAGDROP_GESTURE &&
   139                aEventType != NS_DRAGDROP_START,
   140                "invalid event type for DataTransfer constructor");
   141 }
   143 DataTransfer::~DataTransfer()
   144 {
   145   if (mFiles) {
   146     mFiles->Disconnect();
   147   }
   148 }
   150 // static
   151 already_AddRefed<DataTransfer>
   152 DataTransfer::Constructor(const GlobalObject& aGlobal,
   153                           const nsAString& aEventType, bool aIsExternal,
   154                           ErrorResult& aRv)
   155 {
   156   nsAutoCString onEventType("on");
   157   AppendUTF16toUTF8(aEventType, onEventType);
   158   nsCOMPtr<nsIAtom> eventTypeAtom = do_GetAtom(onEventType);
   159   if (!eventTypeAtom) {
   160     aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
   161     return nullptr;
   162   }
   164   uint32_t eventType = nsContentUtils::GetEventId(eventTypeAtom);
   165   nsRefPtr<DataTransfer> transfer = new DataTransfer(aGlobal.GetAsSupports(),
   166                                                      eventType, aIsExternal,
   167                                                      -1);
   168   return transfer.forget();
   169 }
   171 JSObject*
   172 DataTransfer::WrapObject(JSContext* aCx)
   173 {
   174   return DataTransferBinding::Wrap(aCx, this);
   175 }
   177 NS_IMETHODIMP
   178 DataTransfer::GetDropEffect(nsAString& aDropEffect)
   179 {
   180   nsString dropEffect;
   181   GetDropEffect(dropEffect);
   182   aDropEffect = dropEffect;
   183   return NS_OK;
   184 }
   186 NS_IMETHODIMP
   187 DataTransfer::SetDropEffect(const nsAString& aDropEffect)
   188 {
   189   // the drop effect can only be 'none', 'copy', 'move' or 'link'.
   190   for (uint32_t e = 0; e <= nsIDragService::DRAGDROP_ACTION_LINK; e++) {
   191     if (aDropEffect.EqualsASCII(sEffects[e])) {
   192       // don't allow copyMove
   193       if (e != (nsIDragService::DRAGDROP_ACTION_COPY |
   194                 nsIDragService::DRAGDROP_ACTION_MOVE))
   195         mDropEffect = e;
   196       break;
   197     }
   198   }
   200   return NS_OK;
   201 }
   203 NS_IMETHODIMP
   204 DataTransfer::GetEffectAllowed(nsAString& aEffectAllowed)
   205 {
   206   nsString effectAllowed;
   207   GetEffectAllowed(effectAllowed);
   208   aEffectAllowed = effectAllowed;
   209   return NS_OK;
   210 }
   212 NS_IMETHODIMP
   213 DataTransfer::SetEffectAllowed(const nsAString& aEffectAllowed)
   214 {
   215   if (aEffectAllowed.EqualsLiteral("uninitialized")) {
   216     mEffectAllowed = nsIDragService::DRAGDROP_ACTION_UNINITIALIZED;
   217     return NS_OK;
   218   }
   220   static_assert(nsIDragService::DRAGDROP_ACTION_NONE == 0,
   221                 "DRAGDROP_ACTION_NONE constant is wrong");
   222   static_assert(nsIDragService::DRAGDROP_ACTION_COPY == 1,
   223                 "DRAGDROP_ACTION_COPY constant is wrong");
   224   static_assert(nsIDragService::DRAGDROP_ACTION_MOVE == 2,
   225                 "DRAGDROP_ACTION_MOVE constant is wrong");
   226   static_assert(nsIDragService::DRAGDROP_ACTION_LINK == 4,
   227                 "DRAGDROP_ACTION_LINK constant is wrong");
   229   for (uint32_t e = 0; e < ArrayLength(sEffects); e++) {
   230     if (aEffectAllowed.EqualsASCII(sEffects[e])) {
   231       mEffectAllowed = e;
   232       break;
   233     }
   234   }
   236   return NS_OK;
   237 }
   239 NS_IMETHODIMP
   240 DataTransfer::GetDropEffectInt(uint32_t* aDropEffect)
   241 {
   242   *aDropEffect = mDropEffect;
   243   return  NS_OK;
   244 }
   246 NS_IMETHODIMP
   247 DataTransfer::SetDropEffectInt(uint32_t aDropEffect)
   248 {
   249   mDropEffect = aDropEffect;
   250   return  NS_OK;
   251 }
   253 NS_IMETHODIMP
   254 DataTransfer::GetEffectAllowedInt(uint32_t* aEffectAllowed)
   255 {
   256   *aEffectAllowed = mEffectAllowed;
   257   return  NS_OK;
   258 }
   260 NS_IMETHODIMP
   261 DataTransfer::SetEffectAllowedInt(uint32_t aEffectAllowed)
   262 {
   263   mEffectAllowed = aEffectAllowed;
   264   return  NS_OK;
   265 }
   267 NS_IMETHODIMP
   268 DataTransfer::GetMozUserCancelled(bool* aUserCancelled)
   269 {
   270   *aUserCancelled = MozUserCancelled();
   271   return NS_OK;
   272 }
   274 nsDOMFileList*
   275 DataTransfer::GetFiles(ErrorResult& aRv)
   276 {
   277   if (mEventType != NS_DRAGDROP_DROP && mEventType != NS_DRAGDROP_DRAGDROP &&
   278       mEventType != NS_PASTE) {
   279     return nullptr;
   280   }
   282   if (!mFiles) {
   283     mFiles = new nsDOMFileList(static_cast<nsIDOMDataTransfer*>(this));
   285     uint32_t count = mItems.Length();
   287     for (uint32_t i = 0; i < count; i++) {
   288       nsCOMPtr<nsIVariant> variant;
   289       aRv = MozGetDataAt(NS_ConvertUTF8toUTF16(kFileMime), i, getter_AddRefs(variant));
   290       if (aRv.Failed()) {
   291         return nullptr;
   292       }
   294       if (!variant)
   295         continue;
   297       nsCOMPtr<nsISupports> supports;
   298       nsresult rv = variant->GetAsISupports(getter_AddRefs(supports));
   300       if (NS_FAILED(rv))
   301         continue;
   303       nsCOMPtr<nsIFile> file = do_QueryInterface(supports);
   305       if (!file)
   306         continue;
   308       nsRefPtr<nsDOMFileFile> domFile = new nsDOMFileFile(file);
   310       if (!mFiles->Append(domFile)) {
   311         aRv.Throw(NS_ERROR_FAILURE);
   312         return nullptr;
   313       }
   314     }
   315   }
   317   return mFiles;
   318 }
   320 NS_IMETHODIMP
   321 DataTransfer::GetFiles(nsIDOMFileList** aFileList)
   322 {
   323   ErrorResult rv;
   324   NS_IF_ADDREF(*aFileList = GetFiles(rv));
   325   return rv.ErrorCode();
   326 }
   328 already_AddRefed<DOMStringList>
   329 DataTransfer::Types()
   330 {
   331   nsRefPtr<DOMStringList> types = new DOMStringList();
   332   if (mItems.Length()) {
   333     bool addFile = false;
   334     const nsTArray<TransferItem>& item = mItems[0];
   335     for (uint32_t i = 0; i < item.Length(); i++) {
   336       const nsString& format = item[i].mFormat;
   337       types->Add(format);
   338       if (!addFile) {
   339         addFile = format.EqualsASCII(kFileMime) ||
   340                   format.EqualsASCII("application/x-moz-file-promise");
   341       }
   342     }
   344     if (addFile) {
   345       types->Add(NS_LITERAL_STRING("Files"));
   346     }
   347   }
   349   return types.forget();
   350 }
   352 NS_IMETHODIMP
   353 DataTransfer::GetTypes(nsISupports** aTypes)
   354 {
   355   nsRefPtr<DOMStringList> types = Types();
   356   types.forget(aTypes);
   358   return NS_OK;
   359 }
   361 void
   362 DataTransfer::GetData(const nsAString& aFormat, nsAString& aData,
   363                       ErrorResult& aRv)
   364 {
   365   // return an empty string if data for the format was not found
   366   aData.Truncate();
   368   nsCOMPtr<nsIVariant> data;
   369   nsresult rv = MozGetDataAt(aFormat, 0, getter_AddRefs(data));
   370   if (NS_FAILED(rv)) {
   371     if (rv != NS_ERROR_DOM_INDEX_SIZE_ERR) {
   372       aRv.Throw(rv);
   373     }
   374     return;
   375   }
   377   if (data) {
   378     nsAutoString stringdata;
   379     data->GetAsAString(stringdata);
   381     // for the URL type, parse out the first URI from the list. The URIs are
   382     // separated by newlines
   383     nsAutoString lowercaseFormat;
   384     aRv = nsContentUtils::ASCIIToLower(aFormat, lowercaseFormat);
   385     if (aRv.Failed()) {
   386       return;
   387     }
   389     if (lowercaseFormat.EqualsLiteral("url")) {
   390       int32_t lastidx = 0, idx;
   391       int32_t length = stringdata.Length();
   392       while (lastidx < length) {
   393         idx = stringdata.FindChar('\n', lastidx);
   394         // lines beginning with # are comments
   395         if (stringdata[lastidx] == '#') {
   396           if (idx == -1)
   397             break;
   398         }
   399         else {
   400           if (idx == -1)
   401             aData.Assign(Substring(stringdata, lastidx));
   402           else
   403             aData.Assign(Substring(stringdata, lastidx, idx - lastidx));
   404           aData = nsContentUtils::TrimWhitespace<nsCRT::IsAsciiSpace>(aData, true);
   405           return;
   406         }
   407         lastidx = idx + 1;
   408       }
   409     }
   410     else {
   411       aData = stringdata;
   412     }
   413   }
   414 }
   416 NS_IMETHODIMP
   417 DataTransfer::GetData(const nsAString& aFormat, nsAString& aData)
   418 {
   419   ErrorResult rv;
   420   GetData(aFormat, aData, rv);
   421   return rv.ErrorCode();
   422 }
   424 void
   425 DataTransfer::SetData(const nsAString& aFormat, const nsAString& aData,
   426                       ErrorResult& aRv)
   427 {
   428   nsCOMPtr<nsIWritableVariant> variant = do_CreateInstance(NS_VARIANT_CONTRACTID);
   429   if (!variant) {
   430     aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
   431     return;
   432   }
   434   variant->SetAsAString(aData);
   436   aRv = MozSetDataAt(aFormat, variant, 0);
   437 }
   439 NS_IMETHODIMP
   440 DataTransfer::SetData(const nsAString& aFormat, const nsAString& aData)
   441 {
   442   ErrorResult rv;
   443   SetData(aFormat, aData, rv);
   444   return rv.ErrorCode();
   445 }
   447 void
   448 DataTransfer::ClearData(const Optional<nsAString>& aFormat, ErrorResult& aRv)
   449 {
   450   if (mReadOnly) {
   451     aRv.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
   452     return;
   453   }
   455   if (mItems.Length() == 0) {
   456     return;
   457   }
   459   if (aFormat.WasPassed()) {
   460     MozClearDataAtHelper(aFormat.Value(), 0, aRv);
   461   } else {
   462     MozClearDataAtHelper(EmptyString(), 0, aRv);
   463   }
   464 }
   466 NS_IMETHODIMP
   467 DataTransfer::ClearData(const nsAString& aFormat)
   468 {
   469   Optional<nsAString> format;
   470   format = &aFormat;
   471   ErrorResult rv;
   472   ClearData(format, rv);
   473   return rv.ErrorCode();
   474 }
   476 NS_IMETHODIMP
   477 DataTransfer::GetMozItemCount(uint32_t* aCount)
   478 {
   479   *aCount = MozItemCount();
   480   return NS_OK;
   481 }
   483 NS_IMETHODIMP
   484 DataTransfer::GetMozCursor(nsAString& aCursorState)
   485 {
   486   nsString cursor;
   487   GetMozCursor(cursor);
   488   aCursorState = cursor;
   489   return NS_OK;
   490 }
   492 NS_IMETHODIMP
   493 DataTransfer::SetMozCursor(const nsAString& aCursorState)
   494 {
   495   // Lock the cursor to an arrow during the drag.
   496   mCursorState = aCursorState.EqualsLiteral("default");
   498   return NS_OK;
   499 }
   501 already_AddRefed<nsINode>
   502 DataTransfer::GetMozSourceNode()
   503 {
   504   nsCOMPtr<nsIDragSession> dragSession = nsContentUtils::GetDragSession();
   505   if (!dragSession) {
   506     return nullptr;
   507   }
   509   nsCOMPtr<nsIDOMNode> sourceNode;
   510   dragSession->GetSourceNode(getter_AddRefs(sourceNode));
   511   nsCOMPtr<nsINode> node = do_QueryInterface(sourceNode);
   512   if (node && !nsContentUtils::CanCallerAccess(node)) {
   513     return nullptr;
   514   }
   516   return node.forget();
   517 }
   519 NS_IMETHODIMP
   520 DataTransfer::GetMozSourceNode(nsIDOMNode** aSourceNode)
   521 {
   522   nsCOMPtr<nsINode> sourceNode = GetMozSourceNode();
   523   if (!sourceNode) {
   524     *aSourceNode = nullptr;
   525     return NS_OK;
   526   }
   528   return CallQueryInterface(sourceNode, aSourceNode);
   529 }
   531 already_AddRefed<DOMStringList>
   532 DataTransfer::MozTypesAt(uint32_t aIndex, ErrorResult& aRv)
   533 {
   534   // Only the first item is valid for clipboard events
   535   if (aIndex > 0 &&
   536       (mEventType == NS_CUT || mEventType == NS_COPY || mEventType == NS_PASTE)) {
   537     aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
   538     return nullptr;
   539   }
   541   nsRefPtr<DOMStringList> types = new DOMStringList();
   542   if (aIndex < mItems.Length()) {
   543     // note that you can retrieve the types regardless of their principal
   544     nsTArray<TransferItem>& item = mItems[aIndex];
   545     for (uint32_t i = 0; i < item.Length(); i++)
   546       types->Add(item[i].mFormat);
   547   }
   549   return types.forget();
   550 }
   552 NS_IMETHODIMP
   553 DataTransfer::MozTypesAt(uint32_t aIndex, nsISupports** aTypes)
   554 {
   555   ErrorResult rv;
   556   nsRefPtr<DOMStringList> types = MozTypesAt(aIndex, rv);
   557   types.forget(aTypes);
   558   return rv.ErrorCode();
   559 }
   561 NS_IMETHODIMP
   562 DataTransfer::MozGetDataAt(const nsAString& aFormat, uint32_t aIndex,
   563                            nsIVariant** aData)
   564 {
   565   *aData = nullptr;
   567   if (aFormat.IsEmpty())
   568     return NS_OK;
   570   if (aIndex >= mItems.Length()) {
   571     return NS_ERROR_DOM_INDEX_SIZE_ERR;
   572   }
   574   // Only the first item is valid for clipboard events
   575   if (aIndex > 0 &&
   576       (mEventType == NS_CUT || mEventType == NS_COPY || mEventType == NS_PASTE)) {
   577     return NS_ERROR_DOM_INDEX_SIZE_ERR;
   578   }
   581   nsAutoString format;
   582   GetRealFormat(aFormat, format);
   584   nsTArray<TransferItem>& item = mItems[aIndex];
   586   // Check if the caller is allowed to access the drag data. Callers with
   587   // chrome privileges can always read the data. During the
   588   // drop event, allow retrieving the data except in the case where the
   589   // source of the drag is in a child frame of the caller. In that case,
   590   // we only allow access to data of the same principal. During other events,
   591   // only allow access to the data with the same principal.
   592   nsIPrincipal* principal = nullptr;
   593   if (mIsCrossDomainSubFrameDrop ||
   594       (mEventType != NS_DRAGDROP_DROP && mEventType != NS_DRAGDROP_DRAGDROP &&
   595        mEventType != NS_PASTE &&
   596        !nsContentUtils::IsCallerChrome())) {
   597     nsresult rv = NS_OK;
   598     principal = GetCurrentPrincipal(&rv);
   599     NS_ENSURE_SUCCESS(rv, rv);
   600   }
   602   uint32_t count = item.Length();
   603   for (uint32_t i = 0; i < count; i++) {
   604     TransferItem& formatitem = item[i];
   605     if (formatitem.mFormat.Equals(format)) {
   606       bool subsumes;
   607       if (formatitem.mPrincipal && principal &&
   608           (NS_FAILED(principal->Subsumes(formatitem.mPrincipal, &subsumes)) || !subsumes))
   609         return NS_ERROR_DOM_SECURITY_ERR;
   611       if (!formatitem.mData) {
   612         FillInExternalData(formatitem, aIndex);
   613       } else {
   614         nsCOMPtr<nsISupports> data;
   615         formatitem.mData->GetAsISupports(getter_AddRefs(data));
   616         // Make sure the code that is calling us is same-origin with the data.
   617         nsCOMPtr<EventTarget> pt = do_QueryInterface(data);
   618         if (pt) {
   619           nsresult rv = NS_OK;
   620           nsIScriptContext* c = pt->GetContextForEventHandlers(&rv);
   621           NS_ENSURE_TRUE(c && NS_SUCCEEDED(rv), NS_ERROR_DOM_SECURITY_ERR);
   622           nsIGlobalObject* go = c->GetGlobalObject();
   623           NS_ENSURE_TRUE(go, NS_ERROR_DOM_SECURITY_ERR);
   624           nsCOMPtr<nsIScriptObjectPrincipal> sp = do_QueryInterface(go);
   625           MOZ_ASSERT(sp, "This cannot fail on the main thread.");
   626           nsIPrincipal* dataPrincipal = sp->GetPrincipal();
   627           NS_ENSURE_TRUE(dataPrincipal, NS_ERROR_DOM_SECURITY_ERR);
   628           NS_ENSURE_TRUE(principal || (principal = GetCurrentPrincipal(&rv)),
   629                          NS_ERROR_DOM_SECURITY_ERR);
   630           NS_ENSURE_SUCCESS(rv, rv);
   631           bool equals = false;
   632           NS_ENSURE_TRUE(NS_SUCCEEDED(principal->Equals(dataPrincipal, &equals)) && equals,
   633                          NS_ERROR_DOM_SECURITY_ERR);
   634         }
   635       }
   636       *aData = formatitem.mData;
   637       NS_IF_ADDREF(*aData);
   638       return NS_OK;
   639     }
   640   }
   642   return NS_OK;
   643 }
   645 void
   646 DataTransfer::MozGetDataAt(JSContext* aCx, const nsAString& aFormat,
   647                            uint32_t aIndex,
   648                            JS::MutableHandle<JS::Value> aRetval,
   649                            mozilla::ErrorResult& aRv)
   650 {
   651   nsCOMPtr<nsIVariant> data;
   652   aRv = MozGetDataAt(aFormat, aIndex, getter_AddRefs(data));
   653   if (aRv.Failed()) {
   654     return;
   655   }
   657   if (!data) {
   658     return;
   659   }
   661   JS::Rooted<JS::Value> result(aCx);
   662   if (!VariantToJsval(aCx, data, aRetval)) {
   663     aRv = NS_ERROR_FAILURE;
   664     return;
   665   }
   666 }
   668 NS_IMETHODIMP
   669 DataTransfer::MozSetDataAt(const nsAString& aFormat, nsIVariant* aData,
   670                            uint32_t aIndex)
   671 {
   672   if (aFormat.IsEmpty()) {
   673     return NS_OK;
   674   }
   676   if (mReadOnly) {
   677     return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
   678   }
   680   // Specifying an index less than the current length will replace an existing
   681   // item. Specifying an index equal to the current length will add a new item.
   682   if (aIndex > mItems.Length()) {
   683     return NS_ERROR_DOM_INDEX_SIZE_ERR;
   684   }
   686   // Only the first item is valid for clipboard events
   687   if (aIndex > 0 &&
   688       (mEventType == NS_CUT || mEventType == NS_COPY || mEventType == NS_PASTE)) {
   689     return NS_ERROR_DOM_INDEX_SIZE_ERR;
   690   }
   692   // don't allow non-chrome to add file data
   693   // XXX perhaps this should also limit any non-string type as well
   694   if ((aFormat.EqualsLiteral("application/x-moz-file-promise") ||
   695        aFormat.EqualsLiteral("application/x-moz-file")) &&
   696        !nsContentUtils::IsCallerChrome()) {
   697     return NS_ERROR_DOM_SECURITY_ERR;
   698   }
   700   nsresult rv = NS_OK;
   701   nsIPrincipal* principal = GetCurrentPrincipal(&rv);
   702   NS_ENSURE_SUCCESS(rv, rv);
   704   return SetDataWithPrincipal(aFormat, aData, aIndex, principal);
   705 }
   707 void
   708 DataTransfer::MozSetDataAt(JSContext* aCx, const nsAString& aFormat,
   709                            JS::Handle<JS::Value> aData,
   710                            uint32_t aIndex, ErrorResult& aRv)
   711 {
   712   nsCOMPtr<nsIVariant> data;
   713   aRv = nsContentUtils::XPConnect()->JSValToVariant(aCx, aData,
   714                                                     getter_AddRefs(data));
   715   if (!aRv.Failed()) {
   716     aRv = MozSetDataAt(aFormat, data, aIndex);
   717   }
   718 }
   720 void
   721 DataTransfer::MozClearDataAt(const nsAString& aFormat, uint32_t aIndex,
   722                              ErrorResult& aRv)
   723 {
   724   if (mReadOnly) {
   725     aRv.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
   726     return;
   727   }
   729   if (aIndex >= mItems.Length()) {
   730     aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
   731     return;
   732   }
   734   // Only the first item is valid for clipboard events
   735   if (aIndex > 0 &&
   736       (mEventType == NS_CUT || mEventType == NS_COPY || mEventType == NS_PASTE)) {
   737     aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
   738     return;
   739   }
   741   MozClearDataAtHelper(aFormat, aIndex, aRv);
   742 }
   744 void
   745 DataTransfer::MozClearDataAtHelper(const nsAString& aFormat, uint32_t aIndex,
   746                                    ErrorResult& aRv)
   747 {
   748   MOZ_ASSERT(!mReadOnly);
   749   MOZ_ASSERT(aIndex < mItems.Length());
   750   MOZ_ASSERT(aIndex == 0 ||
   751              (mEventType != NS_CUT && mEventType != NS_COPY &&
   752               mEventType != NS_PASTE));
   754   nsAutoString format;
   755   GetRealFormat(aFormat, format);
   757   nsresult rv = NS_OK;
   758   nsIPrincipal* principal = GetCurrentPrincipal(&rv);
   759   if (NS_FAILED(rv)) {
   760     aRv = rv;
   761     return;
   762   }
   764   // if the format is empty, clear all formats
   765   bool clearall = format.IsEmpty();
   767   nsTArray<TransferItem>& item = mItems[aIndex];
   768   // count backwards so that the count and index don't have to be adjusted
   769   // after removing an element
   770   for (int32_t i = item.Length() - 1; i >= 0; i--) {
   771     TransferItem& formatitem = item[i];
   772     if (clearall || formatitem.mFormat.Equals(format)) {
   773       // don't allow removing data that has a stronger principal
   774       bool subsumes;
   775       if (formatitem.mPrincipal && principal &&
   776           (NS_FAILED(principal->Subsumes(formatitem.mPrincipal, &subsumes)) || !subsumes)) {
   777         aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
   778         return;
   779       }
   781       item.RemoveElementAt(i);
   783       // if a format was specified, break out. Otherwise, loop around until
   784       // all formats have been removed
   785       if (!clearall)
   786         break;
   787     }
   788   }
   790   // if the last format for an item is removed, remove the entire item
   791   if (!item.Length())
   792      mItems.RemoveElementAt(aIndex);
   793 }
   795 NS_IMETHODIMP
   796 DataTransfer::MozClearDataAt(const nsAString& aFormat, uint32_t aIndex)
   797 {
   798   ErrorResult rv;
   799   MozClearDataAt(aFormat, aIndex, rv);
   800   return rv.ErrorCode();
   801 }
   803 void
   804 DataTransfer::SetDragImage(Element& aImage, int32_t aX, int32_t aY,
   805                            ErrorResult& aRv)
   806 {
   807   if (mReadOnly) {
   808     aRv.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
   809     return;
   810   }
   812   mDragImage = &aImage;
   813   mDragImageX = aX;
   814   mDragImageY = aY;
   815 }
   817 NS_IMETHODIMP
   818 DataTransfer::SetDragImage(nsIDOMElement* aImage, int32_t aX, int32_t aY)
   819 {
   820   ErrorResult rv;
   821   nsCOMPtr<Element> image = do_QueryInterface(aImage);
   822   if (image) {
   823     SetDragImage(*image, aX, aY, rv);
   824   }
   825   return rv.ErrorCode();
   826 }
   828 void
   829 DataTransfer::AddElement(Element& aElement, ErrorResult& aRv)
   830 {
   831   if (mReadOnly) {
   832     aRv.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
   833     return;
   834   }
   836   mDragTarget = &aElement;
   837 }
   839 NS_IMETHODIMP
   840 DataTransfer::AddElement(nsIDOMElement* aElement)
   841 {
   842   NS_ENSURE_TRUE(aElement, NS_ERROR_NULL_POINTER);
   844   nsCOMPtr<Element> element = do_QueryInterface(aElement);
   845   NS_ENSURE_TRUE(element, NS_ERROR_INVALID_ARG);
   847   ErrorResult rv;
   848   AddElement(*element, rv);
   849   return rv.ErrorCode();
   850 }
   852 nsresult
   853 DataTransfer::Clone(nsISupports* aParent, uint32_t aEventType,
   854                     bool aUserCancelled, bool aIsCrossDomainSubFrameDrop,
   855                     DataTransfer** aNewDataTransfer)
   856 {
   857   DataTransfer* newDataTransfer =
   858     new DataTransfer(aParent, aEventType, mEffectAllowed, mCursorState,
   859                      mIsExternal, aUserCancelled, aIsCrossDomainSubFrameDrop,
   860                      mClipboardType, mItems, mDragImage, mDragImageX,
   861                      mDragImageY);
   863   *aNewDataTransfer = newDataTransfer;
   864   NS_ADDREF(*aNewDataTransfer);
   865   return NS_OK;
   866 }
   868 already_AddRefed<nsISupportsArray>
   869 DataTransfer::GetTransferables(nsIDOMNode* aDragTarget)
   870 {
   871   MOZ_ASSERT(aDragTarget);
   873   nsCOMPtr<nsISupportsArray> transArray =
   874     do_CreateInstance("@mozilla.org/supports-array;1");
   875   if (!transArray) {
   876     return nullptr;
   877   }
   880   nsCOMPtr<nsINode> dragNode = do_QueryInterface(aDragTarget);
   881   if (!dragNode) {
   882     return nullptr;
   883   }
   885   nsIDocument* doc = dragNode->GetCurrentDoc();
   886   if (!doc) {
   887     return nullptr;
   888   }
   890   nsILoadContext* loadContext = doc->GetLoadContext();
   892   uint32_t count = mItems.Length();
   893   for (uint32_t i = 0; i < count; i++) {
   894     nsCOMPtr<nsITransferable> transferable = GetTransferable(i, loadContext);
   895     if (transferable) {
   896       transArray->AppendElement(transferable);
   897     }
   898   }
   900   return transArray.forget();
   901 }
   903 already_AddRefed<nsITransferable>
   904 DataTransfer::GetTransferable(uint32_t aIndex, nsILoadContext* aLoadContext)
   905 {
   906   if (aIndex >= mItems.Length()) {
   907     return nullptr;
   908   }
   910   nsTArray<TransferItem>& item = mItems[aIndex];
   911   uint32_t count = item.Length();
   912   if (!count) {
   913     return nullptr;
   914   }
   916   nsCOMPtr<nsITransferable> transferable =
   917     do_CreateInstance("@mozilla.org/widget/transferable;1");
   918   if (!transferable) {
   919     return nullptr;
   920   }
   921   transferable->Init(aLoadContext);
   923   bool added = false;
   924   for (uint32_t f = 0; f < count; f++) {
   925     const TransferItem& formatitem = item[f];
   926     if (!formatitem.mData) { // skip empty items
   927       continue;
   928     }
   930     uint32_t length;
   931     nsCOMPtr<nsISupports> convertedData;
   932     if (!ConvertFromVariant(formatitem.mData, getter_AddRefs(convertedData), &length)) {
   933       continue;
   934     }
   936     // the underlying drag code uses text/unicode, so use that instead of text/plain
   937     const char* format;
   938     NS_ConvertUTF16toUTF8 utf8format(formatitem.mFormat);
   939     if (utf8format.EqualsLiteral("text/plain")) {
   940       format = kUnicodeMime;
   941     } else {
   942       format = utf8format.get();
   943     }
   945     // if a converter is set for a format, set the converter for the
   946     // transferable and don't add the item
   947     nsCOMPtr<nsIFormatConverter> converter = do_QueryInterface(convertedData);
   948     if (converter) {
   949       transferable->AddDataFlavor(format);
   950       transferable->SetConverter(converter);
   951       continue;
   952     }
   954     nsresult rv = transferable->SetTransferData(format, convertedData, length);
   955     if (NS_FAILED(rv)) {
   956       return nullptr;
   957     }
   959     added = true;
   960   }
   962   // only return the transferable if data was successfully added to it
   963   if (added) {
   964     return transferable.forget();
   965   }
   967   return nullptr;
   968 }
   970 bool
   971 DataTransfer::ConvertFromVariant(nsIVariant* aVariant,
   972                                  nsISupports** aSupports,
   973                                  uint32_t* aLength)
   974 {
   975   *aSupports = nullptr;
   976   *aLength = 0;
   978   uint16_t type;
   979   aVariant->GetDataType(&type);
   980   if (type == nsIDataType::VTYPE_INTERFACE ||
   981       type == nsIDataType::VTYPE_INTERFACE_IS) {
   982     nsCOMPtr<nsISupports> data;
   983     if (NS_FAILED(aVariant->GetAsISupports(getter_AddRefs(data))))
   984        return false;
   986     nsCOMPtr<nsIFlavorDataProvider> fdp = do_QueryInterface(data);
   987     if (fdp) {
   988       // for flavour data providers, use kFlavorHasDataProvider (which has the
   989       // value 0) as the length.
   990       NS_ADDREF(*aSupports = fdp);
   991       *aLength = nsITransferable::kFlavorHasDataProvider;
   992     }
   993     else {
   994       // wrap the item in an nsISupportsInterfacePointer
   995       nsCOMPtr<nsISupportsInterfacePointer> ptrSupports =
   996         do_CreateInstance(NS_SUPPORTS_INTERFACE_POINTER_CONTRACTID);
   997       if (!ptrSupports)
   998         return false;
  1000       ptrSupports->SetData(data);
  1001       NS_ADDREF(*aSupports = ptrSupports);
  1003       *aLength = sizeof(nsISupportsInterfacePointer *);
  1006     return true;
  1009   char16_t* chrs;
  1010   uint32_t len = 0;
  1011   nsresult rv = aVariant->GetAsWStringWithSize(&len, &chrs);
  1012   if (NS_FAILED(rv))
  1013     return false;
  1015   nsAutoString str;
  1016   str.Adopt(chrs, len);
  1018   nsCOMPtr<nsISupportsString>
  1019     strSupports(do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID));
  1020   if (!strSupports)
  1021     return false;
  1023   strSupports->SetData(str);
  1025   *aSupports = strSupports;
  1026   NS_ADDREF(*aSupports);
  1028   // each character is two bytes
  1029   *aLength = str.Length() << 1;
  1031   return true;
  1034 void
  1035 DataTransfer::ClearAll()
  1037   mItems.Clear();
  1040 nsresult
  1041 DataTransfer::SetDataWithPrincipal(const nsAString& aFormat,
  1042                                    nsIVariant* aData,
  1043                                    uint32_t aIndex,
  1044                                    nsIPrincipal* aPrincipal)
  1046   nsAutoString format;
  1047   GetRealFormat(aFormat, format);
  1049   // check if the item for the format already exists. In that case,
  1050   // just replace it.
  1051   TransferItem* formatitem;
  1052   if (aIndex < mItems.Length()) {
  1053     nsTArray<TransferItem>& item = mItems[aIndex];
  1054     uint32_t count = item.Length();
  1055     for (uint32_t i = 0; i < count; i++) {
  1056       TransferItem& itemformat = item[i];
  1057       if (itemformat.mFormat.Equals(format)) {
  1058         // don't allow replacing data that has a stronger principal
  1059         bool subsumes;
  1060         if (itemformat.mPrincipal && aPrincipal &&
  1061             (NS_FAILED(aPrincipal->Subsumes(itemformat.mPrincipal, &subsumes)) || !subsumes))
  1062           return NS_ERROR_DOM_SECURITY_ERR;
  1064         itemformat.mPrincipal = aPrincipal;
  1065         itemformat.mData = aData;
  1066         return NS_OK;
  1070     // add a new format
  1071     formatitem = item.AppendElement();
  1073   else {
  1074     NS_ASSERTION(aIndex == mItems.Length(), "Index out of range");
  1076     // add a new index
  1077     nsTArray<TransferItem>* item = mItems.AppendElement();
  1078     NS_ENSURE_TRUE(item, NS_ERROR_OUT_OF_MEMORY);
  1080     formatitem = item->AppendElement();
  1083   NS_ENSURE_TRUE(formatitem, NS_ERROR_OUT_OF_MEMORY);
  1085   formatitem->mFormat = format;
  1086   formatitem->mPrincipal = aPrincipal;
  1087   formatitem->mData = aData;
  1089   return NS_OK;
  1092 nsIPrincipal*
  1093 DataTransfer::GetCurrentPrincipal(nsresult* rv)
  1095   nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
  1097   nsCOMPtr<nsIPrincipal> currentPrincipal;
  1098   *rv = ssm->GetSubjectPrincipal(getter_AddRefs(currentPrincipal));
  1099   NS_ENSURE_SUCCESS(*rv, nullptr);
  1101   if (!currentPrincipal)
  1102     ssm->GetSystemPrincipal(getter_AddRefs(currentPrincipal));
  1104   return currentPrincipal.get();
  1107 void
  1108 DataTransfer::GetRealFormat(const nsAString& aInFormat, nsAString& aOutFormat)
  1110   // treat text/unicode as equivalent to text/plain
  1111   nsAutoString lowercaseFormat;
  1112   nsContentUtils::ASCIIToLower(aInFormat, lowercaseFormat);
  1113   if (lowercaseFormat.EqualsLiteral("text") || lowercaseFormat.EqualsLiteral("text/unicode"))
  1114     aOutFormat.AssignLiteral("text/plain");
  1115   else if (lowercaseFormat.EqualsLiteral("url"))
  1116     aOutFormat.AssignLiteral("text/uri-list");
  1117   else
  1118     aOutFormat.Assign(lowercaseFormat);
  1121 void
  1122 DataTransfer::CacheExternalData(const char* aFormat, uint32_t aIndex, nsIPrincipal* aPrincipal)
  1124   if (strcmp(aFormat, kUnicodeMime) == 0) {
  1125     SetDataWithPrincipal(NS_LITERAL_STRING("text/plain"), nullptr, aIndex, aPrincipal);
  1126   } else {
  1127     if (strcmp(aFormat, kURLDataMime) == 0) {
  1128       SetDataWithPrincipal(NS_LITERAL_STRING("text/uri-list"), nullptr, aIndex, aPrincipal);
  1130     SetDataWithPrincipal(NS_ConvertUTF8toUTF16(aFormat), nullptr, aIndex, aPrincipal);
  1134 void
  1135 DataTransfer::CacheExternalDragFormats()
  1137   // Called during the constructor to cache the formats available from an
  1138   // external drag. The data associated with each format will be set to null.
  1139   // This data will instead only be retrieved in FillInExternalDragData when
  1140   // asked for, as it may be time consuming for the source application to
  1141   // generate it.
  1143   nsCOMPtr<nsIDragSession> dragSession = nsContentUtils::GetDragSession();
  1144   if (!dragSession)
  1145     return;
  1147   // make sure that the system principal is used for external drags
  1148   nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
  1149   nsCOMPtr<nsIPrincipal> sysPrincipal;
  1150   ssm->GetSystemPrincipal(getter_AddRefs(sysPrincipal));
  1152   // there isn't a way to get a list of the formats that might be available on
  1153   // all platforms, so just check for the types that can actually be imported
  1154   // XXXndeakin there are some other formats but those are platform specific.
  1155   const char* formats[] = { kFileMime, kHTMLMime, kURLMime, kURLDataMime, kUnicodeMime };
  1157   uint32_t count;
  1158   dragSession->GetNumDropItems(&count);
  1159   for (uint32_t c = 0; c < count; c++) {
  1160     for (uint32_t f = 0; f < ArrayLength(formats); f++) {
  1161       // IsDataFlavorSupported doesn't take an index as an argument and just
  1162       // checks if any of the items support a particular flavor, even though
  1163       // the GetData method does take an index. Here, we just assume that
  1164       // every item being dragged has the same set of flavors.
  1165       bool supported;
  1166       dragSession->IsDataFlavorSupported(formats[f], &supported);
  1167       // if the format is supported, add an item to the array with null as
  1168       // the data. When retrieved, GetRealData will read the data.
  1169       if (supported) {
  1170         CacheExternalData(formats[f], c, sysPrincipal);
  1176 void
  1177 DataTransfer::CacheExternalClipboardFormats()
  1179   NS_ASSERTION(mEventType == NS_PASTE, "caching clipboard data for invalid event");
  1181   // Called during the constructor for paste events to cache the formats
  1182   // available on the clipboard. As with CacheExternalDragFormats, the
  1183   // data will only be retrieved when needed.
  1185   nsCOMPtr<nsIClipboard> clipboard = do_GetService("@mozilla.org/widget/clipboard;1");
  1186   if (!clipboard || mClipboardType < 0) {
  1187     return;
  1190   nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
  1191   nsCOMPtr<nsIPrincipal> sysPrincipal;
  1192   ssm->GetSystemPrincipal(getter_AddRefs(sysPrincipal));
  1194   // there isn't a way to get a list of the formats that might be available on
  1195   // all platforms, so just check for the types that can actually be imported
  1196   const char* formats[] = { kFileMime, kHTMLMime, kURLMime, kURLDataMime, kUnicodeMime };
  1198   for (uint32_t f = 0; f < mozilla::ArrayLength(formats); ++f) {
  1199     // check each format one at a time
  1200     bool supported;
  1201     clipboard->HasDataMatchingFlavors(&(formats[f]), 1, mClipboardType, &supported);
  1202     // if the format is supported, add an item to the array with null as
  1203     // the data. When retrieved, GetRealData will read the data.
  1204     if (supported) {
  1205       CacheExternalData(formats[f], 0, sysPrincipal);
  1210 void
  1211 DataTransfer::FillInExternalData(TransferItem& aItem, uint32_t aIndex)
  1213   NS_PRECONDITION(mIsExternal, "Not an external data transfer");
  1215   if (aItem.mData) {
  1216     return;
  1219   // only drag and paste events should be calling FillInExternalData
  1220   NS_ASSERTION(mEventType != NS_CUT && mEventType != NS_COPY,
  1221                "clipboard event with empty data");
  1223     NS_ConvertUTF16toUTF8 utf8format(aItem.mFormat);
  1224     const char* format = utf8format.get();
  1225     if (strcmp(format, "text/plain") == 0)
  1226       format = kUnicodeMime;
  1227     else if (strcmp(format, "text/uri-list") == 0)
  1228       format = kURLDataMime;
  1230     nsCOMPtr<nsITransferable> trans =
  1231       do_CreateInstance("@mozilla.org/widget/transferable;1");
  1232     if (!trans)
  1233       return;
  1235   trans->Init(nullptr);
  1236   trans->AddDataFlavor(format);
  1238   if (mEventType == NS_PASTE) {
  1239     MOZ_ASSERT(aIndex == 0, "index in clipboard must be 0");
  1241     nsCOMPtr<nsIClipboard> clipboard = do_GetService("@mozilla.org/widget/clipboard;1");
  1242     if (!clipboard || mClipboardType < 0) {
  1243       return;
  1246     clipboard->GetData(trans, mClipboardType);
  1247   } else {
  1248     nsCOMPtr<nsIDragSession> dragSession = nsContentUtils::GetDragSession();
  1249     if (!dragSession) {
  1250       return;
  1253 #ifdef DEBUG
  1254     // Since this is an external drag, the source document will always be null.
  1255     nsCOMPtr<nsIDOMDocument> domDoc;
  1256     dragSession->GetSourceDocument(getter_AddRefs(domDoc));
  1257     MOZ_ASSERT(!domDoc);
  1258 #endif
  1260     dragSession->GetData(trans, aIndex);
  1263     uint32_t length = 0;
  1264     nsCOMPtr<nsISupports> data;
  1265     trans->GetTransferData(format, getter_AddRefs(data), &length);
  1266     if (!data)
  1267       return;
  1269     nsCOMPtr<nsIWritableVariant> variant = do_CreateInstance(NS_VARIANT_CONTRACTID);
  1270     if (!variant)
  1271       return;
  1273     nsCOMPtr<nsISupportsString> supportsstr = do_QueryInterface(data);
  1274     if (supportsstr) {
  1275       nsAutoString str;
  1276       supportsstr->GetData(str);
  1277       variant->SetAsAString(str);
  1279     else {
  1280       variant->SetAsISupports(data);
  1283     aItem.mData = variant;
  1286 } // namespace dom
  1287 } // namespace mozilla

mercurial