|
1 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
2 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
4 |
|
5 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); |
|
6 |
|
7 const Cc = Components.classes; |
|
8 const Ci = Components.interfaces; |
|
9 |
|
10 // This component is used for handling dragover and drop of urls. |
|
11 // |
|
12 // It checks to see whether a drop of a url is allowed. For instance, a url |
|
13 // cannot be dropped if it is not a valid uri or the source of the drag cannot |
|
14 // access the uri. This prevents, for example, a source document from tricking |
|
15 // the user into dragging a chrome url. |
|
16 |
|
17 function ContentAreaDropListener() { }; |
|
18 |
|
19 ContentAreaDropListener.prototype = |
|
20 { |
|
21 classID: Components.ID("{1f34bc80-1bc7-11d6-a384-d705dd0746fc}"), |
|
22 QueryInterface: XPCOMUtils.generateQI([Ci.nsIDroppedLinkHandler, Ci.nsISupports]), |
|
23 |
|
24 _getDropURL : function (dt) |
|
25 { |
|
26 let types = dt.types; |
|
27 for (let t = 0; t < types.length; t++) { |
|
28 let type = types[t]; |
|
29 switch (type) { |
|
30 case "text/uri-list": |
|
31 var url = dt.getData("URL").replace(/^\s+|\s+$/g, ""); |
|
32 return [url, url]; |
|
33 case "text/plain": |
|
34 case "text/x-moz-text-internal": |
|
35 var url = dt.getData(type).replace(/^\s+|\s+$/g, ""); |
|
36 return [url, url]; |
|
37 case "text/x-moz-url": |
|
38 return dt.getData(type).split("\n"); |
|
39 } |
|
40 } |
|
41 |
|
42 // For shortcuts, we want to check for the file type last, so that the |
|
43 // url pointed to in one of the url types is found first before the file |
|
44 // type, which points to the actual file. |
|
45 let file = dt.mozGetDataAt("application/x-moz-file", 0); |
|
46 if (file instanceof Ci.nsIFile) { |
|
47 let ioService = Cc["@mozilla.org/network/io-service;1"]. |
|
48 getService(Ci.nsIIOService); |
|
49 let fileHandler = ioService.getProtocolHandler("file") |
|
50 .QueryInterface(Ci.nsIFileProtocolHandler); |
|
51 return [fileHandler.getURLSpecFromFile(file), file.leafName]; |
|
52 } |
|
53 |
|
54 return [ ]; |
|
55 }, |
|
56 |
|
57 _validateURI: function(dataTransfer, uriString, disallowInherit) |
|
58 { |
|
59 if (!uriString) |
|
60 return ""; |
|
61 |
|
62 // Strip leading and trailing whitespace, then try to create a |
|
63 // URI from the dropped string. If that succeeds, we're |
|
64 // dropping a URI and we need to do a security check to make |
|
65 // sure the source document can load the dropped URI. |
|
66 uriString = uriString.replace(/^\s*|\s*$/g, ''); |
|
67 |
|
68 let uri; |
|
69 let ioService = Cc["@mozilla.org/network/io-service;1"] |
|
70 .getService(Components.interfaces.nsIIOService); |
|
71 try { |
|
72 // Check that the uri is valid first and return an empty string if not. |
|
73 // It may just be plain text and should be ignored here |
|
74 uri = ioService.newURI(uriString, null, null); |
|
75 } catch (ex) { } |
|
76 if (!uri) |
|
77 return uriString; |
|
78 |
|
79 // uriString is a valid URI, so do the security check. |
|
80 let secMan = Cc["@mozilla.org/scriptsecuritymanager;1"]. |
|
81 getService(Ci.nsIScriptSecurityManager); |
|
82 let sourceNode = dataTransfer.mozSourceNode; |
|
83 let flags = secMan.STANDARD; |
|
84 if (disallowInherit) |
|
85 flags |= secMan.DISALLOW_INHERIT_PRINCIPAL; |
|
86 |
|
87 // Use file:/// as the default uri so that drops of file URIs are always allowed |
|
88 let principal = sourceNode ? sourceNode.nodePrincipal |
|
89 : secMan.getSimpleCodebasePrincipal(ioService.newURI("file:///", null, null)); |
|
90 |
|
91 secMan.checkLoadURIStrWithPrincipal(principal, uriString, flags); |
|
92 |
|
93 return uriString; |
|
94 }, |
|
95 |
|
96 canDropLink: function(aEvent, aAllowSameDocument) |
|
97 { |
|
98 if (this._eventTargetIsDisabled(aEvent)) |
|
99 return false; |
|
100 |
|
101 let dataTransfer = aEvent.dataTransfer; |
|
102 let types = dataTransfer.types; |
|
103 if (!types.contains("application/x-moz-file") && |
|
104 !types.contains("text/x-moz-url") && |
|
105 !types.contains("text/uri-list") && |
|
106 !types.contains("text/x-moz-text-internal") && |
|
107 !types.contains("text/plain")) |
|
108 return false; |
|
109 |
|
110 if (aAllowSameDocument) |
|
111 return true; |
|
112 |
|
113 let sourceNode = dataTransfer.mozSourceNode; |
|
114 if (!sourceNode) |
|
115 return true; |
|
116 |
|
117 // don't allow a drop of a node from the same document onto this one |
|
118 let sourceDocument = sourceNode.ownerDocument; |
|
119 let eventDocument = aEvent.originalTarget.ownerDocument; |
|
120 if (sourceDocument == eventDocument) |
|
121 return false; |
|
122 |
|
123 // also check for nodes in other child or sibling frames by checking |
|
124 // if both have the same top window. |
|
125 if (sourceDocument && eventDocument) { |
|
126 let sourceRoot = sourceDocument.defaultView.top; |
|
127 if (sourceRoot && sourceRoot == eventDocument.defaultView.top) |
|
128 return false; |
|
129 } |
|
130 |
|
131 return true; |
|
132 }, |
|
133 |
|
134 dropLink: function(aEvent, aName, aDisallowInherit) |
|
135 { |
|
136 aName.value = ""; |
|
137 if (this._eventTargetIsDisabled(aEvent)) |
|
138 return ""; |
|
139 |
|
140 let dataTransfer = aEvent.dataTransfer; |
|
141 let [url, name] = this._getDropURL(dataTransfer); |
|
142 |
|
143 try { |
|
144 url = this._validateURI(dataTransfer, url, aDisallowInherit); |
|
145 } catch (ex) { |
|
146 aEvent.stopPropagation(); |
|
147 aEvent.preventDefault(); |
|
148 throw ex; |
|
149 } |
|
150 |
|
151 if (name) |
|
152 aName.value = name; |
|
153 |
|
154 return url; |
|
155 }, |
|
156 |
|
157 _eventTargetIsDisabled: function(aEvent) |
|
158 { |
|
159 let ownerDoc = aEvent.originalTarget.ownerDocument; |
|
160 if (!ownerDoc || !ownerDoc.defaultView) |
|
161 return false; |
|
162 |
|
163 return ownerDoc.defaultView |
|
164 .QueryInterface(Components.interfaces.nsIInterfaceRequestor) |
|
165 .getInterface(Components.interfaces.nsIDOMWindowUtils) |
|
166 .isNodeDisabledForEvents(aEvent.originalTarget); |
|
167 } |
|
168 }; |
|
169 |
|
170 var components = [ContentAreaDropListener]; |
|
171 this.NSGetFactory = XPCOMUtils.generateNSGetFactory(components); |