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 /**
2 * Handling native paths.
3 *
4 * This module contains a number of functions destined to simplify
5 * working with native paths through a cross-platform API. Functions
6 * of this module will only work with the following assumptions:
7 *
8 * - paths are valid;
9 * - paths are defined with one of the grammars that this module can
10 * parse (see later);
11 * - all path concatenations go through function |join|.
12 *
13 * Limitations of this implementation.
14 *
15 * Windows supports 6 distinct grammars for paths. For the moment, this
16 * implementation supports the following subset:
17 *
18 * - drivename:backslash-separated components
19 * - backslash-separated components
20 * - \\drivename\ followed by backslash-separated components
21 *
22 * Additionally, |normalize| can convert a path containing slash-
23 * separated components to a path containing backslash-separated
24 * components.
25 */
27 "use strict";
29 // Boilerplate used to be able to import this module both from the main
30 // thread and from worker threads.
31 if (typeof Components != "undefined") {
32 Components.utils.importGlobalProperties(["URL"]);
33 // Global definition of |exports|, to keep everybody happy.
34 // In non-main thread, |exports| is provided by the module
35 // loader.
36 this.exports = {};
37 } else if (typeof "module" == "undefined" || typeof "exports" == "undefined") {
38 throw new Error("Please load this module using require()");
39 }
41 let EXPORTED_SYMBOLS = [
42 "basename",
43 "dirname",
44 "join",
45 "normalize",
46 "split",
47 "winGetDrive",
48 "winIsAbsolute",
49 "toFileURI",
50 "fromFileURI",
51 ];
53 /**
54 * Return the final part of the path.
55 * The final part of the path is everything after the last "\\".
56 */
57 let basename = function(path) {
58 if (path.startsWith("\\\\")) {
59 // UNC-style path
60 let index = path.lastIndexOf("\\");
61 if (index != 1) {
62 return path.slice(index + 1);
63 }
64 return ""; // Degenerate case
65 }
66 return path.slice(Math.max(path.lastIndexOf("\\"),
67 path.lastIndexOf(":")) + 1);
68 };
69 exports.basename = basename;
71 /**
72 * Return the directory part of the path.
73 *
74 * If the path contains no directory, return the drive letter,
75 * or "." if the path contains no drive letter or if option
76 * |winNoDrive| is set.
77 *
78 * Otherwise, return everything before the last backslash,
79 * including the drive/server name.
80 *
81 *
82 * @param {string} path The path.
83 * @param {*=} options Platform-specific options controlling the behavior
84 * of this function. This implementation supports the following options:
85 * - |winNoDrive| If |true|, also remove the letter from the path name.
86 */
87 let dirname = function(path, options) {
88 let noDrive = (options && options.winNoDrive);
90 // Find the last occurrence of "\\"
91 let index = path.lastIndexOf("\\");
92 if (index == -1) {
93 // If there is no directory component...
94 if (!noDrive) {
95 // Return the drive path if possible, falling back to "."
96 return this.winGetDrive(path) || ".";
97 } else {
98 // Or just "."
99 return ".";
100 }
101 }
103 if (index == 1 && path.charAt(0) == "\\") {
104 // The path is reduced to a UNC drive
105 if (noDrive) {
106 return ".";
107 } else {
108 return path;
109 }
110 }
112 // Ignore any occurrence of "\\: immediately before that one
113 while (index >= 0 && path[index] == "\\") {
114 --index;
115 }
117 // Compute what is left, removing the drive name if necessary
118 let start;
119 if (noDrive) {
120 start = (this.winGetDrive(path) || "").length;
121 } else {
122 start = 0;
123 }
124 return path.slice(start, index + 1);
125 };
126 exports.dirname = dirname;
128 /**
129 * Join path components.
130 * This is the recommended manner of getting the path of a file/subdirectory
131 * in a directory.
132 *
133 * Example: Obtaining $TMP/foo/bar in an OS-independent manner
134 * var tmpDir = OS.Constants.Path.tmpDir;
135 * var path = OS.Path.join(tmpDir, "foo", "bar");
136 *
137 * Under Windows, this will return "$TMP\foo\bar".
138 */
139 let join = function(...path) {
140 let paths = [];
141 let root;
142 let absolute = false;
143 for (let subpath of path) {
144 if (subpath == null) {
145 throw new TypeError("invalid path component");
146 }
147 let drive = this.winGetDrive(subpath);
148 if (drive) {
149 root = drive;
150 let component = trimBackslashes(subpath.slice(drive.length));
151 if (component) {
152 paths = [component];
153 } else {
154 paths = [];
155 }
156 absolute = true;
157 } else if (this.winIsAbsolute(subpath)) {
158 paths = [trimBackslashes(subpath)];
159 absolute = true;
160 } else {
161 paths.push(trimBackslashes(subpath));
162 }
163 }
164 let result = "";
165 if (root) {
166 result += root;
167 }
168 if (absolute) {
169 result += "\\";
170 }
171 result += paths.join("\\");
172 return result;
173 };
174 exports.join = join;
176 /**
177 * Return the drive name of a path, or |null| if the path does
178 * not contain a drive name.
179 *
180 * Drive name appear either as "DriveName:..." (the return drive
181 * name includes the ":") or "\\\\DriveName..." (the returned drive name
182 * includes "\\\\").
183 */
184 let winGetDrive = function(path) {
185 if (path == null) {
186 throw new TypeError("path is invalid");
187 }
189 if (path.startsWith("\\\\")) {
190 // UNC path
191 if (path.length == 2) {
192 return null;
193 }
194 let index = path.indexOf("\\", 2);
195 if (index == -1) {
196 return path;
197 }
198 return path.slice(0, index);
199 }
200 // Non-UNC path
201 let index = path.indexOf(":");
202 if (index <= 0) return null;
203 return path.slice(0, index + 1);
204 };
205 exports.winGetDrive = winGetDrive;
207 /**
208 * Return |true| if the path is absolute, |false| otherwise.
209 *
210 * We consider that a path is absolute if it starts with "\\"
211 * or "driveletter:\\".
212 */
213 let winIsAbsolute = function(path) {
214 let index = path.indexOf(":");
215 return path.length > index + 1 && path[index + 1] == "\\";
216 };
217 exports.winIsAbsolute = winIsAbsolute;
219 /**
220 * Normalize a path by removing any unneeded ".", "..", "\\".
221 * Also convert any "/" to a "\\".
222 */
223 let normalize = function(path) {
224 let stack = [];
226 if (!path.startsWith("\\\\")) {
227 // Normalize "/" to "\\"
228 path = path.replace(/\//g, "\\");
229 }
231 // Remove the drive (we will put it back at the end)
232 let root = this.winGetDrive(path);
233 if (root) {
234 path = path.slice(root.length);
235 }
237 // Remember whether we need to restore a leading "\\" or drive name.
238 let absolute = this.winIsAbsolute(path);
240 // And now, fill |stack| from the components,
241 // popping whenever there is a ".."
242 path.split("\\").forEach(function loop(v) {
243 switch (v) {
244 case "": case ".": // Ignore
245 break;
246 case "..":
247 if (stack.length == 0) {
248 if (absolute) {
249 throw new Error("Path is ill-formed: attempting to go past root");
250 } else {
251 stack.push("..");
252 }
253 } else {
254 if (stack[stack.length - 1] == "..") {
255 stack.push("..");
256 } else {
257 stack.pop();
258 }
259 }
260 break;
261 default:
262 stack.push(v);
263 }
264 });
266 // Put everything back together
267 let result = stack.join("\\");
268 if (absolute || root) {
269 result = "\\" + result;
270 }
271 if (root) {
272 result = root + result;
273 }
274 return result;
275 };
276 exports.normalize = normalize;
278 /**
279 * Return the components of a path.
280 * You should generally apply this function to a normalized path.
281 *
282 * @return {{
283 * {bool} absolute |true| if the path is absolute, |false| otherwise
284 * {array} components the string components of the path
285 * {string?} winDrive the drive or server for this path
286 * }}
287 *
288 * Other implementations may add additional OS-specific informations.
289 */
290 let split = function(path) {
291 return {
292 absolute: this.winIsAbsolute(path),
293 winDrive: this.winGetDrive(path),
294 components: path.split("\\")
295 };
296 };
297 exports.split = split;
299 /**
300 * Return the file:// URI file path of the given local file path.
301 */
302 // The case of %3b is designed to match Services.io, but fundamentally doesn't matter.
303 let toFileURIExtraEncodings = {';': '%3b', '?': '%3F', "'": '%27', '#': '%23'};
304 let toFileURI = function toFileURI(path) {
305 // URI-escape forward slashes and convert backward slashes to forward
306 path = this.normalize(path).replace(/[\\\/]/g, m => (m=='\\')? '/' : '%2F');
307 let uri = encodeURI(path);
309 // add a prefix, and encodeURI doesn't escape a few characters that we do
310 // want to escape, so fix that up
311 let prefix = "file:///";
312 uri = prefix + uri.replace(/[;?'#]/g, match => toFileURIExtraEncodings[match]);
314 // turn e.g., file:///C: into file:///C:/
315 if (uri.charAt(uri.length - 1) === ':') {
316 uri += "/"
317 }
319 return uri;
320 };
321 exports.toFileURI = toFileURI;
323 /**
324 * Returns the local file path from a given file URI.
325 */
326 let fromFileURI = function fromFileURI(uri) {
327 let url = new URL(uri);
328 if (url.protocol != 'file:') {
329 throw new Error("fromFileURI expects a file URI");
330 }
332 // strip leading slash, since Windows paths don't start with one
333 uri = url.pathname.substr(1);
335 let path = decodeURI(uri);
336 // decode a few characters where URL's parsing is overzealous
337 path = path.replace(/%(3b|3f|23)/gi,
338 match => decodeURIComponent(match));
339 path = this.normalize(path);
341 // this.normalize() does not remove the trailing slash if the path
342 // component is a drive letter. eg. 'C:\'' will not get normalized.
343 if (path.endsWith(":\\")) {
344 path = path.substr(0, path.length - 1);
345 }
346 return this.normalize(path);
347 };
348 exports.fromFileURI = fromFileURI;
350 /**
351 * Utility function: Remove any leading/trailing backslashes
352 * from a string.
353 */
354 let trimBackslashes = function trimBackslashes(string) {
355 return string.replace(/^\\+|\\+$/g,'');
356 };
358 //////////// Boilerplate
359 if (typeof Components != "undefined") {
360 this.EXPORTED_SYMBOLS = EXPORTED_SYMBOLS;
361 for (let symbol of EXPORTED_SYMBOLS) {
362 this[symbol] = exports[symbol];
363 }
364 }