Bug 1424107 - Pass the triggering principal URI across processes in drag-and-drop. r=smaug
authorTooru Fujisawa <arai_a@mac.com>
Fri, 09 Feb 2018 10:43:53 +0900
changeset 458084 fc5cbc7e0d7ff28ed81f802a4973e2e8634cfe61
parent 458083 21f73ed97e6a5c9ff968a710da3d7ddb62fce2ca
child 458085 1fa8c5b051ac7a91c3856610fe99b8af0066cb54
push id1683
push usersfraser@mozilla.com
push dateThu, 26 Apr 2018 16:43:40 +0000
treeherdermozilla-release@5af6cb21869d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1424107
milestone60.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1424107 - Pass the triggering principal URI across processes in drag-and-drop. r=smaug
dom/base/contentAreaDropListener.js
dom/base/nsContentAreaDragDrop.cpp
dom/base/nsContentAreaDragDrop.h
dom/events/DataTransfer.cpp
dom/events/DataTransfer.h
dom/events/EventStateManager.cpp
dom/events/EventStateManager.h
dom/ipc/PBrowser.ipdl
dom/ipc/TabChild.cpp
dom/ipc/TabChild.h
dom/ipc/TabParent.cpp
dom/ipc/TabParent.h
dom/webidl/DataTransfer.webidl
widget/gtk/nsDragService.cpp
widget/gtk/nsDragService.h
widget/nsBaseDragService.cpp
widget/nsBaseDragService.h
widget/nsDragServiceProxy.cpp
widget/nsIDragService.idl
widget/nsIDragSession.idl
--- a/dom/base/contentAreaDropListener.js
+++ b/dom/base/contentAreaDropListener.js
@@ -109,55 +109,74 @@ ContentAreaDropListener.prototype =
       uri = ioService.newURI(uriString);
     } catch (ex) { }
     if (!uri)
       return uriString;
 
     // uriString is a valid URI, so do the security check.
     let secMan = Cc["@mozilla.org/scriptsecuritymanager;1"].
                    getService(Ci.nsIScriptSecurityManager);
-    let sourceNode = dataTransfer.mozSourceNode;
     let flags = secMan.STANDARD;
     if (disallowInherit)
       flags |= secMan.DISALLOW_INHERIT_PRINCIPAL;
 
-    let principal;
-    if (sourceNode) {
-      principal = this._getTriggeringPrincipalFromSourceNode(sourceNode);
-    } else {
-      // Use file:/// as the default uri so that drops of file URIs are always
-      // allowed.
-      principal = secMan.createCodebasePrincipal(ioService.newURI("file:///"), {});
-    }
+    let principal = this._getTriggeringPrincipalFromDataTransfer(dataTransfer, false);
     secMan.checkLoadURIStrWithPrincipal(principal, uriString, flags);
 
     return uriString;
   },
 
-  _getTriggeringPrincipalFromSourceNode: function(aSourceNode)
+  _getTriggeringPrincipalFromDataTransfer: function(aDataTransfer,
+                                                    fallbackToSystemPrincipal)
   {
-    if (aSourceNode.localName == "browser" &&
-        aSourceNode.namespaceURI == "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul") {
-      return aSourceNode.contentPrincipal;
+    let sourceNode = aDataTransfer.mozSourceNode;
+    if (sourceNode &&
+        (sourceNode.localName !== "browser" ||
+         sourceNode.namespaceURI !== "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul")) {
+      // Use sourceNode's principal only if the sourceNode is not browser.
+      //
+      // If sourceNode is browser, the actual triggering principal may be
+      // differ than sourceNode's principal, since sourceNode's principal is
+      // top level document's one and the drag may be triggered from a frame
+      // with different principal.
+      if (sourceNode.nodePrincipal) {
+        return sourceNode.nodePrincipal;
+      }
     }
-    return aSourceNode.nodePrincipal;
+
+    // First, fallback to mozTriggeringPrincipalURISpec that is set when the
+    // drop comes from another content process.
+    let principalURISpec = aDataTransfer.mozTriggeringPrincipalURISpec;
+    if (!principalURISpec) {
+      // Fallback to either system principal or file principal, supposing
+      // the drop comes from outside of the browser, so that drops of file
+      // URIs are always allowed.
+      //
+      // TODO: Investigate and describe the difference between them,
+      //       or use only one principal. (Bug 1367038)
+      if (fallbackToSystemPrincipal) {
+        let secMan = Cc["@mozilla.org/scriptsecuritymanager;1"].
+            getService(Ci.nsIScriptSecurityManager);
+        return secMan.getSystemPrincipal();
+      } else {
+        principalURISpec = "file:///";
+      }
+    }
+    let ioService = Cc["@mozilla.org/network/io-service;1"]
+        .getService(Components.interfaces.nsIIOService);
+    let secMan = Cc["@mozilla.org/scriptsecuritymanager;1"].
+        getService(Ci.nsIScriptSecurityManager);
+    return secMan.createCodebasePrincipal(ioService.newURI(principalURISpec), {});
   },
 
   getTriggeringPrincipal: function(aEvent)
   {
     let dataTransfer = aEvent.dataTransfer;
-    let sourceNode = dataTransfer.mozSourceNode;
-    if (sourceNode) {
-      return this._getTriggeringPrincipalFromSourceNode(sourceNode, false);
-    }
-    // Bug 1367038: mozSourceNode is null if the drag event originated
-    // in an external application - needs better fallback!
-    let secMan = Cc["@mozilla.org/scriptsecuritymanager;1"].
-                   getService(Ci.nsIScriptSecurityManager);
-    return secMan.getSystemPrincipal();
+    return this._getTriggeringPrincipalFromDataTransfer(dataTransfer, true);
+
   },
 
   canDropLink: function(aEvent, aAllowSameDocument)
   {
     if (this._eventTargetIsDisabled(aEvent))
       return false;
 
     let dataTransfer = aEvent.dataTransfer;
--- a/dom/base/nsContentAreaDragDrop.cpp
+++ b/dom/base/nsContentAreaDragDrop.cpp
@@ -67,17 +67,18 @@ class MOZ_STACK_CLASS DragDataProducer
 public:
   DragDataProducer(nsPIDOMWindowOuter* aWindow,
                    nsIContent* aTarget,
                    nsIContent* aSelectionTargetNode,
                    bool aIsAltKeyPressed);
   nsresult Produce(DataTransfer* aDataTransfer,
                    bool* aCanDrag,
                    nsISelection** aSelection,
-                   nsIContent** aDragNode);
+                   nsIContent** aDragNode,
+                   nsACString& aPrincipalURISpec);
 
 private:
   void AddString(DataTransfer* aDataTransfer,
                  const nsAString& aFlavor,
                  const nsAString& aData,
                  nsIPrincipal* aPrincipal);
   nsresult AddStringsToDataTransfer(nsIContent* aDragNode,
                                     DataTransfer* aDataTransfer);
@@ -114,25 +115,27 @@ private:
 nsresult
 nsContentAreaDragDrop::GetDragData(nsPIDOMWindowOuter* aWindow,
                                    nsIContent* aTarget,
                                    nsIContent* aSelectionTargetNode,
                                    bool aIsAltKeyPressed,
                                    DataTransfer* aDataTransfer,
                                    bool* aCanDrag,
                                    nsISelection** aSelection,
-                                   nsIContent** aDragNode)
+                                   nsIContent** aDragNode,
+                                   nsACString& aPrincipalURISpec)
 {
   NS_ENSURE_TRUE(aSelectionTargetNode, NS_ERROR_INVALID_ARG);
 
   *aCanDrag = true;
 
   DragDataProducer
     provider(aWindow, aTarget, aSelectionTargetNode, aIsAltKeyPressed);
-  return provider.Produce(aDataTransfer, aCanDrag, aSelection, aDragNode);
+  return provider.Produce(aDataTransfer, aCanDrag, aSelection, aDragNode,
+                          aPrincipalURISpec);
 }
 
 
 NS_IMPL_ISUPPORTS(nsContentAreaDragDropDataProvider, nsIFlavorDataProvider)
 
 // SaveURIToFile
 // used on platforms where it's possible to drag items (e.g. images)
 // into the file system
