Sat, 03 Jan 2015 20:18:00 +0100
Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.
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/. */
5 "use strict";
7 module.metadata = {
8 "stability": "stable",
9 "engines": {
10 // TODO Fennec Support 789757
11 "Firefox": "*"
12 }
13 };
15 const { Cc, Ci } = require("chrome");
16 const { DataURL } = require("./url");
17 const errors = require("./deprecated/errors");
18 const apiUtils = require("./deprecated/api-utils");
19 /*
20 While these data flavors resemble Internet media types, they do
21 no directly map to them.
22 */
23 const kAllowableFlavors = [
24 "text/unicode",
25 "text/html",
26 "image/png"
27 /* CURRENTLY UNSUPPORTED FLAVORS
28 "text/plain",
29 "image/jpg",
30 "image/jpeg",
31 "image/gif",
32 "text/x-moz-text-internal",
33 "AOLMAIL",
34 "application/x-moz-file",
35 "text/x-moz-url",
36 "text/x-moz-url-data",
37 "text/x-moz-url-desc",
38 "text/x-moz-url-priv",
39 "application/x-moz-nativeimage",
40 "application/x-moz-nativehtml",
41 "application/x-moz-file-promise-url",
42 "application/x-moz-file-promise-dest-filename",
43 "application/x-moz-file-promise",
44 "application/x-moz-file-promise-dir"
45 */
46 ];
48 /*
49 Aliases for common flavors. Not all flavors will
50 get an alias. New aliases must be approved by a
51 Jetpack API druid.
52 */
53 const kFlavorMap = [
54 { short: "text", long: "text/unicode" },
55 { short: "html", long: "text/html" },
56 { short: "image", long: "image/png" }
57 ];
59 let clipboardService = Cc["@mozilla.org/widget/clipboard;1"].
60 getService(Ci.nsIClipboard);
62 let clipboardHelper = Cc["@mozilla.org/widget/clipboardhelper;1"].
63 getService(Ci.nsIClipboardHelper);
65 let imageTools = Cc["@mozilla.org/image/tools;1"].
66 getService(Ci.imgITools);
68 exports.set = function(aData, aDataType) {
70 let options = {
71 data: aData,
72 datatype: aDataType || "text"
73 };
75 // If `aDataType` is not given or if it's "image", the data is parsed as
76 // data URL to detect a better datatype
77 if (aData && (!aDataType || aDataType === "image")) {
78 try {
79 let dataURL = new DataURL(aData);
81 options.datatype = dataURL.mimeType;
82 options.data = dataURL.data;
83 }
84 catch (e) {
85 // Ignore invalid URIs
86 if (e.name !== "URIError") {
87 throw e;
88 }
89 }
90 }
92 options = apiUtils.validateOptions(options, {
93 data: {
94 is: ["string"]
95 },
96 datatype: {
97 is: ["string"]
98 }
99 });
101 let flavor = fromJetpackFlavor(options.datatype);
103 if (!flavor)
104 throw new Error("Invalid flavor for " + options.datatype);
106 // Additional checks for using the simple case
107 if (flavor == "text/unicode") {
108 clipboardHelper.copyString(options.data);
109 return true;
110 }
112 // Below are the more complex cases where we actually have to work with a
113 // nsITransferable object
114 var xferable = Cc["@mozilla.org/widget/transferable;1"].
115 createInstance(Ci.nsITransferable);
116 if (!xferable)
117 throw new Error("Couldn't set the clipboard due to an internal error " +
118 "(couldn't create a Transferable object).");
119 // Bug 769440: Starting with FF16, transferable have to be inited
120 if ("init" in xferable)
121 xferable.init(null);
123 switch (flavor) {
124 case "text/html":
125 // add text/html flavor
126 let (str = Cc["@mozilla.org/supports-string;1"].
127 createInstance(Ci.nsISupportsString))
128 {
129 str.data = options.data;
130 xferable.addDataFlavor(flavor);
131 xferable.setTransferData(flavor, str, str.data.length * 2);
132 }
134 // add a text/unicode flavor (html converted to plain text)
135 let (str = Cc["@mozilla.org/supports-string;1"].
136 createInstance(Ci.nsISupportsString),
137 converter = Cc["@mozilla.org/feed-textconstruct;1"].
138 createInstance(Ci.nsIFeedTextConstruct))
139 {
140 converter.type = "html";
141 converter.text = options.data;
142 str.data = converter.plainText();
143 xferable.addDataFlavor("text/unicode");
144 xferable.setTransferData("text/unicode", str, str.data.length * 2);
145 }
146 break;
148 // Set images to the clipboard is not straightforward, to have an idea how
149 // it works on platform side, see:
150 // http://mxr.mozilla.org/mozilla-central/source/content/base/src/nsCopySupport.cpp?rev=7857c5bff017#530
151 case "image/png":
152 let image = options.data;
154 let container = {};
156 try {
157 let input = Cc["@mozilla.org/io/string-input-stream;1"].
158 createInstance(Ci.nsIStringInputStream);
160 input.setData(image, image.length);
162 imageTools.decodeImageData(input, flavor, container);
163 }
164 catch (e) {
165 throw new Error("Unable to decode data given in a valid image.");
166 }
168 // Store directly the input stream makes the cliboard's data available
169 // for Firefox but not to the others application or to the OS. Therefore,
170 // a `nsISupportsInterfacePointer` object that reference an `imgIContainer`
171 // with the image is needed.
172 var imgPtr = Cc["@mozilla.org/supports-interface-pointer;1"].
173 createInstance(Ci.nsISupportsInterfacePointer);
175 imgPtr.data = container.value;
177 xferable.addDataFlavor(flavor);
178 xferable.setTransferData(flavor, imgPtr, -1);
180 break;
181 default:
182 throw new Error("Unable to handle the flavor " + flavor + ".");
183 }
185 // TODO: Not sure if this will ever actually throw. -zpao
186 try {
187 clipboardService.setData(
188 xferable,
189 null,
190 clipboardService.kGlobalClipboard
191 );
192 } catch (e) {
193 throw new Error("Couldn't set clipboard data due to an internal error: " + e);
194 }
195 return true;
196 };
199 exports.get = function(aDataType) {
200 let options = {
201 datatype: aDataType
202 };
204 // Figure out the best data type for the clipboard's data, if omitted
205 if (!aDataType) {
206 if (~currentFlavors().indexOf("image"))
207 options.datatype = "image";
208 else
209 options.datatype = "text";
210 }
212 options = apiUtils.validateOptions(options, {
213 datatype: {
214 is: ["string"]
215 }
216 });
218 var xferable = Cc["@mozilla.org/widget/transferable;1"].
219 createInstance(Ci.nsITransferable);
220 if (!xferable)
221 throw new Error("Couldn't set the clipboard due to an internal error " +
222 "(couldn't create a Transferable object).");
223 // Bug 769440: Starting with FF16, transferable have to be inited
224 if ("init" in xferable)
225 xferable.init(null);
227 var flavor = fromJetpackFlavor(options.datatype);
229 // Ensure that the user hasn't requested a flavor that we don't support.
230 if (!flavor)
231 throw new Error("Getting the clipboard with the flavor '" + flavor +
232 "' is not supported.");
234 // TODO: Check for matching flavor first? Probably not worth it.
236 xferable.addDataFlavor(flavor);
237 // Get the data into our transferable.
238 clipboardService.getData(
239 xferable,
240 clipboardService.kGlobalClipboard
241 );
243 var data = {};
244 var dataLen = {};
245 try {
246 xferable.getTransferData(flavor, data, dataLen);
247 } catch (e) {
248 // Clipboard doesn't contain data in flavor, return null.
249 return null;
250 }
252 // There's no data available, return.
253 if (data.value === null)
254 return null;
256 // TODO: Add flavors here as we support more in kAllowableFlavors.
257 switch (flavor) {
258 case "text/unicode":
259 case "text/html":
260 data = data.value.QueryInterface(Ci.nsISupportsString).data;
261 break;
262 case "image/png":
263 let dataURL = new DataURL();
265 dataURL.mimeType = flavor;
266 dataURL.base64 = true;
268 let image = data.value;
270 // Due to the differences in how images could be stored in the clipboard
271 // the checks below are needed. The clipboard could already provide the
272 // image as byte streams, but also as pointer, or as image container.
273 // If it's not possible obtain a byte stream, the function returns `null`.
274 if (image instanceof Ci.nsISupportsInterfacePointer)
275 image = image.data;
277 if (image instanceof Ci.imgIContainer)
278 image = imageTools.encodeImage(image, flavor);
280 if (image instanceof Ci.nsIInputStream) {
281 let binaryStream = Cc["@mozilla.org/binaryinputstream;1"].
282 createInstance(Ci.nsIBinaryInputStream);
284 binaryStream.setInputStream(image);
286 dataURL.data = binaryStream.readBytes(binaryStream.available());
288 data = dataURL.toString();
289 }
290 else
291 data = null;
293 break;
294 default:
295 data = null;
296 }
298 return data;
299 };
301 function currentFlavors() {
302 // Loop over kAllowableFlavors, calling hasDataMatchingFlavors for each.
303 // This doesn't seem like the most efficient way, but we can't get
304 // confirmation for specific flavors any other way. This is supposed to be
305 // an inexpensive call, so performance shouldn't be impacted (much).
306 var currentFlavors = [];
307 for each (var flavor in kAllowableFlavors) {
308 var matches = clipboardService.hasDataMatchingFlavors(
309 [flavor],
310 1,
311 clipboardService.kGlobalClipboard
312 );
313 if (matches)
314 currentFlavors.push(toJetpackFlavor(flavor));
315 }
316 return currentFlavors;
317 };
319 Object.defineProperty(exports, "currentFlavors", { get : currentFlavors });
321 // SUPPORT FUNCTIONS ////////////////////////////////////////////////////////
323 function toJetpackFlavor(aFlavor) {
324 for each (let flavorMap in kFlavorMap)
325 if (flavorMap.long == aFlavor)
326 return flavorMap.short;
327 // Return null in the case where we don't match
328 return null;
329 }
331 function fromJetpackFlavor(aJetpackFlavor) {
332 // TODO: Handle proper flavors better
333 for each (let flavorMap in kFlavorMap)
334 if (flavorMap.short == aJetpackFlavor || flavorMap.long == aJetpackFlavor)
335 return flavorMap.long;
336 // Return null in the case where we don't match.
337 return null;
338 }