DataTransfer.cpp 47 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561
  1. /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. #include "mozilla/ArrayUtils.h"
  6. #include "mozilla/BasicEvents.h"
  7. #include "DataTransfer.h"
  8. #include "nsIDOMDocument.h"
  9. #include "nsISupportsPrimitives.h"
  10. #include "nsIScriptSecurityManager.h"
  11. #include "mozilla/dom/DOMStringList.h"
  12. #include "nsArray.h"
  13. #include "nsError.h"
  14. #include "nsIDragService.h"
  15. #include "nsIClipboard.h"
  16. #include "nsContentUtils.h"
  17. #include "nsIContent.h"
  18. #include "nsIBinaryInputStream.h"
  19. #include "nsIBinaryOutputStream.h"
  20. #include "nsIStorageStream.h"
  21. #include "nsStringStream.h"
  22. #include "nsCRT.h"
  23. #include "nsIScriptObjectPrincipal.h"
  24. #include "nsIScriptContext.h"
  25. #include "nsIDocument.h"
  26. #include "nsIScriptGlobalObject.h"
  27. #include "nsVariant.h"
  28. #include "mozilla/dom/ContentChild.h"
  29. #include "mozilla/dom/DataTransferBinding.h"
  30. #include "mozilla/dom/DataTransferItemList.h"
  31. #include "mozilla/dom/Directory.h"
  32. #include "mozilla/dom/Element.h"
  33. #include "mozilla/dom/FileList.h"
  34. #include "mozilla/dom/BindingUtils.h"
  35. #include "mozilla/dom/OSFileSystem.h"
  36. #include "mozilla/dom/Promise.h"
  37. #include "nsNetUtil.h"
  38. #include "nsReadableUtils.h"
  39. namespace mozilla {
  40. namespace dom {
  41. NS_IMPL_CYCLE_COLLECTION_CLASS(DataTransfer)
  42. NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(DataTransfer)
  43. NS_IMPL_CYCLE_COLLECTION_UNLINK(mParent)
  44. NS_IMPL_CYCLE_COLLECTION_UNLINK(mItems)
  45. NS_IMPL_CYCLE_COLLECTION_UNLINK(mDragTarget)
  46. NS_IMPL_CYCLE_COLLECTION_UNLINK(mDragImage)
  47. NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
  48. NS_IMPL_CYCLE_COLLECTION_UNLINK_END
  49. NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(DataTransfer)
  50. NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParent)
  51. NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mItems)
  52. NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDragTarget)
  53. NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDragImage)
  54. NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
  55. NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(DataTransfer)
  56. NS_IMPL_CYCLE_COLLECTING_ADDREF(DataTransfer)
  57. 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
  64. // the size of the array
  65. const char DataTransfer::sEffects[8][9] = {
  66. "none", "copy", "move", "copyMove", "link", "copyLink", "linkMove", "all"
  67. };
  68. // Used for custom clipboard types.
  69. enum CustomClipboardTypeId {
  70. eCustomClipboardTypeId_None,
  71. eCustomClipboardTypeId_String
  72. };
  73. DataTransfer::DataTransfer(nsISupports* aParent, EventMessage aEventMessage,
  74. bool aIsExternal, int32_t aClipboardType)
  75. : mParent(aParent)
  76. , mDropEffect(nsIDragService::DRAGDROP_ACTION_NONE)
  77. , mEffectAllowed(nsIDragService::DRAGDROP_ACTION_UNINITIALIZED)
  78. , mEventMessage(aEventMessage)
  79. , mCursorState(false)
  80. , mReadOnly(true)
  81. , mIsExternal(aIsExternal)
  82. , mUserCancelled(false)
  83. , mIsCrossDomainSubFrameDrop(false)
  84. , mClipboardType(aClipboardType)
  85. , mDragImageX(0)
  86. , mDragImageY(0)
  87. {
  88. mItems = new DataTransferItemList(this, aIsExternal);
  89. // For these events, we want to be able to add data to the data transfer, so
  90. // clear the readonly state. Otherwise, the data is already present. For
  91. // external usage, cache the data from the native clipboard or drag.
  92. if (aEventMessage == eCut ||
  93. aEventMessage == eCopy ||
  94. aEventMessage == eDragStart) {
  95. mReadOnly = false;
  96. } else if (mIsExternal) {
  97. if (aEventMessage == ePaste) {
  98. CacheExternalClipboardFormats();
  99. } else if (aEventMessage >= eDragDropEventFirst &&
  100. aEventMessage <= eDragDropEventLast) {
  101. CacheExternalDragFormats();
  102. }
  103. }
  104. }
  105. DataTransfer::DataTransfer(nsISupports* aParent,
  106. EventMessage aEventMessage,
  107. const uint32_t aEffectAllowed,
  108. bool aCursorState,
  109. bool aIsExternal,
  110. bool aUserCancelled,
  111. bool aIsCrossDomainSubFrameDrop,
  112. int32_t aClipboardType,
  113. DataTransferItemList* aItems,
  114. Element* aDragImage,
  115. uint32_t aDragImageX,
  116. uint32_t aDragImageY)
  117. : mParent(aParent)
  118. , mDropEffect(nsIDragService::DRAGDROP_ACTION_NONE)
  119. , mEffectAllowed(aEffectAllowed)
  120. , mEventMessage(aEventMessage)
  121. , mCursorState(aCursorState)
  122. , mReadOnly(true)
  123. , mIsExternal(aIsExternal)
  124. , mUserCancelled(aUserCancelled)
  125. , mIsCrossDomainSubFrameDrop(aIsCrossDomainSubFrameDrop)
  126. , mClipboardType(aClipboardType)
  127. , mDragImage(aDragImage)
  128. , mDragImageX(aDragImageX)
  129. , mDragImageY(aDragImageY)
  130. {
  131. MOZ_ASSERT(mParent);
  132. MOZ_ASSERT(aItems);
  133. // We clone the items array after everything else, so that it has a valid
  134. // mParent value
  135. mItems = aItems->Clone(this);
  136. // The items are copied from aItems into mItems. There is no need to copy
  137. // the actual data in the items as the data transfer will be read only. The
  138. // dragstart event is the only time when items are
  139. // modifiable, but those events should have been using the first constructor
  140. // above.
  141. NS_ASSERTION(aEventMessage != eDragStart,
  142. "invalid event type for DataTransfer constructor");
  143. }
  144. DataTransfer::~DataTransfer()
  145. {}
  146. // static
  147. already_AddRefed<DataTransfer>
  148. DataTransfer::Constructor(const GlobalObject& aGlobal, ErrorResult& aRv)
  149. {
  150. RefPtr<DataTransfer> transfer = new DataTransfer(aGlobal.GetAsSupports(),
  151. eCopy, /* is external */ false, /* clipboard type */ -1);
  152. transfer->mEffectAllowed = nsIDragService::DRAGDROP_ACTION_NONE;
  153. return transfer.forget();
  154. }
  155. JSObject*
  156. DataTransfer::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
  157. {
  158. return DataTransferBinding::Wrap(aCx, this, aGivenProto);
  159. }
  160. NS_IMETHODIMP
  161. DataTransfer::GetDropEffect(nsAString& aDropEffect)
  162. {
  163. nsString dropEffect;
  164. GetDropEffect(dropEffect);
  165. aDropEffect = dropEffect;
  166. return NS_OK;
  167. }
  168. NS_IMETHODIMP
  169. DataTransfer::SetDropEffect(const nsAString& aDropEffect)
  170. {
  171. // the drop effect can only be 'none', 'copy', 'move' or 'link'.
  172. for (uint32_t e = 0; e <= nsIDragService::DRAGDROP_ACTION_LINK; e++) {
  173. if (aDropEffect.EqualsASCII(sEffects[e])) {
  174. // don't allow copyMove
  175. if (e != (nsIDragService::DRAGDROP_ACTION_COPY |
  176. nsIDragService::DRAGDROP_ACTION_MOVE)) {
  177. mDropEffect = e;
  178. }
  179. break;
  180. }
  181. }
  182. return NS_OK;
  183. }
  184. NS_IMETHODIMP
  185. DataTransfer::GetEffectAllowed(nsAString& aEffectAllowed)
  186. {
  187. nsString effectAllowed;
  188. GetEffectAllowed(effectAllowed);
  189. aEffectAllowed = effectAllowed;
  190. return NS_OK;
  191. }
  192. NS_IMETHODIMP
  193. DataTransfer::SetEffectAllowed(const nsAString& aEffectAllowed)
  194. {
  195. if (aEffectAllowed.EqualsLiteral("uninitialized")) {
  196. mEffectAllowed = nsIDragService::DRAGDROP_ACTION_UNINITIALIZED;
  197. return NS_OK;
  198. }
  199. static_assert(nsIDragService::DRAGDROP_ACTION_NONE == 0,
  200. "DRAGDROP_ACTION_NONE constant is wrong");
  201. static_assert(nsIDragService::DRAGDROP_ACTION_COPY == 1,
  202. "DRAGDROP_ACTION_COPY constant is wrong");
  203. static_assert(nsIDragService::DRAGDROP_ACTION_MOVE == 2,
  204. "DRAGDROP_ACTION_MOVE constant is wrong");
  205. static_assert(nsIDragService::DRAGDROP_ACTION_LINK == 4,
  206. "DRAGDROP_ACTION_LINK constant is wrong");
  207. for (uint32_t e = 0; e < ArrayLength(sEffects); e++) {
  208. if (aEffectAllowed.EqualsASCII(sEffects[e])) {
  209. mEffectAllowed = e;
  210. break;
  211. }
  212. }
  213. return NS_OK;
  214. }
  215. NS_IMETHODIMP
  216. DataTransfer::GetDropEffectInt(uint32_t* aDropEffect)
  217. {
  218. *aDropEffect = mDropEffect;
  219. return NS_OK;
  220. }
  221. NS_IMETHODIMP
  222. DataTransfer::SetDropEffectInt(uint32_t aDropEffect)
  223. {
  224. mDropEffect = aDropEffect;
  225. return NS_OK;
  226. }
  227. NS_IMETHODIMP
  228. DataTransfer::GetEffectAllowedInt(uint32_t* aEffectAllowed)
  229. {
  230. *aEffectAllowed = mEffectAllowed;
  231. return NS_OK;
  232. }
  233. NS_IMETHODIMP
  234. DataTransfer::SetEffectAllowedInt(uint32_t aEffectAllowed)
  235. {
  236. mEffectAllowed = aEffectAllowed;
  237. return NS_OK;
  238. }
  239. NS_IMETHODIMP
  240. DataTransfer::GetMozUserCancelled(bool* aUserCancelled)
  241. {
  242. *aUserCancelled = MozUserCancelled();
  243. return NS_OK;
  244. }
  245. already_AddRefed<FileList>
  246. DataTransfer::GetFiles(nsIPrincipal& aSubjectPrincipal,
  247. ErrorResult& aRv)
  248. {
  249. return mItems->Files(&aSubjectPrincipal);
  250. }
  251. NS_IMETHODIMP
  252. DataTransfer::GetFiles(nsIDOMFileList** aFileList)
  253. {
  254. if (!aFileList) {
  255. return NS_ERROR_FAILURE;
  256. }
  257. // The XPCOM interface is only avaliable to system code, and thus we can
  258. // assume the system principal. This is consistent with the previous behavour
  259. // of this function, which also assumed the system principal.
  260. //
  261. // This code is also called from C++ code, which expects it to have a System
  262. // Principal, and thus the SubjectPrincipal cannot be used.
  263. RefPtr<FileList> files = mItems->Files(nsContentUtils::GetSystemPrincipal());
  264. files.forget(aFileList);
  265. return NS_OK;
  266. }
  267. void
  268. DataTransfer::GetTypes(nsTArray<nsString>& aTypes,
  269. nsIPrincipal& aSubjectPrincipal) const
  270. {
  271. // When called from bindings, aTypes will be empty, but since we might have
  272. // Gecko-internal callers too, clear it to be safe.
  273. aTypes.Clear();
  274. const nsTArray<RefPtr<DataTransferItem>>* items = mItems->MozItemsAt(0);
  275. if (NS_WARN_IF(!items)) {
  276. return;
  277. }
  278. for (uint32_t i = 0; i < items->Length(); i++) {
  279. DataTransferItem* item = items->ElementAt(i);
  280. MOZ_ASSERT(item);
  281. if (item->ChromeOnly() && !nsContentUtils::IsSystemPrincipal(&aSubjectPrincipal)) {
  282. continue;
  283. }
  284. // NOTE: The reason why we get the internal type here is because we want
  285. // kFileMime to appear in the types list for backwards compatibility
  286. // reasons.
  287. nsAutoString type;
  288. item->GetInternalType(type);
  289. if (item->Kind() == DataTransferItem::KIND_STRING || type.EqualsASCII(kFileMime)) {
  290. // If the entry has kind KIND_STRING, we want to add it to the list.
  291. aTypes.AppendElement(type);
  292. }
  293. }
  294. for (uint32_t i = 0; i < mItems->Length(); ++i) {
  295. bool found = false;
  296. DataTransferItem* item = mItems->IndexedGetter(i, found);
  297. MOZ_ASSERT(found);
  298. if (item->Kind() != DataTransferItem::KIND_FILE) {
  299. continue;
  300. }
  301. aTypes.AppendElement(NS_LITERAL_STRING("Files"));
  302. break;
  303. }
  304. }
  305. void
  306. DataTransfer::GetData(const nsAString& aFormat, nsAString& aData,
  307. nsIPrincipal& aSubjectPrincipal,
  308. ErrorResult& aRv)
  309. {
  310. // return an empty string if data for the format was not found
  311. aData.Truncate();
  312. nsCOMPtr<nsIVariant> data;
  313. nsresult rv =
  314. GetDataAtInternal(aFormat, 0, &aSubjectPrincipal,
  315. getter_AddRefs(data));
  316. if (NS_FAILED(rv)) {
  317. if (rv != NS_ERROR_DOM_INDEX_SIZE_ERR) {
  318. aRv.Throw(rv);
  319. }
  320. return;
  321. }
  322. if (data) {
  323. nsAutoString stringdata;
  324. data->GetAsAString(stringdata);
  325. // for the URL type, parse out the first URI from the list. The URIs are
  326. // separated by newlines
  327. nsAutoString lowercaseFormat;
  328. nsContentUtils::ASCIIToLower(aFormat, lowercaseFormat);
  329. if (lowercaseFormat.EqualsLiteral("url")) {
  330. int32_t lastidx = 0, idx;
  331. int32_t length = stringdata.Length();
  332. while (lastidx < length) {
  333. idx = stringdata.FindChar('\n', lastidx);
  334. // lines beginning with # are comments
  335. if (stringdata[lastidx] == '#') {
  336. if (idx == -1) {
  337. break;
  338. }
  339. }
  340. else {
  341. if (idx == -1) {
  342. aData.Assign(Substring(stringdata, lastidx));
  343. } else {
  344. aData.Assign(Substring(stringdata, lastidx, idx - lastidx));
  345. }
  346. aData = nsContentUtils::TrimWhitespace<nsCRT::IsAsciiSpace>(aData,
  347. true);
  348. return;
  349. }
  350. lastidx = idx + 1;
  351. }
  352. }
  353. else {
  354. aData = stringdata;
  355. }
  356. }
  357. }
  358. void
  359. DataTransfer::SetData(const nsAString& aFormat, const nsAString& aData,
  360. nsIPrincipal& aSubjectPrincipal,
  361. ErrorResult& aRv)
  362. {
  363. RefPtr<nsVariantCC> variant = new nsVariantCC();
  364. variant->SetAsAString(aData);
  365. aRv = SetDataAtInternal(aFormat, variant, 0, &aSubjectPrincipal);
  366. }
  367. void
  368. DataTransfer::ClearData(const Optional<nsAString>& aFormat,
  369. nsIPrincipal& aSubjectPrincipal,
  370. ErrorResult& aRv)
  371. {
  372. if (mReadOnly) {
  373. aRv.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
  374. return;
  375. }
  376. if (MozItemCount() == 0) {
  377. return;
  378. }
  379. if (aFormat.WasPassed()) {
  380. MozClearDataAtHelper(aFormat.Value(), 0, aSubjectPrincipal, aRv);
  381. } else {
  382. MozClearDataAtHelper(EmptyString(), 0, aSubjectPrincipal, aRv);
  383. }
  384. }
  385. NS_IMETHODIMP
  386. DataTransfer::GetMozItemCount(uint32_t* aCount)
  387. {
  388. *aCount = MozItemCount();
  389. return NS_OK;
  390. }
  391. NS_IMETHODIMP
  392. DataTransfer::GetMozCursor(nsAString& aCursorState)
  393. {
  394. nsString cursor;
  395. GetMozCursor(cursor);
  396. aCursorState = cursor;
  397. return NS_OK;
  398. }
  399. NS_IMETHODIMP
  400. DataTransfer::SetMozCursor(const nsAString& aCursorState)
  401. {
  402. // Lock the cursor to an arrow during the drag.
  403. mCursorState = aCursorState.EqualsLiteral("default");
  404. return NS_OK;
  405. }
  406. already_AddRefed<nsINode>
  407. DataTransfer::GetMozSourceNode()
  408. {
  409. nsCOMPtr<nsIDragSession> dragSession = nsContentUtils::GetDragSession();
  410. if (!dragSession) {
  411. return nullptr;
  412. }
  413. nsCOMPtr<nsIDOMNode> sourceNode;
  414. dragSession->GetSourceNode(getter_AddRefs(sourceNode));
  415. nsCOMPtr<nsINode> node = do_QueryInterface(sourceNode);
  416. if (node && !nsContentUtils::LegacyIsCallerNativeCode()
  417. && !nsContentUtils::CanCallerAccess(node)) {
  418. return nullptr;
  419. }
  420. return node.forget();
  421. }
  422. NS_IMETHODIMP
  423. DataTransfer::GetMozSourceNode(nsIDOMNode** aSourceNode)
  424. {
  425. nsCOMPtr<nsINode> sourceNode = GetMozSourceNode();
  426. if (!sourceNode) {
  427. *aSourceNode = nullptr;
  428. return NS_OK;
  429. }
  430. return CallQueryInterface(sourceNode, aSourceNode);
  431. }
  432. already_AddRefed<DOMStringList>
  433. DataTransfer::MozTypesAt(uint32_t aIndex, ErrorResult& aRv) const
  434. {
  435. // Only the first item is valid for clipboard events
  436. if (aIndex > 0 &&
  437. (mEventMessage == eCut || mEventMessage == eCopy ||
  438. mEventMessage == ePaste)) {
  439. aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
  440. return nullptr;
  441. }
  442. RefPtr<DOMStringList> types = new DOMStringList();
  443. if (aIndex < MozItemCount()) {
  444. // note that you can retrieve the types regardless of their principal
  445. const nsTArray<RefPtr<DataTransferItem>>& items = *mItems->MozItemsAt(aIndex);
  446. bool addFile = false;
  447. for (uint32_t i = 0; i < items.Length(); i++) {
  448. if (items[i]->ChromeOnly() && !nsContentUtils::LegacyIsCallerChromeOrNativeCode()) {
  449. continue;
  450. }
  451. // NOTE: The reason why we get the internal type here is because we want
  452. // kFileMime to appear in the types list for backwards compatibility
  453. // reasons.
  454. nsAutoString type;
  455. items[i]->GetInternalType(type);
  456. if (NS_WARN_IF(!types->Add(type))) {
  457. aRv.Throw(NS_ERROR_FAILURE);
  458. return nullptr;
  459. }
  460. if (items[i]->Kind() == DataTransferItem::KIND_FILE) {
  461. addFile = true;
  462. }
  463. }
  464. if (addFile) {
  465. types->Add(NS_LITERAL_STRING("Files"));
  466. }
  467. }
  468. return types.forget();
  469. }
  470. NS_IMETHODIMP
  471. DataTransfer::MozTypesAt(uint32_t aIndex, nsISupports** aTypes)
  472. {
  473. ErrorResult rv;
  474. RefPtr<DOMStringList> types = MozTypesAt(aIndex, rv);
  475. types.forget(aTypes);
  476. return rv.StealNSResult();
  477. }
  478. nsresult
  479. DataTransfer::GetDataAtNoSecurityCheck(const nsAString& aFormat,
  480. uint32_t aIndex,
  481. nsIVariant** aData)
  482. {
  483. return GetDataAtInternal(aFormat, aIndex,
  484. nsContentUtils::GetSystemPrincipal(), aData);
  485. }
  486. nsresult
  487. DataTransfer::GetDataAtInternal(const nsAString& aFormat, uint32_t aIndex,
  488. nsIPrincipal* aSubjectPrincipal,
  489. nsIVariant** aData)
  490. {
  491. *aData = nullptr;
  492. if (aFormat.IsEmpty()) {
  493. return NS_OK;
  494. }
  495. if (aIndex >= MozItemCount()) {
  496. return NS_ERROR_DOM_INDEX_SIZE_ERR;
  497. }
  498. // Only the first item is valid for clipboard events
  499. if (aIndex > 0 &&
  500. (mEventMessage == eCut || mEventMessage == eCopy ||
  501. mEventMessage == ePaste)) {
  502. return NS_ERROR_DOM_INDEX_SIZE_ERR;
  503. }
  504. nsAutoString format;
  505. GetRealFormat(aFormat, format);
  506. MOZ_ASSERT(aSubjectPrincipal);
  507. RefPtr<DataTransferItem> item = mItems->MozItemByTypeAt(format, aIndex);
  508. if (!item) {
  509. // The index exists but there's no data for the specified format, in this
  510. // case we just return undefined
  511. return NS_OK;
  512. }
  513. // If we have chrome only content, and we aren't chrome, don't allow access
  514. if (!nsContentUtils::IsSystemPrincipal(aSubjectPrincipal) && item->ChromeOnly()) {
  515. return NS_OK;
  516. }
  517. // DataTransferItem::Data() handles the principal checks
  518. ErrorResult result;
  519. nsCOMPtr<nsIVariant> data = item->Data(aSubjectPrincipal, result);
  520. if (NS_WARN_IF(!data || result.Failed())) {
  521. return result.StealNSResult();
  522. }
  523. data.forget(aData);
  524. return NS_OK;
  525. }
  526. void
  527. DataTransfer::MozGetDataAt(JSContext* aCx, const nsAString& aFormat,
  528. uint32_t aIndex,
  529. JS::MutableHandle<JS::Value> aRetval,
  530. nsIPrincipal& aSubjectPrincipal,
  531. mozilla::ErrorResult& aRv)
  532. {
  533. nsCOMPtr<nsIVariant> data;
  534. aRv = GetDataAtInternal(aFormat, aIndex, &aSubjectPrincipal,
  535. getter_AddRefs(data));
  536. if (aRv.Failed()) {
  537. return;
  538. }
  539. if (!data) {
  540. aRetval.setNull();
  541. return;
  542. }
  543. JS::Rooted<JS::Value> result(aCx);
  544. if (!VariantToJsval(aCx, data, aRetval)) {
  545. aRv = NS_ERROR_FAILURE;
  546. return;
  547. }
  548. }
  549. /* static */ bool
  550. DataTransfer::PrincipalMaySetData(const nsAString& aType,
  551. nsIVariant* aData,
  552. nsIPrincipal* aPrincipal)
  553. {
  554. if (!nsContentUtils::IsSystemPrincipal(aPrincipal)) {
  555. DataTransferItem::eKind kind = DataTransferItem::KindFromData(aData);
  556. if (kind == DataTransferItem::KIND_OTHER) {
  557. NS_WARNING("Disallowing adding non string/file types to DataTransfer");
  558. return false;
  559. }
  560. if (aType.EqualsASCII(kFileMime) ||
  561. aType.EqualsASCII(kFilePromiseMime)) {
  562. NS_WARNING("Disallowing adding x-moz-file or x-moz-file-promize types to DataTransfer");
  563. return false;
  564. }
  565. // Disallow content from creating x-moz-place flavors, so that it cannot
  566. // create fake Places smart queries exposing user data.
  567. if (StringBeginsWith(aType, NS_LITERAL_STRING("text/x-moz-place"))) {
  568. NS_WARNING("Disallowing adding moz-place types to DataTransfer");
  569. return false;
  570. }
  571. }
  572. return true;
  573. }
  574. void
  575. DataTransfer::TypesListMayHaveChanged()
  576. {
  577. DataTransferBinding::ClearCachedTypesValue(this);
  578. }
  579. nsresult
  580. DataTransfer::SetDataAtInternal(const nsAString& aFormat, nsIVariant* aData,
  581. uint32_t aIndex,
  582. nsIPrincipal* aSubjectPrincipal)
  583. {
  584. if (aFormat.IsEmpty()) {
  585. return NS_OK;
  586. }
  587. if (mReadOnly) {
  588. return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
  589. }
  590. // Specifying an index less than the current length will replace an existing
  591. // item. Specifying an index equal to the current length will add a new item.
  592. if (aIndex > MozItemCount()) {
  593. return NS_ERROR_DOM_INDEX_SIZE_ERR;
  594. }
  595. // Only the first item is valid for clipboard events
  596. if (aIndex > 0 &&
  597. (mEventMessage == eCut || mEventMessage == eCopy ||
  598. mEventMessage == ePaste)) {
  599. return NS_ERROR_DOM_INDEX_SIZE_ERR;
  600. }
  601. // Don't allow the custom type to be assigned.
  602. if (aFormat.EqualsLiteral(kCustomTypesMime)) {
  603. return NS_ERROR_TYPE_ERR;
  604. }
  605. if (!PrincipalMaySetData(aFormat, aData, aSubjectPrincipal)) {
  606. return NS_ERROR_DOM_SECURITY_ERR;
  607. }
  608. return SetDataWithPrincipal(aFormat, aData, aIndex, aSubjectPrincipal);
  609. }
  610. void
  611. DataTransfer::MozSetDataAt(JSContext* aCx, const nsAString& aFormat,
  612. JS::Handle<JS::Value> aData, uint32_t aIndex,
  613. nsIPrincipal& aSubjectPrincipal,
  614. ErrorResult& aRv)
  615. {
  616. nsCOMPtr<nsIVariant> data;
  617. aRv = nsContentUtils::XPConnect()->JSValToVariant(aCx, aData,
  618. getter_AddRefs(data));
  619. if (!aRv.Failed()) {
  620. aRv = SetDataAtInternal(aFormat, data, aIndex, &aSubjectPrincipal);
  621. }
  622. }
  623. void
  624. DataTransfer::MozClearDataAt(const nsAString& aFormat, uint32_t aIndex,
  625. nsIPrincipal& aSubjectPrincipal,
  626. ErrorResult& aRv)
  627. {
  628. if (mReadOnly) {
  629. aRv.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
  630. return;
  631. }
  632. if (aIndex >= MozItemCount()) {
  633. aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
  634. return;
  635. }
  636. // Only the first item is valid for clipboard events
  637. if (aIndex > 0 &&
  638. (mEventMessage == eCut || mEventMessage == eCopy ||
  639. mEventMessage == ePaste)) {
  640. aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
  641. return;
  642. }
  643. MozClearDataAtHelper(aFormat, aIndex, aSubjectPrincipal, aRv);
  644. // If we just cleared the 0-th index, and there are still more than 1 indexes
  645. // remaining, MozClearDataAt should cause the 1st index to become the 0th
  646. // index. This should _only_ happen when the MozClearDataAt function is
  647. // explicitly called by script, as this behavior is inconsistent with spec.
  648. // (however, so is the MozClearDataAt API)
  649. if (aIndex == 0 && mItems->MozItemCount() > 1 &&
  650. mItems->MozItemsAt(0)->Length() == 0) {
  651. mItems->PopIndexZero();
  652. }
  653. }
  654. void
  655. DataTransfer::MozClearDataAtHelper(const nsAString& aFormat, uint32_t aIndex,
  656. nsIPrincipal& aSubjectPrincipal,
  657. ErrorResult& aRv)
  658. {
  659. MOZ_ASSERT(!mReadOnly);
  660. MOZ_ASSERT(aIndex < MozItemCount());
  661. MOZ_ASSERT(aIndex == 0 ||
  662. (mEventMessage != eCut && mEventMessage != eCopy &&
  663. mEventMessage != ePaste));
  664. nsAutoString format;
  665. GetRealFormat(aFormat, format);
  666. mItems->MozRemoveByTypeAt(format, aIndex, aSubjectPrincipal, aRv);
  667. }
  668. void
  669. DataTransfer::SetDragImage(Element& aImage, int32_t aX, int32_t aY,
  670. ErrorResult& aRv)
  671. {
  672. if (mReadOnly) {
  673. aRv.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
  674. return;
  675. }
  676. mDragImage = &aImage;
  677. mDragImageX = aX;
  678. mDragImageY = aY;
  679. }
  680. NS_IMETHODIMP
  681. DataTransfer::SetDragImage(nsIDOMElement* aImage, int32_t aX, int32_t aY)
  682. {
  683. ErrorResult rv;
  684. nsCOMPtr<Element> image = do_QueryInterface(aImage);
  685. if (image) {
  686. SetDragImage(*image, aX, aY, rv);
  687. }
  688. return rv.StealNSResult();
  689. }
  690. already_AddRefed<Promise>
  691. DataTransfer::GetFilesAndDirectories(nsIPrincipal& aSubjectPrincipal,
  692. ErrorResult& aRv)
  693. {
  694. nsCOMPtr<nsINode> parentNode = do_QueryInterface(mParent);
  695. if (!parentNode) {
  696. aRv.Throw(NS_ERROR_FAILURE);
  697. return nullptr;
  698. }
  699. nsCOMPtr<nsIGlobalObject> global = parentNode->OwnerDoc()->GetScopeObject();
  700. MOZ_ASSERT(global);
  701. if (!global) {
  702. aRv.Throw(NS_ERROR_FAILURE);
  703. return nullptr;
  704. }
  705. RefPtr<Promise> p = Promise::Create(global, aRv);
  706. if (NS_WARN_IF(aRv.Failed())) {
  707. return nullptr;
  708. }
  709. RefPtr<FileList> files = mItems->Files(&aSubjectPrincipal);
  710. if (NS_WARN_IF(!files)) {
  711. return nullptr;
  712. }
  713. Sequence<RefPtr<File>> filesSeq;
  714. files->ToSequence(filesSeq, aRv);
  715. if (NS_WARN_IF(aRv.Failed())) {
  716. return nullptr;
  717. }
  718. p->MaybeResolve(filesSeq);
  719. return p.forget();
  720. }
  721. already_AddRefed<Promise>
  722. DataTransfer::GetFiles(bool aRecursiveFlag,
  723. nsIPrincipal& aSubjectPrincipal,
  724. ErrorResult& aRv)
  725. {
  726. // Currently we don't support directories.
  727. return GetFilesAndDirectories(aSubjectPrincipal, aRv);
  728. }
  729. void
  730. DataTransfer::AddElement(Element& aElement, ErrorResult& aRv)
  731. {
  732. if (mReadOnly) {
  733. aRv.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
  734. return;
  735. }
  736. mDragTarget = &aElement;
  737. }
  738. NS_IMETHODIMP
  739. DataTransfer::AddElement(nsIDOMElement* aElement)
  740. {
  741. NS_ENSURE_TRUE(aElement, NS_ERROR_NULL_POINTER);
  742. nsCOMPtr<Element> element = do_QueryInterface(aElement);
  743. NS_ENSURE_TRUE(element, NS_ERROR_INVALID_ARG);
  744. ErrorResult rv;
  745. AddElement(*element, rv);
  746. return rv.StealNSResult();
  747. }
  748. nsresult
  749. DataTransfer::Clone(nsISupports* aParent, EventMessage aEventMessage,
  750. bool aUserCancelled, bool aIsCrossDomainSubFrameDrop,
  751. DataTransfer** aNewDataTransfer)
  752. {
  753. RefPtr<DataTransfer> newDataTransfer =
  754. new DataTransfer(aParent, aEventMessage, mEffectAllowed, mCursorState,
  755. mIsExternal, aUserCancelled, aIsCrossDomainSubFrameDrop,
  756. mClipboardType, mItems, mDragImage, mDragImageX,
  757. mDragImageY);
  758. newDataTransfer.forget(aNewDataTransfer);
  759. return NS_OK;
  760. }
  761. already_AddRefed<nsIArray>
  762. DataTransfer::GetTransferables(nsIDOMNode* aDragTarget)
  763. {
  764. MOZ_ASSERT(aDragTarget);
  765. nsCOMPtr<nsINode> dragNode = do_QueryInterface(aDragTarget);
  766. if (!dragNode) {
  767. return nullptr;
  768. }
  769. nsIDocument* doc = dragNode->GetComposedDoc();
  770. if (!doc) {
  771. return nullptr;
  772. }
  773. return GetTransferables(doc->GetLoadContext());
  774. }
  775. already_AddRefed<nsIArray>
  776. DataTransfer::GetTransferables(nsILoadContext* aLoadContext)
  777. {
  778. nsCOMPtr<nsIMutableArray> transArray = nsArray::Create();
  779. if (!transArray) {
  780. return nullptr;
  781. }
  782. uint32_t count = MozItemCount();
  783. for (uint32_t i = 0; i < count; i++) {
  784. nsCOMPtr<nsITransferable> transferable = GetTransferable(i, aLoadContext);
  785. if (transferable) {
  786. transArray->AppendElement(transferable, /*weak =*/ false);
  787. }
  788. }
  789. return transArray.forget();
  790. }
  791. already_AddRefed<nsITransferable>
  792. DataTransfer::GetTransferable(uint32_t aIndex, nsILoadContext* aLoadContext)
  793. {
  794. if (aIndex >= MozItemCount()) {
  795. return nullptr;
  796. }
  797. const nsTArray<RefPtr<DataTransferItem>>& item = *mItems->MozItemsAt(aIndex);
  798. uint32_t count = item.Length();
  799. if (!count) {
  800. return nullptr;
  801. }
  802. nsCOMPtr<nsITransferable> transferable =
  803. do_CreateInstance("@mozilla.org/widget/transferable;1");
  804. if (!transferable) {
  805. return nullptr;
  806. }
  807. transferable->Init(aLoadContext);
  808. nsCOMPtr<nsIStorageStream> storageStream;
  809. nsCOMPtr<nsIBinaryOutputStream> stream;
  810. bool added = false;
  811. bool handlingCustomFormats = true;
  812. // When writing the custom data, we need to ensure that there is sufficient
  813. // space for a (uint32_t) data ending type, and the null byte character at
  814. // the end of the nsCString. We claim that space upfront and store it in
  815. // baseLength. This value will be set to zero if a write error occurs
  816. // indicating that the data and length are no longer valid.
  817. const uint32_t baseLength = sizeof(uint32_t) + 1;
  818. uint32_t totalCustomLength = baseLength;
  819. const char* knownFormats[] = {
  820. kTextMime, kHTMLMime, kNativeHTMLMime, kRTFMime,
  821. kURLMime, kURLDataMime, kURLDescriptionMime, kURLPrivateMime,
  822. kPNGImageMime, kJPEGImageMime, kGIFImageMime, kNativeImageMime,
  823. kFileMime, kFilePromiseMime, kFilePromiseURLMime,
  824. kFilePromiseDestFilename, kFilePromiseDirectoryMime,
  825. kMozTextInternal, kHTMLContext, kHTMLInfo };
  826. /*
  827. * Two passes are made here to iterate over all of the types. First, look for
  828. * any types that are not in the list of known types. For this pass,
  829. * handlingCustomFormats will be true. Data that corresponds to unknown types
  830. * will be pulled out and inserted into a single type (kCustomTypesMime) by
  831. * writing the data into a stream.
  832. *
  833. * The second pass will iterate over the formats looking for known types.
  834. * These are added as is. The unknown types are all then inserted as a single
  835. * type (kCustomTypesMime) in the same position of the first custom type. This
  836. * model is used to maintain the format order as best as possible.
  837. *
  838. * The format of the kCustomTypesMime type is one or more of the following
  839. * stored sequentially:
  840. * <32-bit> type (only none or string is supported)
  841. * <32-bit> length of format
  842. * <wide string> format
  843. * <32-bit> length of data
  844. * <wide string> data
  845. * A type of eCustomClipboardTypeId_None ends the list, without any following
  846. * data.
  847. */
  848. do {
  849. for (uint32_t f = 0; f < count; f++) {
  850. RefPtr<DataTransferItem> formatitem = item[f];
  851. nsCOMPtr<nsIVariant> variant = formatitem->DataNoSecurityCheck();
  852. if (!variant) { // skip empty items
  853. continue;
  854. }
  855. nsAutoString type;
  856. formatitem->GetInternalType(type);
  857. // If the data is of one of the well-known formats, use it directly.
  858. bool isCustomFormat = true;
  859. for (uint32_t f = 0; f < ArrayLength(knownFormats); f++) {
  860. if (type.EqualsASCII(knownFormats[f])) {
  861. isCustomFormat = false;
  862. break;
  863. }
  864. }
  865. uint32_t lengthInBytes;
  866. nsCOMPtr<nsISupports> convertedData;
  867. if (handlingCustomFormats) {
  868. if (!ConvertFromVariant(variant, getter_AddRefs(convertedData),
  869. &lengthInBytes)) {
  870. continue;
  871. }
  872. // When handling custom types, add the data to the stream if this is a
  873. // custom type. If totalCustomLength is 0, then a write error occurred
  874. // on a previous item, so ignore any others.
  875. if (isCustomFormat && totalCustomLength > 0) {
  876. // If it isn't a string, just ignore it. The dataTransfer is cached in
  877. // the drag sesion during drag-and-drop, so non-strings will be
  878. // available when dragging locally.
  879. nsCOMPtr<nsISupportsString> str(do_QueryInterface(convertedData));
  880. if (str) {
  881. nsAutoString data;
  882. str->GetData(data);
  883. if (!stream) {
  884. // Create a storage stream to write to.
  885. NS_NewStorageStream(1024, UINT32_MAX, getter_AddRefs(storageStream));
  886. nsCOMPtr<nsIOutputStream> outputStream;
  887. storageStream->GetOutputStream(0, getter_AddRefs(outputStream));
  888. stream = do_CreateInstance("@mozilla.org/binaryoutputstream;1");
  889. stream->SetOutputStream(outputStream);
  890. }
  891. CheckedInt<uint32_t> formatLength =
  892. CheckedInt<uint32_t>(type.Length()) * sizeof(nsString::char_type);
  893. // The total size of the stream is the format length, the data
  894. // length, two integers to hold the lengths and one integer for
  895. // the string flag. Guard against large data by ignoring any that
  896. // don't fit.
  897. CheckedInt<uint32_t> newSize = formatLength + totalCustomLength +
  898. lengthInBytes + (sizeof(uint32_t) * 3);
  899. if (newSize.isValid()) {
  900. // If a write error occurs, set totalCustomLength to 0 so that
  901. // further processing gets ignored.
  902. nsresult rv = stream->Write32(eCustomClipboardTypeId_String);
  903. if (NS_WARN_IF(NS_FAILED(rv))) {
  904. totalCustomLength = 0;
  905. continue;
  906. }
  907. rv = stream->Write32(formatLength.value());
  908. if (NS_WARN_IF(NS_FAILED(rv))) {
  909. totalCustomLength = 0;
  910. continue;
  911. }
  912. rv = stream->WriteBytes((const char *)type.get(), formatLength.value());
  913. if (NS_WARN_IF(NS_FAILED(rv))) {
  914. totalCustomLength = 0;
  915. continue;
  916. }
  917. rv = stream->Write32(lengthInBytes);
  918. if (NS_WARN_IF(NS_FAILED(rv))) {
  919. totalCustomLength = 0;
  920. continue;
  921. }
  922. rv = stream->WriteBytes((const char *)data.get(), lengthInBytes);
  923. if (NS_WARN_IF(NS_FAILED(rv))) {
  924. totalCustomLength = 0;
  925. continue;
  926. }
  927. totalCustomLength = newSize.value();
  928. }
  929. }
  930. }
  931. } else if (isCustomFormat && stream) {
  932. // This is the second pass of the loop (handlingCustomFormats is false).
  933. // When encountering the first custom format, append all of the stream
  934. // at this position. If totalCustomLength is 0 indicating a write error
  935. // occurred, or no data has been added to it, don't output anything,
  936. if (totalCustomLength > baseLength) {
  937. // Write out an end of data terminator.
  938. nsresult rv = stream->Write32(eCustomClipboardTypeId_None);
  939. if (NS_SUCCEEDED(rv)) {
  940. nsCOMPtr<nsIInputStream> inputStream;
  941. storageStream->NewInputStream(0, getter_AddRefs(inputStream));
  942. RefPtr<nsStringBuffer> stringBuffer =
  943. nsStringBuffer::Alloc(totalCustomLength);
  944. // Subtract off the null terminator when reading.
  945. totalCustomLength--;
  946. // Read the data from the stream and add a null-terminator as
  947. // ToString needs it.
  948. uint32_t amountRead;
  949. rv = inputStream->Read(static_cast<char*>(stringBuffer->Data()),
  950. totalCustomLength, &amountRead);
  951. if (NS_SUCCEEDED(rv)) {
  952. static_cast<char*>(stringBuffer->Data())[amountRead] = 0;
  953. nsCString str;
  954. stringBuffer->ToString(totalCustomLength, str);
  955. nsCOMPtr<nsISupportsCString>
  956. strSupports(do_CreateInstance(NS_SUPPORTS_CSTRING_CONTRACTID));
  957. strSupports->SetData(str);
  958. nsresult rv = transferable->SetTransferData(kCustomTypesMime,
  959. strSupports,
  960. totalCustomLength);
  961. if (NS_FAILED(rv)) {
  962. return nullptr;
  963. }
  964. added = true;
  965. }
  966. }
  967. }
  968. // Clear the stream so it doesn't get used again.
  969. stream = nullptr;
  970. } else {
  971. // This is the second pass of the loop and a known type is encountered.
  972. // Add it as is.
  973. if (!ConvertFromVariant(variant, getter_AddRefs(convertedData),
  974. &lengthInBytes)) {
  975. continue;
  976. }
  977. // The underlying drag code uses text/unicode, so use that instead of
  978. // text/plain
  979. const char* format;
  980. NS_ConvertUTF16toUTF8 utf8format(type);
  981. if (utf8format.EqualsLiteral(kTextMime)) {
  982. format = kUnicodeMime;
  983. } else {
  984. format = utf8format.get();
  985. }
  986. // If a converter is set for a format, set the converter for the
  987. // transferable and don't add the item
  988. nsCOMPtr<nsIFormatConverter> converter =
  989. do_QueryInterface(convertedData);
  990. if (converter) {
  991. transferable->AddDataFlavor(format);
  992. transferable->SetConverter(converter);
  993. continue;
  994. }
  995. nsresult rv = transferable->SetTransferData(format, convertedData,
  996. lengthInBytes);
  997. if (NS_FAILED(rv)) {
  998. return nullptr;
  999. }
  1000. added = true;
  1001. }
  1002. }
  1003. handlingCustomFormats = !handlingCustomFormats;
  1004. } while (!handlingCustomFormats);
  1005. // only return the transferable if data was successfully added to it
  1006. if (added) {
  1007. return transferable.forget();
  1008. }
  1009. return nullptr;
  1010. }
  1011. bool
  1012. DataTransfer::ConvertFromVariant(nsIVariant* aVariant,
  1013. nsISupports** aSupports,
  1014. uint32_t* aLength) const
  1015. {
  1016. *aSupports = nullptr;
  1017. *aLength = 0;
  1018. uint16_t type;
  1019. aVariant->GetDataType(&type);
  1020. if (type == nsIDataType::VTYPE_INTERFACE ||
  1021. type == nsIDataType::VTYPE_INTERFACE_IS) {
  1022. nsCOMPtr<nsISupports> data;
  1023. if (NS_FAILED(aVariant->GetAsISupports(getter_AddRefs(data)))) {
  1024. return false;
  1025. }
  1026. nsCOMPtr<nsIFlavorDataProvider> fdp = do_QueryInterface(data);
  1027. if (fdp) {
  1028. // for flavour data providers, use kFlavorHasDataProvider (which has the
  1029. // value 0) as the length.
  1030. fdp.forget(aSupports);
  1031. *aLength = nsITransferable::kFlavorHasDataProvider;
  1032. }
  1033. else {
  1034. // wrap the item in an nsISupportsInterfacePointer
  1035. nsCOMPtr<nsISupportsInterfacePointer> ptrSupports =
  1036. do_CreateInstance(NS_SUPPORTS_INTERFACE_POINTER_CONTRACTID);
  1037. if (!ptrSupports) {
  1038. return false;
  1039. }
  1040. ptrSupports->SetData(data);
  1041. ptrSupports.forget(aSupports);
  1042. *aLength = sizeof(nsISupportsInterfacePointer *);
  1043. }
  1044. return true;
  1045. }
  1046. char16_t* chrs;
  1047. uint32_t len = 0;
  1048. nsresult rv = aVariant->GetAsWStringWithSize(&len, &chrs);
  1049. if (NS_FAILED(rv)) {
  1050. return false;
  1051. }
  1052. nsAutoString str;
  1053. str.Adopt(chrs, len);
  1054. nsCOMPtr<nsISupportsString>
  1055. strSupports(do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID));
  1056. if (!strSupports) {
  1057. return false;
  1058. }
  1059. strSupports->SetData(str);
  1060. strSupports.forget(aSupports);
  1061. // each character is two bytes
  1062. *aLength = str.Length() << 1;
  1063. return true;
  1064. }
  1065. void
  1066. DataTransfer::ClearAll()
  1067. {
  1068. mItems->ClearAllItems();
  1069. }
  1070. uint32_t
  1071. DataTransfer::MozItemCount() const
  1072. {
  1073. return mItems->MozItemCount();
  1074. }
  1075. nsresult
  1076. DataTransfer::SetDataWithPrincipal(const nsAString& aFormat,
  1077. nsIVariant* aData,
  1078. uint32_t aIndex,
  1079. nsIPrincipal* aPrincipal)
  1080. {
  1081. nsAutoString format;
  1082. GetRealFormat(aFormat, format);
  1083. ErrorResult rv;
  1084. RefPtr<DataTransferItem> item =
  1085. mItems->SetDataWithPrincipal(format, aData, aIndex, aPrincipal,
  1086. /* aInsertOnly = */ false,
  1087. /* aHidden= */ false,
  1088. rv);
  1089. return rv.StealNSResult();
  1090. }
  1091. void
  1092. DataTransfer::SetDataWithPrincipalFromOtherProcess(const nsAString& aFormat,
  1093. nsIVariant* aData,
  1094. uint32_t aIndex,
  1095. nsIPrincipal* aPrincipal,
  1096. bool aHidden)
  1097. {
  1098. if (aFormat.EqualsLiteral(kCustomTypesMime)) {
  1099. FillInExternalCustomTypes(aData, aIndex, aPrincipal);
  1100. } else {
  1101. nsAutoString format;
  1102. GetRealFormat(aFormat, format);
  1103. ErrorResult rv;
  1104. RefPtr<DataTransferItem> item =
  1105. mItems->SetDataWithPrincipal(format, aData, aIndex, aPrincipal,
  1106. /* aInsertOnly = */ false, aHidden, rv);
  1107. if (NS_WARN_IF(rv.Failed())) {
  1108. rv.SuppressException();
  1109. }
  1110. }
  1111. }
  1112. void
  1113. DataTransfer::GetRealFormat(const nsAString& aInFormat,
  1114. nsAString& aOutFormat) const
  1115. {
  1116. // treat text/unicode as equivalent to text/plain
  1117. nsAutoString lowercaseFormat;
  1118. nsContentUtils::ASCIIToLower(aInFormat, lowercaseFormat);
  1119. if (lowercaseFormat.EqualsLiteral("text") ||
  1120. lowercaseFormat.EqualsLiteral("text/unicode")) {
  1121. aOutFormat.AssignLiteral("text/plain");
  1122. return;
  1123. }
  1124. if (lowercaseFormat.EqualsLiteral("url")) {
  1125. aOutFormat.AssignLiteral("text/uri-list");
  1126. return;
  1127. }
  1128. aOutFormat.Assign(lowercaseFormat);
  1129. }
  1130. nsresult
  1131. DataTransfer::CacheExternalData(const char* aFormat, uint32_t aIndex,
  1132. nsIPrincipal* aPrincipal, bool aHidden)
  1133. {
  1134. ErrorResult rv;
  1135. RefPtr<DataTransferItem> item;
  1136. if (strcmp(aFormat, kUnicodeMime) == 0) {
  1137. item = mItems->SetDataWithPrincipal(NS_LITERAL_STRING("text/plain"), nullptr,
  1138. aIndex, aPrincipal, false, aHidden, rv);
  1139. if (NS_WARN_IF(rv.Failed())) {
  1140. return rv.StealNSResult();
  1141. }
  1142. return NS_OK;
  1143. }
  1144. if (strcmp(aFormat, kURLDataMime) == 0) {
  1145. item = mItems->SetDataWithPrincipal(NS_LITERAL_STRING("text/uri-list"), nullptr,
  1146. aIndex, aPrincipal, false, aHidden, rv);
  1147. if (NS_WARN_IF(rv.Failed())) {
  1148. return rv.StealNSResult();
  1149. }
  1150. return NS_OK;
  1151. }
  1152. nsAutoString format;
  1153. GetRealFormat(NS_ConvertUTF8toUTF16(aFormat), format);
  1154. item = mItems->SetDataWithPrincipal(format, nullptr, aIndex,
  1155. aPrincipal, false, aHidden, rv);
  1156. if (NS_WARN_IF(rv.Failed())) {
  1157. return rv.StealNSResult();
  1158. }
  1159. return NS_OK;
  1160. }
  1161. void
  1162. DataTransfer::CacheExternalDragFormats()
  1163. {
  1164. // Called during the constructor to cache the formats available from an
  1165. // external drag. The data associated with each format will be set to null.
  1166. // This data will instead only be retrieved in FillInExternalDragData when
  1167. // asked for, as it may be time consuming for the source application to
  1168. // generate it.
  1169. nsCOMPtr<nsIDragSession> dragSession = nsContentUtils::GetDragSession();
  1170. if (!dragSession) {
  1171. return;
  1172. }
  1173. // make sure that the system principal is used for external drags
  1174. nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
  1175. nsCOMPtr<nsIPrincipal> sysPrincipal;
  1176. ssm->GetSystemPrincipal(getter_AddRefs(sysPrincipal));
  1177. // there isn't a way to get a list of the formats that might be available on
  1178. // all platforms, so just check for the types that can actually be imported
  1179. // XXXndeakin there are some other formats but those are platform specific.
  1180. // NOTE: kFileMime must have index 0
  1181. const char* formats[] = { kFileMime, kHTMLMime, kURLMime, kURLDataMime,
  1182. kUnicodeMime, kPNGImageMime };
  1183. uint32_t count;
  1184. dragSession->GetNumDropItems(&count);
  1185. for (uint32_t c = 0; c < count; c++) {
  1186. bool hasFileData = false;
  1187. dragSession->IsDataFlavorSupported(kFileMime, &hasFileData);
  1188. // First, check for the special format that holds custom types.
  1189. bool supported;
  1190. dragSession->IsDataFlavorSupported(kCustomTypesMime, &supported);
  1191. if (supported) {
  1192. FillInExternalCustomTypes(c, sysPrincipal);
  1193. }
  1194. for (uint32_t f = 0; f < ArrayLength(formats); f++) {
  1195. // IsDataFlavorSupported doesn't take an index as an argument and just
  1196. // checks if any of the items support a particular flavor, even though
  1197. // the GetData method does take an index. Here, we just assume that
  1198. // every item being dragged has the same set of flavors.
  1199. bool supported;
  1200. dragSession->IsDataFlavorSupported(formats[f], &supported);
  1201. // if the format is supported, add an item to the array with null as
  1202. // the data. When retrieved, GetRealData will read the data.
  1203. if (supported) {
  1204. CacheExternalData(formats[f], c, sysPrincipal, /* hidden = */ f && hasFileData);
  1205. }
  1206. }
  1207. }
  1208. }
  1209. void
  1210. DataTransfer::CacheExternalClipboardFormats()
  1211. {
  1212. NS_ASSERTION(mEventMessage == ePaste,
  1213. "caching clipboard data for invalid event");
  1214. // Called during the constructor for paste events to cache the formats
  1215. // available on the clipboard. As with CacheExternalDragFormats, the
  1216. // data will only be retrieved when needed.
  1217. nsCOMPtr<nsIClipboard> clipboard =
  1218. do_GetService("@mozilla.org/widget/clipboard;1");
  1219. if (!clipboard || mClipboardType < 0) {
  1220. return;
  1221. }
  1222. nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
  1223. nsCOMPtr<nsIPrincipal> sysPrincipal;
  1224. ssm->GetSystemPrincipal(getter_AddRefs(sysPrincipal));
  1225. // Check if the clipboard has any files
  1226. bool hasFileData = false;
  1227. const char *fileMime[] = { kFileMime };
  1228. clipboard->HasDataMatchingFlavors(fileMime, 1, mClipboardType, &hasFileData);
  1229. // We will be ignoring any application/x-moz-file files found in the paste
  1230. // datatransfer within e10s, as they will fail to be sent over IPC. Because of
  1231. // that, we will unset hasFileData, whether or not it would have been set.
  1232. // (bug 1308007)
  1233. if (XRE_IsContentProcess()) {
  1234. hasFileData = false;
  1235. }
  1236. // there isn't a way to get a list of the formats that might be available on
  1237. // all platforms, so just check for the types that can actually be imported.
  1238. // NOTE: kCustomTypesMime must have index 0, kFileMime index 1
  1239. const char* formats[] = { kCustomTypesMime, kFileMime, kHTMLMime, kRTFMime,
  1240. kURLMime, kURLDataMime, kUnicodeMime, kPNGImageMime };
  1241. for (uint32_t f = 0; f < mozilla::ArrayLength(formats); ++f) {
  1242. // check each format one at a time
  1243. bool supported;
  1244. clipboard->HasDataMatchingFlavors(&(formats[f]), 1, mClipboardType,
  1245. &supported);
  1246. // if the format is supported, add an item to the array with null as
  1247. // the data. When retrieved, GetRealData will read the data.
  1248. if (supported) {
  1249. if (f == 0) {
  1250. FillInExternalCustomTypes(0, sysPrincipal);
  1251. } else {
  1252. // In non-e10s we support pasting files from explorer.exe.
  1253. // Unfortunately, we fail to send that data over IPC in e10s, so we
  1254. // don't want to add the item to the DataTransfer and end up producing a
  1255. // null `application/x-moz-file`. (bug 1308007)
  1256. if (XRE_IsContentProcess() && f == 1) {
  1257. continue;
  1258. }
  1259. // If we aren't the file data, and we have file data, we want to be hidden
  1260. CacheExternalData(formats[f], 0, sysPrincipal, /* hidden = */ f != 1 && hasFileData);
  1261. }
  1262. }
  1263. }
  1264. }
  1265. void
  1266. DataTransfer::FillAllExternalData()
  1267. {
  1268. if (mIsExternal) {
  1269. for (uint32_t i = 0; i < MozItemCount(); ++i) {
  1270. const nsTArray<RefPtr<DataTransferItem>>& items = *mItems->MozItemsAt(i);
  1271. for (uint32_t j = 0; j < items.Length(); ++j) {
  1272. MOZ_ASSERT(items[j]->Index() == i);
  1273. items[j]->FillInExternalData();
  1274. }
  1275. }
  1276. }
  1277. }
  1278. void
  1279. DataTransfer::FillInExternalCustomTypes(uint32_t aIndex,
  1280. nsIPrincipal* aPrincipal)
  1281. {
  1282. RefPtr<DataTransferItem> item = new DataTransferItem(this,
  1283. NS_LITERAL_STRING(kCustomTypesMime),
  1284. DataTransferItem::KIND_STRING);
  1285. item->SetIndex(aIndex);
  1286. nsCOMPtr<nsIVariant> variant = item->DataNoSecurityCheck();
  1287. if (!variant) {
  1288. return;
  1289. }
  1290. FillInExternalCustomTypes(variant, aIndex, aPrincipal);
  1291. }
  1292. void
  1293. DataTransfer::FillInExternalCustomTypes(nsIVariant* aData, uint32_t aIndex,
  1294. nsIPrincipal* aPrincipal)
  1295. {
  1296. char* chrs;
  1297. uint32_t len = 0;
  1298. nsresult rv = aData->GetAsStringWithSize(&len, &chrs);
  1299. if (NS_FAILED(rv)) {
  1300. return;
  1301. }
  1302. nsAutoCString str;
  1303. str.Adopt(chrs, len);
  1304. nsCOMPtr<nsIInputStream> stringStream;
  1305. NS_NewCStringInputStream(getter_AddRefs(stringStream), str);
  1306. nsCOMPtr<nsIBinaryInputStream> stream =
  1307. do_CreateInstance("@mozilla.org/binaryinputstream;1");
  1308. if (!stream) {
  1309. return;
  1310. }
  1311. rv = stream->SetInputStream(stringStream);
  1312. NS_ENSURE_SUCCESS_VOID(rv);
  1313. uint32_t type;
  1314. do {
  1315. rv = stream->Read32(&type);
  1316. NS_ENSURE_SUCCESS_VOID(rv);
  1317. if (type == eCustomClipboardTypeId_String) {
  1318. uint32_t formatLength;
  1319. rv = stream->Read32(&formatLength);
  1320. NS_ENSURE_SUCCESS_VOID(rv);
  1321. char* formatBytes;
  1322. rv = stream->ReadBytes(formatLength, &formatBytes);
  1323. NS_ENSURE_SUCCESS_VOID(rv);
  1324. nsAutoString format;
  1325. format.Adopt(reinterpret_cast<char16_t*>(formatBytes),
  1326. formatLength / sizeof(char16_t));
  1327. uint32_t dataLength;
  1328. rv = stream->Read32(&dataLength);
  1329. NS_ENSURE_SUCCESS_VOID(rv);
  1330. char* dataBytes;
  1331. rv = stream->ReadBytes(dataLength, &dataBytes);
  1332. NS_ENSURE_SUCCESS_VOID(rv);
  1333. nsAutoString data;
  1334. data.Adopt(reinterpret_cast<char16_t*>(dataBytes),
  1335. dataLength / sizeof(char16_t));
  1336. RefPtr<nsVariantCC> variant = new nsVariantCC();
  1337. rv = variant->SetAsAString(data);
  1338. NS_ENSURE_SUCCESS_VOID(rv);
  1339. SetDataWithPrincipal(format, variant, aIndex, aPrincipal);
  1340. }
  1341. } while (type != eCustomClipboardTypeId_None);
  1342. }
  1343. } // namespace dom
  1344. } // namespace mozilla