@@ -360,17 +363,18 @@ DragDataProducer::GetNodeString(nsIConte
     range->ToString(outNodeString);
   }
 }
 
 nsresult
 DragDataProducer::Produce(DataTransfer* aDataTransfer,
                           bool* aCanDrag,
                           nsISelection** aSelection,
-                          nsIContent** aDragNode)
+                          nsIContent** aDragNode,
+                          nsACString& aPrincipalURISpec)
 {
   NS_PRECONDITION(aCanDrag && aSelection && aDataTransfer && aDragNode,
                   "null pointer passed to Produce");
   NS_ASSERTION(mWindow, "window not set");
   NS_ASSERTION(mSelectionTargetNode, "selection target node should have been set");
 
   *aDragNode = nullptr;
 
@@ -425,17 +429,17 @@ DragDataProducer::Produce(DataTransfer* 
     nsCOMPtr<nsIFrameLoaderOwner> flo = do_QueryInterface(mTarget);
     if (flo) {
       RefPtr<nsFrameLoader> fl = flo->GetFrameLoader();
       if (fl) {
         TabParent* tp = static_cast<TabParent*>(fl->GetRemoteBrowser());
         if (tp) {
           // We have a TabParent, so it may have data for dnd in case the child
           // process started a dnd session.
-          tp->AddInitialDnDDataTo(aDataTransfer);
+          tp->AddInitialDnDDataTo(aDataTransfer, aPrincipalURISpec);
         }
       }
     }
     return NS_OK;
   }
 
   if (isChromeShell && textControl) {
     // Only use the selection if the target node is in the selection.
--- a/dom/base/nsContentAreaDragDrop.h
+++ b/dom/base/nsContentAreaDragDrop.h
@@ -45,25 +45,29 @@ public:
    *                    not drag the link.
    * aDataTransfer - the dataTransfer for the drag event.
    * aCanDrag - [out] set to true if the drag may proceed, false to stop the
    *            drag entirely
    * aSelection - [out] set to the selection being dragged, or null if no
    *                    selection is being dragged.
    * aDragNode - [out] the link, image or area being dragged, or null if the
    *             drag occurred on another element.
+   * aPrincipalURISpec - [out] set to the URI of the triggering principal of
+   *                           the drag, or empty string if it's from
+   *                           browser chrome or OS
    */
   static nsresult GetDragData(nsPIDOMWindowOuter* aWindow,
                               nsIContent* aTarget,
                               nsIContent* aSelectionTargetNode,
                               bool aIsAltKeyPressed,
                               mozilla::dom::DataTransfer* aDataTransfer,
                               bool* aCanDrag,
                               nsISelection** aSelection,
-                              nsIContent** aDragNode);
+                              nsIContent** aDragNode,
+                              nsACString& aPrincipalURISpec);
 };
 
 // this is used to save images to disk lazily when the image data is asked for
 // during the drop instead of when it is added to the drag data transfer. This
 // ensures that the image data is only created when an image drop is allowed.
 class nsContentAreaDragDropDataProvider : public nsIFlavorDataProvider
 {
   virtual ~nsContentAreaDragDropDataProvider() {}
--- a/dom/events/DataTransfer.cpp
+++ b/dom/events/DataTransfer.cpp
@@ -302,16 +302,30 @@ DataTransfer::SetDropEffectInt(uint32_t 
 
 NS_IMETHODIMP
 DataTransfer::GetEffectAllowedInt(uint32_t* aEffectAllowed)
 {
   *aEffectAllowed = mEffectAllowed;
   return  NS_OK;
 }
 
+void
+DataTransfer::GetMozTriggeringPrincipalURISpec(nsAString& aPrincipalURISpec)
+{
+  nsCOMPtr<nsIDragSession> dragSession = nsContentUtils::GetDragSession();
+  if (!dragSession) {
+    aPrincipalURISpec.Truncate(0);
+    return;
+  }
+
+  nsCString principalURISpec;
+  dragSession->GetTriggeringPrincipalURISpec(principalURISpec);
+  CopyUTF8toUTF16(principalURISpec, aPrincipalURISpec);
+}
+
 NS_IMETHODIMP
 DataTransfer::SetEffectAllowedInt(uint32_t aEffectAllowed)
 {
   mEffectAllowed = aEffectAllowed;
   return  NS_OK;
 }
 
 NS_IMETHODIMP
--- a/dom/events/DataTransfer.h
+++ b/dom/events/DataTransfer.h
@@ -206,16 +206,18 @@ public:
 
   bool MozUserCancelled() const
   {
     return mUserCancelled;
   }
 
   already_AddRefed<nsINode> GetMozSourceNode();
 
+  void GetMozTriggeringPrincipalURISpec(nsAString& aPrincipalURISpec);
+
   mozilla::dom::Element* GetDragTarget() const
   {
     return mDragTarget;
   }
 
   nsresult GetDataAtNoSecurityCheck(const nsAString& aFormat, uint32_t aIndex,
                                     nsIVariant** aData);
 
--- a/dom/events/EventStateManager.cpp
+++ b/dom/events/EventStateManager.cpp
@@ -1330,27 +1330,30 @@ EventStateManager::DispatchCrossProcessE
     RefPtr<TabParent> tabParent = remote;
     if (tabParent->Manager()->IsContentParent()) {
       tabParent->Manager()->AsContentParent()->MaybeInvokeDragSession(tabParent);
     }
 
     nsCOMPtr<nsIDragSession> dragSession = nsContentUtils::GetDragSession();
     uint32_t dropEffect = nsIDragService::DRAGDROP_ACTION_NONE;
     uint32_t action = nsIDragService::DRAGDROP_ACTION_NONE;
+    nsCString principalURISpec;
     if (dragSession) {
       dragSession->DragEventDispatchedToChildProcess();
       dragSession->GetDragAction(&action);
+      dragSession->GetTriggeringPrincipalURISpec(principalURISpec);
       nsCOMPtr<nsIDOMDataTransfer> initialDataTransfer;
       dragSession->GetDataTransfer(getter_AddRefs(initialDataTransfer));
       if (initialDataTransfer) {
         initialDataTransfer->GetDropEffectInt(&dropEffect);
       }
     }
 
-    tabParent->SendRealDragEvent(*aEvent->AsDragEvent(), action, dropEffect);
+    tabParent->SendRealDragEvent(*aEvent->AsDragEvent(), action, dropEffect,
+                                 principalURISpec);
     return;
   }
   case ePluginEventClass: {
     *aStatus = nsEventStatus_eConsumeNoDefault;
     remote->SendPluginEvent(*aEvent->AsPluginEvent());
     return;
   }
   default: {
@@ -1858,21 +1861,23 @@ EventStateManager::GenerateDragGesture(n
       auto protectDataTransfer = MakeScopeExit([&] {
         if (dataTransfer) {
           dataTransfer->Disconnect();
         }
       });
 
       nsCOMPtr<nsISelection> selection;
       nsCOMPtr<nsIContent> eventContent, targetContent;
+      nsCString principalURISpec;
       mCurrentTarget->GetContentForEvent(aEvent, getter_AddRefs(eventContent));
       if (eventContent)
         DetermineDragTargetAndDefaultData(window, eventContent, dataTransfer,
                                           getter_AddRefs(selection),
-                                          getter_AddRefs(targetContent));
+                                          getter_AddRefs(targetContent),
+                                          principalURISpec);
 
       // Stop tracking the drag gesture now. This should stop us from
       // reentering GenerateDragGesture inside DOM event processing.
       StopTrackingDragGesture();
 
       if (!targetContent)
         return;
 
@@ -1924,17 +1929,18 @@ EventStateManager::GenerateDragGesture(n
       if (observerService) {
         observerService->NotifyObservers(dataTransfer,
                                          "on-datatransfer-available",
                                          nullptr);
       }
 
       if (status != nsEventStatus_eConsumeNoDefault) {
         bool dragStarted = DoDefaultDragStart(aPresContext, event, dataTransfer,
-                                              targetContent, selection);
+                                              targetContent, selection,
+                                              principalURISpec);
         if (dragStarted) {
           sActiveESM = nullptr;
           MaybeFirePointerCancel(aEvent);
           aEvent->StopPropagation();
         }
       }
 
       // Reset mCurretTargetContent to what it was
@@ -1947,32 +1953,34 @@ EventStateManager::GenerateDragGesture(n
   }
 } // GenerateDragGesture
 
 void
 EventStateManager::DetermineDragTargetAndDefaultData(nsPIDOMWindowOuter* aWindow,
                                                      nsIContent* aSelectionTarget,
                                                      DataTransfer* aDataTransfer,
                                                      nsISelection** aSelection,
-                                                     nsIContent** aTargetNode)
+                                                     nsIContent** aTargetNode,
+                                                     nsACString& aPrincipalURISpec)
 {
   *aTargetNode = nullptr;
 
   // GetDragData determines if a selection, link or image in the content
   // should be dragged, and places the data associated with the drag in the
   // data transfer.
   // mGestureDownContent is the node where the mousedown event for the drag
   // occurred, and aSelectionTarget is the node to use when a selection is used
   bool canDrag;
   nsCOMPtr<nsIContent> dragDataNode;
   bool wasAlt = (mGestureModifiers & MODIFIER_ALT) != 0;
   nsresult rv = nsContentAreaDragDrop::GetDragData(aWindow, mGestureDownContent,
                                                    aSelectionTarget, wasAlt,
                                                    aDataTransfer, &canDrag, aSelection,
-                                                   getter_AddRefs(dragDataNode));
+                                                   getter_AddRefs(dragDataNode),
+                                                   aPrincipalURISpec);
   if (NS_FAILED(rv) || !canDrag)
     return;
 
   // if GetDragData returned a node, use that as the node being dragged.
   // Otherwise, if a selection is being dragged, use the node within the
   // selection that was dragged. Otherwise, just use the mousedown target.
   nsIContent* dragContent = mGestureDownContent;
   if (dragDataNode)
@@ -2026,17 +2034,18 @@ EventStateManager::DetermineDragTargetAn
   }
 }
 
 bool
 EventStateManager::DoDefaultDragStart(nsPresContext* aPresContext,
                                       WidgetDragEvent* aDragEvent,
                                       DataTransfer* aDataTransfer,
                                       nsIContent* aDragTarget,
-                                      nsISelection* aSelection)
+                                      nsISelection* aSelection,
+                                      const nsACString& aPrincipalURISpec)
 {
   nsCOMPtr<nsIDragService> dragService =
     do_GetService("@mozilla.org/widget/dragservice;1");
   if (!dragService)
     return false;
 
   // Default handling for the dragstart event.
   //
@@ -2105,17 +2114,19 @@ EventStateManager::DoDefaultDragStart(ns
   RefPtr<DragEvent> event =
     NS_NewDOMDragEvent(dragTarget, aPresContext, aDragEvent);
 
   // Use InvokeDragSessionWithSelection if a selection is being dragged,
   // such that the image can be generated from the selected text. However,
   // use InvokeDragSessionWithImage if a custom image was set or something
   // other than a selection is being dragged.
   if (!dragImage && aSelection) {
-    dragService->InvokeDragSessionWithSelection(aSelection, transArray,
+    dragService->InvokeDragSessionWithSelection(aSelection,
+                                                aPrincipalURISpec,
+                                                transArray,
                                                 action, event, dataTransfer);
   }
   else {
     // if dragging within a XUL tree and no custom drag image was
     // set, the region argument to InvokeDragSessionWithImage needs
     // to be set to the area encompassing the selected rows of the
     // tree to ensure that the drag feedback gets clipped to those
     // rows. For other content, region should be null.
@@ -2128,17 +2139,18 @@ EventStateManager::DoDefaultDragStart(ns
           do_QueryFrame(dragTarget->GetPrimaryFrame());
         if (treeBody) {
           treeBody->GetSelectionRegion(getter_AddRefs(region));
         }
       }
     }
 #endif
 
-    dragService->InvokeDragSessionWithImage(dragTarget->AsDOMNode(), transArray,
+    dragService->InvokeDragSessionWithImage(dragTarget->AsDOMNode(),
+                                            aPrincipalURISpec, transArray,
                                             region, action,
                                             dragImage ? dragImage->AsDOMNode() :
                                                         nullptr,
                                             imageX, imageY, event,
                                             dataTransfer);
   }
 
   return true;
--- a/dom/events/EventStateManager.h
+++ b/dom/events/EventStateManager.h
@@ -920,38 +920,45 @@ protected:
    * Determine which node the drag should be targeted at.
    * This is either the node clicked when there is a selection, or, for HTML,
    * the element with a draggable property set to true.
    *
    * aSelectionTarget - target to check for selection
    * aDataTransfer - data transfer object that will contain the data to drag
    * aSelection - [out] set to the selection to be dragged
    * aTargetNode - [out] the draggable node, or null if there isn't one
+   * aPrincipalURISpec - [out] set to the URI of the triggering principal of
+   *                           the drag, or an empty string if it's from
+   *                           browser chrome or OS
    */
   void DetermineDragTargetAndDefaultData(nsPIDOMWindowOuter* aWindow,
                                          nsIContent* aSelectionTarget,
                                          dom::DataTransfer* aDataTransfer,
                                          nsISelection** aSelection,
-                                         nsIContent** aTargetNode);
+                                         nsIContent** aTargetNode,
+                                         nsACString& aPrincipalURISpec);
 
   /*
    * Perform the default handling for the dragstart event and set up a
    * drag for aDataTransfer if it contains any data. Returns true if a drag has
    * started.
    *
    * aDragEvent - the dragstart event
    * aDataTransfer - the data transfer that holds the data to be dragged
    * aDragTarget - the target of the drag
    * aSelection - the selection to be dragged
+   * aPrincipalURISpec - the URI of the triggering principal of the drag,
+   *                     or an empty string if it's from browser chrome or OS
    */
   bool DoDefaultDragStart(nsPresContext* aPresContext,
                           WidgetDragEvent* aDragEvent,
                           dom::DataTransfer* aDataTransfer,
                           nsIContent* aDragTarget,
-                          nsISelection* aSelection);
+                          nsISelection* aSelection,
+                          const nsACString& aPrincipalURISpec);
 
   bool IsTrackingDragGesture ( ) const { return mGestureDownContent != nullptr; }
   /**
    * Set the fields of aEvent to reflect the mouse position and modifier keys
    * that were set when the user first pressed the mouse button (stored by
    * BeginTrackingDragGesture). aEvent->mWidget must be
    * mCurrentTarget->GetNearestWidget().
    */
--- a/dom/ipc/PBrowser.ipdl
+++ b/dom/ipc/PBrowser.ipdl
@@ -561,17 +561,18 @@ parent:
 
     nested(inside_sync) sync DispatchWheelEvent(WidgetWheelEvent event);
     nested(inside_sync) sync DispatchMouseEvent(WidgetMouseEvent event);
     nested(inside_sync) sync DispatchKeyboardEvent(WidgetKeyboardEvent event);
 
     async InvokeDragSession(IPCDataTransfer[] transfers, uint32_t action,
                             OptionalShmem visualData,
                             uint32_t stride, uint8_t format,
-                            LayoutDeviceIntRect dragRect);
+                            LayoutDeviceIntRect dragRect,
+                            nsCString principalURISpec);
 
     // After a compositor reset, it is necessary to reconnect each layers ID to
     // the compositor of the widget that will render those layers. Note that
     // this is sync so we can ensure that messages to the window compositor
     // arrive before the TabChild attempts to use its cross-process compositor
     // bridge.
     sync EnsureLayersConnected() returns (CompositorOptions compositorOptions);
 
@@ -700,17 +701,17 @@ child:
                                            uint64_t aInputBlockId,
                                            nsEventStatus aApzResponse);
 
     /*
      * We disable the input event queue when there is an active dnd session. We
      * don't need support RealDragEvent with input priority.
      */
     async RealDragEvent(WidgetDragEvent aEvent, uint32_t aDragAction,
-                        uint32_t aDropEffect);
+                        uint32_t aDropEffect, nsCString aPrincipalURISpec);
 
     async PluginEvent(WidgetPluginEvent aEvent);
 
     /**
      * @see nsIDOMWindowUtils sendKeyEvent.
      */
     async KeyEvent(nsString aType,
                    int32_t aKeyCode,
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -1943,24 +1943,26 @@ TabChild::RecvNormalPriorityRealTouchMov
   const nsEventStatus& aApzResponse)
 {
   return RecvRealTouchMoveEvent(aEvent, aGuid, aInputBlockId, aApzResponse);
 }
 
 mozilla::ipc::IPCResult
 TabChild::RecvRealDragEvent(const WidgetDragEvent& aEvent,
                             const uint32_t& aDragAction,
-                            const uint32_t& aDropEffect)
+                            const uint32_t& aDropEffect,
+                            const nsCString& aPrincipalURISpec)
 {
   WidgetDragEvent localEvent(aEvent);
   localEvent.mWidget = mPuppetWidget;
 
   nsCOMPtr<nsIDragSession> dragSession = nsContentUtils::GetDragSession();
   if (dragSession) {
     dragSession->SetDragAction(aDragAction);
+    dragSession->SetTriggeringPrincipalURISpec(aPrincipalURISpec);
     nsCOMPtr<nsIDOMDataTransfer> initialDataTransfer;
     dragSession->GetDataTransfer(getter_AddRefs(initialDataTransfer));
     if (initialDataTransfer) {
       initialDataTransfer->SetDropEffectInt(aDropEffect);
     }
   }
 
   if (aEvent.mMessage == eDrop) {
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -386,17 +386,18 @@ public:
                                                            const uint64_t& aInputBlockId) override;
   virtual mozilla::ipc::IPCResult
   RecvNormalPriorityRealMouseButtonEvent(const mozilla::WidgetMouseEvent& aEvent,
                                          const ScrollableLayerGuid& aGuid,
                                          const uint64_t& aInputBlockId) override;
 
   virtual mozilla::ipc::IPCResult RecvRealDragEvent(const WidgetDragEvent& aEvent,
                                                     const uint32_t& aDragAction,
-                                                    const uint32_t& aDropEffect) override;
+                                                    const uint32_t& aDropEffect,
+                                                    const nsCString& aPrincipalURISpec) override;
 
   virtual mozilla::ipc::IPCResult
   RecvRealKeyEvent(const mozilla::WidgetKeyboardEvent& aEvent) override;
 
   virtual mozilla::ipc::IPCResult
   RecvNormalPriorityRealKeyEvent(const mozilla::WidgetKeyboardEvent& aEvent) override;
 
   virtual mozilla::ipc::IPCResult RecvMouseWheelEvent(const mozilla::WidgetWheelEvent& aEvent,
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -1276,30 +1276,32 @@ TabParent::QueryDropLinksForVerification
     mVerifyDropLinks.Clear();
     return false;
   }
   return true;
 }
 
 void
 TabParent::SendRealDragEvent(WidgetDragEvent& aEvent, uint32_t aDragAction,
-                             uint32_t aDropEffect)
+                             uint32_t aDropEffect,
+                             const nsCString& aPrincipalURISpec)
 {
   if (mIsDestroyed || !mIsReadyToHandleInputEvents) {
     return;
   }
   MOZ_ASSERT(!Manager()->AsContentParent()->IsInputPriorityEventEnabled());
   aEvent.mRefPoint += GetChildProcessOffset();
   if (aEvent.mMessage == eDrop) {
     if (!QueryDropLinksForVerification()) {
       return;
     }
   }
   DebugOnly<bool> ret =
-    PBrowserParent::SendRealDragEvent(aEvent, aDragAction, aDropEffect);
+    PBrowserParent::SendRealDragEvent(aEvent, aDragAction, aDropEffect,
+                                      aPrincipalURISpec);
   NS_WARNING_ASSERTION(ret, "PBrowserParent::SendRealDragEvent() failed");
   MOZ_ASSERT(!ret || aEvent.HasBeenPostedToRemoteProcess());
 }
 
 LayoutDevicePoint
 TabParent::AdjustTapToChildWidget(const LayoutDevicePoint& aPoint)
 {
   return aPoint + LayoutDevicePoint(GetChildProcessOffset());
@@ -3340,17 +3342,18 @@ TabParent::RecvAsyncAuthPrompt(const nsC
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 TabParent::RecvInvokeDragSession(nsTArray<IPCDataTransfer>&& aTransfers,
                                  const uint32_t& aAction,
                                  const OptionalShmem& aVisualDnDData,
                                  const uint32_t& aStride, const uint8_t& aFormat,
-                                 const LayoutDeviceIntRect& aDragRect)
+                                 const LayoutDeviceIntRect& aDragRect,
+                                 const nsCString& aPrincipalURISpec)
 {
   mInitialDataTransferItems.Clear();
   nsIPresShell* shell = mFrameElement->OwnerDoc()->GetShell();
   if (!shell) {
     if (Manager()->IsContentParent()) {
       Unused << Manager()->AsContentParent()->SendEndDragSession(true, true,
                                                                  LayoutDeviceIntPoint(),
                                                                  0);
@@ -3382,29 +3385,44 @@ TabParent::RecvInvokeDragSession(nsTArra
         gfx::CreateDataSourceSurfaceFromData(gfx::IntSize(aDragRect.width, aDragRect.height),
                                              static_cast<gfx::SurfaceFormat>(aFormat),
                                              aVisualDnDData.get_Shmem().get<uint8_t>(),
                                              aStride);
   }
 
   mDragValid = true;
   mDragRect = aDragRect;
+  mDragPrincipalURISpec = aPrincipalURISpec;
 
   esm->BeginTrackingRemoteDragGesture(mFrameElement);
 
   if (aVisualDnDData.type() == OptionalShmem::TShmem) {
     Unused << DeallocShmem(aVisualDnDData);
   }
 
   return IPC_OK();
 }
 
 void
-TabParent::AddInitialDnDDataTo(DataTransfer* aDataTransfer)
+TabParent::AddInitialDnDDataTo(DataTransfer* aDataTransfer,
+                               nsACString& aPrincipalURISpec)
 {
+  aPrincipalURISpec.Assign(mDragPrincipalURISpec);
+
+  nsCOMPtr<nsIPrincipal> principal;
+  if (!mDragPrincipalURISpec.IsEmpty()) {
+    // If principal is given, try using it first.
+    principal = BasePrincipal::CreateCodebasePrincipal(mDragPrincipalURISpec);
+  }
+  if (!principal) {
+    // Fallback to system principal, to handle like the data is from browser
+    // chrome or OS.
+    principal = nsContentUtils::GetSystemPrincipal();
+  }
+
   for (uint32_t i = 0; i < mInitialDataTransferItems.Length(); ++i) {
     nsTArray<IPCDataTransferItem>& itemArray = mInitialDataTransferItems[i];
     for (auto& item : itemArray) {
       RefPtr<nsVariantCC> variant = new nsVariantCC();
       // Special case kFilePromiseMime so that we get the right
       // nsIFlavorDataProvider for it.
       if (item.flavor().EqualsLiteral(kFilePromiseMime)) {
         RefPtr<nsISupports> flavorDataProvider =
@@ -3430,29 +3448,27 @@ TabParent::AddInitialDnDDataTo(DataTrans
         } else {
           Shmem data = item.data().get_Shmem();
           variant->SetAsACString(nsDependentCString(data.get<char>(), data.Size<char>()));
         }
 
         mozilla::Unused << DeallocShmem(item.data().get_Shmem());
       }
 
-      // Using system principal here, since once the data is on parent process
-      // side, it can be handled as being from browser chrome or OS.
-
       // We set aHidden to false, as we don't need to worry about hiding data
       // from content in the parent process where there is no content.
       // XXX: Nested Content Processes may change this
       aDataTransfer->SetDataWithPrincipalFromOtherProcess(NS_ConvertUTF8toUTF16(item.flavor()),
                                                           variant, i,
-                                                          nsContentUtils::GetSystemPrincipal(),
+                                                          principal,
                                                           /* aHidden = */ false);
     }
   }
   mInitialDataTransferItems.Clear();
+  mDragPrincipalURISpec.Truncate(0);
 }
 
 bool
 TabParent::TakeDragVisualization(RefPtr<mozilla::gfx::SourceSurface>& aSurface,
                                  LayoutDeviceIntRect* aDragRect)
 {
   if (!mDragValid)
     return false;
--- a/dom/ipc/TabParent.h
+++ b/dom/ipc/TabParent.h
@@ -437,17 +437,18 @@ public:
    * The following Send*Event() marks aEvent as posted to remote process if
    * it succeeded.  So, you can check the result with
    * aEvent.HasBeenPostedToRemoteProcess().
    */
   void SendRealMouseEvent(WidgetMouseEvent& aEvent);
 
   void SendRealDragEvent(WidgetDragEvent& aEvent,
                          uint32_t aDragAction,
-                         uint32_t aDropEffect);
+                         uint32_t aDropEffect,
+                         const nsCString& aPrincipalURISpec);
 
   void SendMouseWheelEvent(WidgetWheelEvent& aEvent);
 
   void SendRealKeyEvent(WidgetKeyboardEvent& aEvent);
 
   void SendRealTouchEvent(WidgetTouchEvent& aEvent);
 
   void SendPluginEvent(WidgetPluginEvent& aEvent);
@@ -580,19 +581,21 @@ public:
 
   void LayerTreeUpdate(uint64_t aEpoch, bool aActive);
 
   virtual mozilla::ipc::IPCResult
   RecvInvokeDragSession(nsTArray<IPCDataTransfer>&& aTransfers,
                         const uint32_t& aAction,
                         const OptionalShmem& aVisualDnDData,
                         const uint32_t& aStride, const uint8_t& aFormat,
-                        const LayoutDeviceIntRect& aDragRect) override;
+                        const LayoutDeviceIntRect& aDragRect,
+                        const nsCString& aPrincipalURISpec) override;
 
-  void AddInitialDnDDataTo(DataTransfer* aDataTransfer);
+  void AddInitialDnDDataTo(DataTransfer* aDataTransfer,
+                           nsACString& aPrincipalURISpec);
 
   bool TakeDragVisualization(RefPtr<mozilla::gfx::SourceSurface>& aSurface,
                              LayoutDeviceIntRect* aDragRect);
 
   layout::RenderFrameParent* GetRenderFrame();
 
   bool SetRenderFrame(PRenderFrameParent* aRFParent);
   bool GetRenderFrameInfo(TextureFactoryIdentifier* aTextureFactoryIdentifier,
@@ -689,16 +692,17 @@ private:
 
   uint32_t mChromeFlags;
 
   nsTArray<nsTArray<IPCDataTransferItem>> mInitialDataTransferItems;
 
   RefPtr<gfx::DataSourceSurface> mDnDVisualization;
   bool mDragValid;
   LayoutDeviceIntRect mDragRect;
+  nsCString mDragPrincipalURISpec;
 
   // When true, the TabParent is initialized without child side's request.
   // When false, the TabParent is initialized by window.open() from child side.
   bool mInitedByParent;
 
   nsCOMPtr<nsILoadContext> mLoadContext;
 
   // We keep a strong reference to the frameloader after we've sent the
--- a/dom/webidl/DataTransfer.webidl
+++ b/dom/webidl/DataTransfer.webidl
@@ -152,16 +152,24 @@ partial interface DataTransfer {
   /**
    * The node that the mouse was pressed over to begin the drag. For external
    * drags, or if the caller cannot access this node, this will be null.
    */
   [UseCounter]
   readonly attribute Node? mozSourceNode;
 
   /**
+   * The URI spec of the triggering principal.  This may be different than
+   * sourceNode's principal when sourceNode is xul:browser and the drag is
+   * triggered in a browsing context inside it.
+   */
+  [ChromeOnly]
+  readonly attribute DOMString mozTriggeringPrincipalURISpec;
+
+  /**
    * Copy the given DataTransfer for the given event. Used by testing code for
    * creating emulated Drag and Drop events in the UI.
    *
    * NOTE: Don't expose a DataTransfer produced with this method to the web or
    * use this for non-testing purposes. It can easily be used to get the
    * DataTransfer into an invalid state, and is an unstable implementation
    * detail of EventUtils.synthesizeDrag.
    */
--- a/widget/gtk/nsDragService.cpp
+++ b/widget/gtk/nsDragService.cpp
@@ -300,32 +300,34 @@ GetGtkWindow(nsIDOMDocument *aDocument)
 
     return GTK_WINDOW(toplevel);
 }
 
 // nsIDragService
 
 NS_IMETHODIMP
 nsDragService::InvokeDragSession(nsIDOMNode *aDOMNode,
+                                 const nsACString& aPrincipalURISpec,
                                  nsIArray * aArrayTransferables,
                                  nsIScriptableRegion * aRegion,
                                  uint32_t aActionType,
                                  nsContentPolicyType aContentPolicyType =
                                    nsIContentPolicy::TYPE_OTHER)
 {
     MOZ_LOG(sDragLm, LogLevel::Debug, ("nsDragService::InvokeDragSession"));
 
     // If the previous source drag has not yet completed, signal handlers need
     // to be removed from sGrabWidget and dragend needs to be dispatched to
     // the source node, but we can't call EndDragSession yet because we don't
     // know whether or not the drag succeeded.
     if (mSourceNode)
         return NS_ERROR_NOT_AVAILABLE;
 
-    return nsBaseDragService::InvokeDragSession(aDOMNode, aArrayTransferables,
+    return nsBaseDragService::InvokeDragSession(aDOMNode, aPrincipalURISpec,
+                                                aArrayTransferables,
                                                 aRegion, aActionType,
                                                 aContentPolicyType);
 }
 
 // nsBaseDragService
 nsresult
 nsDragService::InvokeDragSessionImpl(nsIArray* aArrayTransferables,
                                      nsIScriptableRegion* aRegion,
--- a/widget/gtk/nsDragService.h
+++ b/widget/gtk/nsDragService.h
@@ -59,16 +59,17 @@ public:
     NS_DECL_NSIOBSERVER
 
     // nsBaseDragService
     virtual nsresult InvokeDragSessionImpl(nsIArray* anArrayTransferables,
                                            nsIScriptableRegion* aRegion,
                                            uint32_t aActionType) override;
     // nsIDragService
     NS_IMETHOD InvokeDragSession (nsIDOMNode *aDOMNode,
+                                  const nsACString& aPrincipalURISpec,
                                   nsIArray * anArrayTransferables,
                                   nsIScriptableRegion * aRegion,
                                   uint32_t aActionType,
                                   nsContentPolicyType aContentPolicyType) override;
     NS_IMETHOD StartDragSession() override;
     NS_IMETHOD EndDragSession(bool aDoneDrag, uint32_t aKeyModifiers) override;
 
     // nsIDragSession
--- a/widget/nsBaseDragService.cpp
+++ b/widget/nsBaseDragService.cpp
@@ -164,16 +164,29 @@ NS_IMETHODIMP
 nsBaseDragService::GetSourceNode(nsIDOMNode** aSourceNode)
 {
   *aSourceNode = mSourceNode.get();
   NS_IF_ADDREF(*aSourceNode);
 
   return NS_OK;
 }
 
+NS_IMETHODIMP
+nsBaseDragService::GetTriggeringPrincipalURISpec(nsACString& aPrincipalURISpec)
+{
+  aPrincipalURISpec = mTriggeringPrincipalURISpec;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsBaseDragService::SetTriggeringPrincipalURISpec(const nsACString& aPrincipalURISpec)
+{
+  mTriggeringPrincipalURISpec = aPrincipalURISpec;
+  return NS_OK;
+}
 
 //-------------------------------------------------------------------------
 
 NS_IMETHODIMP
 nsBaseDragService::GetData(nsITransferable * aTransferable,
                            uint32_t aItemIndex)
 {
   return NS_ERROR_FAILURE;
@@ -200,53 +213,57 @@ nsBaseDragService::SetDataTransfer(nsIDO
 {
   mDataTransfer = aDataTransfer;
   return NS_OK;
 }
 
 //-------------------------------------------------------------------------
 NS_IMETHODIMP
 nsBaseDragService::InvokeDragSession(nsIDOMNode *aDOMNode,
+                                     const nsACString& aPrincipalURISpec,
                                      nsIArray* aTransferableArray,
                                      nsIScriptableRegion* aDragRgn,
                                      uint32_t aActionType,
                                      nsContentPolicyType aContentPolicyType =
                                        nsIContentPolicy::TYPE_OTHER)
 {
   AUTO_PROFILER_LABEL("nsBaseDragService::InvokeDragSession", OTHER);
 
   NS_ENSURE_TRUE(aDOMNode, NS_ERROR_INVALID_ARG);
   NS_ENSURE_TRUE(mSuppressLevel == 0, NS_ERROR_FAILURE);
 
   // stash the document of the dom node
   nsCOMPtr<nsINode> node = do_QueryInterface(aDOMNode);
   mSourceDocument = do_QueryInterface(node->OwnerDoc());
+  mTriggeringPrincipalURISpec.Assign(aPrincipalURISpec);
   mSourceNode = aDOMNode;
   mContentPolicyType = aContentPolicyType;
   mEndDragPoint = LayoutDeviceIntPoint(0, 0);
 
   // When the mouse goes down, the selection code starts a mouse
   // capture. However, this gets in the way of determining drag
   // feedback for things like trees because the event coordinates
   // are in the wrong coord system, so turn off mouse capture.
   nsIPresShell::ClearMouseCapture(nullptr);
 
   nsresult rv = InvokeDragSessionImpl(aTransferableArray,
                                       aDragRgn, aActionType);
 
   if (NS_FAILED(rv)) {
     mSourceNode = nullptr;
+    mTriggeringPrincipalURISpec.Truncate(0);
     mSourceDocument = nullptr;
   }
 
   return rv;
 }
 
 NS_IMETHODIMP
 nsBaseDragService::InvokeDragSessionWithImage(nsIDOMNode* aDOMNode,
+                                              const nsACString& aPrincipalURISpec,
                                               nsIArray* aTransferableArray,
                                               nsIScriptableRegion* aRegion,
                                               uint32_t aActionType,
                                               nsIDOMNode* aImage,
                                               int32_t aImageX, int32_t aImageY,
                                               nsIDOMDragEvent* aDragEvent,
                                               nsIDOMDataTransfer* aDataTransfer)
 {
@@ -260,31 +277,33 @@ nsBaseDragService::InvokeDragSessionWith
   mDragPopup = nullptr;
   mImage = aImage;
   mImageOffset = CSSIntPoint(aImageX, aImageY);
 
   aDragEvent->GetScreenX(&mScreenPosition.x);
   aDragEvent->GetScreenY(&mScreenPosition.y);
   aDragEvent->GetMozInputSource(&mInputSource);
 
-  nsresult rv = InvokeDragSession(aDOMNode, aTransferableArray,
+  nsresult rv = InvokeDragSession(aDOMNode, aPrincipalURISpec,
+                                  aTransferableArray,
                                   aRegion, aActionType,
                                   nsIContentPolicy::TYPE_INTERNAL_IMAGE);
 
   if (NS_FAILED(rv)) {
     mImage = nullptr;
     mHasImage = false;
     mDataTransfer = nullptr;
   }
 
   return rv;
 }
 
 NS_IMETHODIMP
 nsBaseDragService::InvokeDragSessionWithSelection(nsISelection* aSelection,
+                                                  const nsACString& aPrincipalURISpec,
                                                   nsIArray* aTransferableArray,
                                                   uint32_t aActionType,
                                                   nsIDOMDragEvent* aDragEvent,
                                                   nsIDOMDataTransfer* aDataTransfer)
 {
   NS_ENSURE_TRUE(aSelection, NS_ERROR_NULL_POINTER);
   NS_ENSURE_TRUE(aDragEvent, NS_ERROR_NULL_POINTER);
   NS_ENSURE_TRUE(mSuppressLevel == 0, NS_ERROR_FAILURE);
@@ -301,17 +320,18 @@ nsBaseDragService::InvokeDragSessionWith
   aDragEvent->GetMozInputSource(&mInputSource);
 
   // just get the focused node from the selection
   // XXXndeakin this should actually be the deepest node that contains both
   // endpoints of the selection
   nsCOMPtr<nsIDOMNode> node;
   aSelection->GetFocusNode(getter_AddRefs(node));
 
-  nsresult rv = InvokeDragSession(node, aTransferableArray,
+  nsresult rv = InvokeDragSession(node, aPrincipalURISpec,
+                                  aTransferableArray,
                                   nullptr, aActionType,
                                   nsIContentPolicy::TYPE_OTHER);
 
   if (NS_FAILED(rv)) {
     mHasImage = false;
     mSelection = nullptr;
     mDataTransfer = nullptr;
   }
@@ -417,16 +437,17 @@ nsBaseDragService::EndDragSession(bool a
   }
 
   mDoingDrag = false;
   mCanDrop = false;
 
   // release the source we've been holding on to.
   mSourceDocument = nullptr;
   mSourceNode = nullptr;
+  mTriggeringPrincipalURISpec.Truncate(0);
   mSelection = nullptr;
   mDataTransfer = nullptr;
   mHasImage = false;
   mUserCancelled = false;
   mDragPopup = nullptr;
   mImage = nullptr;
   mImageOffset = CSSIntPoint();
   mScreenPosition = CSSIntPoint();
--- a/widget/nsBaseDragService.h
+++ b/widget/nsBaseDragService.h
@@ -9,16 +9,17 @@
 #include "nsIDragService.h"
 #include "nsIDragSession.h"
 #include "nsITransferable.h"
 #include "nsIDOMDocument.h"
 #include "nsIDOMDataTransfer.h"
 #include "nsCOMPtr.h"
 #include "nsRect.h"
 #include "nsPoint.h"
+#include "nsString.h"
 #include "mozilla/RefPtr.h"
 #include "mozilla/dom/ContentParent.h"
 #include "mozilla/dom/HTMLCanvasElement.h"
 #include "nsTArray.h"
 #include "Units.h"
 
 // translucency level for drag images
 #define DRAG_TRANSLUCENCY 0.65
@@ -154,16 +155,17 @@ protected:
 
   bool mDragEventDispatchedToChildProcess;
 
   uint32_t mDragAction;
   uint32_t mDragActionFromChildProcess;
 
   nsSize mTargetSize;
   nsCOMPtr<nsIDOMNode> mSourceNode;
+  nsCString mTriggeringPrincipalURISpec;
   nsCOMPtr<nsIDOMDocument> mSourceDocument;       // the document at the drag source. will be null
                                                   //  if it came from outside the app.
   nsContentPolicyType mContentPolicyType;         // the contentpolicy type passed to the channel
                                                   // when initiating the drag session
   nsCOMPtr<nsIDOMDataTransfer> mDataTransfer;
 
   // used to determine the image to appear on the cursor while dragging
   nsCOMPtr<nsIDOMNode> mImage;
--- a/widget/nsDragServiceProxy.cpp
+++ b/widget/nsDragServiceProxy.cpp
@@ -24,32 +24,54 @@ NS_IMPL_ISUPPORTS_INHERITED0(nsDragServi
 nsDragServiceProxy::nsDragServiceProxy()
 {
 }
 
 nsDragServiceProxy::~nsDragServiceProxy()
 {
 }
 
+static void
+GetPrincipalURIFromNode(nsCOMPtr<nsIDOMNode>& sourceNode,
+                        nsCString& aPrincipalURISpec)
+{
+  nsCOMPtr<nsINode> node = do_QueryInterface(sourceNode);
+  if (!node) {
+    return;
+  }
+
+  nsCOMPtr<nsIPrincipal> principal = node->NodePrincipal();
+  nsCOMPtr<nsIURI> principalURI;
+  nsresult rv = principal->GetURI(getter_AddRefs(principalURI));
+  if (NS_FAILED(rv)) {
+    return;
+  }
+
+  principalURI->GetSpec(aPrincipalURISpec);
+}
+
 nsresult
 nsDragServiceProxy::InvokeDragSessionImpl(nsIArray* aArrayTransferables,
                                           nsIScriptableRegion* aRegion,
                                           uint32_t aActionType)
 {
   nsCOMPtr<nsIDocument> doc = do_QueryInterface(mSourceDocument);
   NS_ENSURE_STATE(doc->GetDocShell());
   TabChild* child = TabChild::GetFrom(doc->GetDocShell());
   NS_ENSURE_STATE(child);
   nsTArray<mozilla::dom::IPCDataTransfer> dataTransfers;
   nsContentUtils::TransferablesToIPCTransferables(aArrayTransferables,
                                                   dataTransfers,
                                                   false,
                                                   child->Manager(),
                                                   nullptr);
 
+  nsCString principalURISpec;
+  GetPrincipalURIFromNode(mSourceNode, principalURISpec);
+
   LayoutDeviceIntRect dragRect;
   if (mHasImage || mSelection) {
     nsPresContext* pc;
     RefPtr<mozilla::gfx::SourceSurface> surface;
     DrawDrag(mSourceNode, aRegion, mScreenPosition, &dragRect, &surface, &pc);
 
     if (surface) {
       RefPtr<mozilla::gfx::DataSourceSurface> dataSurface =
@@ -71,20 +93,21 @@ nsDragServiceProxy::InvokeDragSessionImp
         if (!surfaceData.IsReadable() || !surfaceData.get<char>()) {
           NS_WARNING("Failed to create shared memory for drag session.");
           return NS_ERROR_FAILURE;
         }
 
         mozilla::Unused <<
           child->SendInvokeDragSession(dataTransfers, aActionType, surfaceData,
                                        stride, static_cast<uint8_t>(dataSurface->GetFormat()),
-                                       dragRect);
+                                       dragRect, principalURISpec);
         StartDragSession();
         return NS_OK;
       }
     }
   }
 
   mozilla::Unused << child->SendInvokeDragSession(dataTransfers, aActionType,
-                                                  mozilla::void_t(), 0, 0, dragRect);
+                                                  mozilla::void_t(), 0, 0, dragRect,
+                                                  principalURISpec);
   StartDragSession();
   return NS_OK;
 }
--- a/widget/nsIDragService.idl
+++ b/widget/nsIDragService.idl
@@ -37,25 +37,28 @@ interface nsIDragService : nsISupports
   const long DRAGDROP_ACTION_LINK = 4;
   const long DRAGDROP_ACTION_UNINITIALIZED = 64;
 
   /**
     * Starts a modal drag session with an array of transaferables.
     *
     * Note: This method is deprecated for non-native code.
     *
+    * @param  aPrincipalURISpec - the URI of the triggering principal of the
+    *            drag, or an empty string if it's from browser chrome or OS
     * @param  aTransferables - an array of transferables to be dragged
     * @param  aRegion - a region containing rectangles for cursor feedback, 
     *            in window coordinates.
     * @param  aActionType - specified which of copy/move/link are allowed
     * @param  aContentPolicyType - the contentPolicyType that will be
     *           passed to the loadInfo when creating a new channel
     *           (defaults to TYPE_OTHER)
     */
   void invokeDragSession (in nsIDOMNode aDOMNode,
+                          in AUTF8String aPrincipalURISpec,
                           in nsIArray aTransferables, 
                           in nsIScriptableRegion aRegion,
                           in unsigned long aActionType,
                           [optional] in nsContentPolicyType aContentPolicyType);
 
   /**
    * Starts a modal drag session using an image. The first four arguments are
    * the same as invokeDragSession.
@@ -79,16 +82,17 @@ interface nsIDragService : nsISupports
    * rendered at its real size. For other types of elements, the element is
    * rendered into an offscreen buffer in the same manner as it is currently
    * displayed. The document selection is hidden while drawing.
    *
    * The aDragEvent must be supplied as the current screen coordinates of the
    * event are needed to calculate the image location.
    */
   void invokeDragSessionWithImage(in nsIDOMNode aDOMNode,
+                                  in AUTF8String aPrincipalURISpec,
                                   in nsIArray aTransferableArray,
                                   in nsIScriptableRegion aRegion,
                                   in unsigned long aActionType,
                                   in nsIDOMNode aImage,
                                   in long aImageX,
                                   in long aImageY,
                                   in nsIDOMDragEvent aDragEvent,
                                   in nsIDOMDataTransfer aDataTransfer);
@@ -96,16 +100,17 @@ interface nsIDragService : nsISupports
   /**
    * Start a modal drag session using the selection as the drag image.
    * The aDragEvent must be supplied as the current screen coordinates of the
    * event are needed to calculate the image location.
    *
    * Note: This method is deprecated for non-native code.
    */
   void invokeDragSessionWithSelection(in nsISelection aSelection,
+                                      in AUTF8String aPrincipalURISpec,
                                       in nsIArray aTransferableArray,
                                       in unsigned long aActionType,
                                       in nsIDOMDragEvent aDragEvent,
                                       in nsIDOMDataTransfer aDataTransfer);
 
   /**
     * Returns the current Drag Session  
     */
--- a/widget/nsIDragSession.idl
+++ b/widget/nsIDragSession.idl
@@ -58,16 +58,23 @@ interface nsIDragSession : nsISupports
 
   /**
     * The dom node that was originally dragged to start the session, which will be null if the
     * drag originated outside the application.
     */
   readonly attribute nsIDOMNode sourceNode;
 
   /**
+   * The URI spec of the triggering principal.  This may be different than
+   * sourceNode's principal when sourceNode is xul:browser and the drag is
+   * triggered in a browsing context inside it.
+   */
+  attribute AUTF8String triggeringPrincipalURISpec;
+
+  /**
    * The data transfer object for the current drag.
    */
   attribute nsIDOMDataTransfer dataTransfer;
 
   /**
     * Get data from a Drag&Drop. Can be called while the drag is in process
     * or after the drop has completed.  
     *