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.
michael@0 | 1 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this file, |
michael@0 | 3 | * You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 4 | |
michael@0 | 5 | "use strict"; |
michael@0 | 6 | |
michael@0 | 7 | this.EXPORTED_SYMBOLS = ["XPathGenerator"]; |
michael@0 | 8 | |
michael@0 | 9 | this.XPathGenerator = { |
michael@0 | 10 | // these two hashes should be kept in sync |
michael@0 | 11 | namespaceURIs: { |
michael@0 | 12 | "xhtml": "http://www.w3.org/1999/xhtml", |
michael@0 | 13 | "xul": "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" |
michael@0 | 14 | }, |
michael@0 | 15 | namespacePrefixes: { |
michael@0 | 16 | "http://www.w3.org/1999/xhtml": "xhtml", |
michael@0 | 17 | "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul": "xul" |
michael@0 | 18 | }, |
michael@0 | 19 | |
michael@0 | 20 | /** |
michael@0 | 21 | * Generates an approximate XPath query to an (X)HTML node |
michael@0 | 22 | */ |
michael@0 | 23 | generate: function sss_xph_generate(aNode) { |
michael@0 | 24 | // have we reached the document node already? |
michael@0 | 25 | if (!aNode.parentNode) |
michael@0 | 26 | return ""; |
michael@0 | 27 | |
michael@0 | 28 | // Access localName, namespaceURI just once per node since it's expensive. |
michael@0 | 29 | let nNamespaceURI = aNode.namespaceURI; |
michael@0 | 30 | let nLocalName = aNode.localName; |
michael@0 | 31 | |
michael@0 | 32 | let prefix = this.namespacePrefixes[nNamespaceURI] || null; |
michael@0 | 33 | let tag = (prefix ? prefix + ":" : "") + this.escapeName(nLocalName); |
michael@0 | 34 | |
michael@0 | 35 | // stop once we've found a tag with an ID |
michael@0 | 36 | if (aNode.id) |
michael@0 | 37 | return "//" + tag + "[@id=" + this.quoteArgument(aNode.id) + "]"; |
michael@0 | 38 | |
michael@0 | 39 | // count the number of previous sibling nodes of the same tag |
michael@0 | 40 | // (and possible also the same name) |
michael@0 | 41 | let count = 0; |
michael@0 | 42 | let nName = aNode.name || null; |
michael@0 | 43 | for (let n = aNode; (n = n.previousSibling); ) |
michael@0 | 44 | if (n.localName == nLocalName && n.namespaceURI == nNamespaceURI && |
michael@0 | 45 | (!nName || n.name == nName)) |
michael@0 | 46 | count++; |
michael@0 | 47 | |
michael@0 | 48 | // recurse until hitting either the document node or an ID'd node |
michael@0 | 49 | return this.generate(aNode.parentNode) + "/" + tag + |
michael@0 | 50 | (nName ? "[@name=" + this.quoteArgument(nName) + "]" : "") + |
michael@0 | 51 | (count ? "[" + (count + 1) + "]" : ""); |
michael@0 | 52 | }, |
michael@0 | 53 | |
michael@0 | 54 | /** |
michael@0 | 55 | * Resolves an XPath query generated by XPathGenerator.generate |
michael@0 | 56 | */ |
michael@0 | 57 | resolve: function sss_xph_resolve(aDocument, aQuery) { |
michael@0 | 58 | let xptype = Components.interfaces.nsIDOMXPathResult.FIRST_ORDERED_NODE_TYPE; |
michael@0 | 59 | return aDocument.evaluate(aQuery, aDocument, this.resolveNS, xptype, null).singleNodeValue; |
michael@0 | 60 | }, |
michael@0 | 61 | |
michael@0 | 62 | /** |
michael@0 | 63 | * Namespace resolver for the above XPath resolver |
michael@0 | 64 | */ |
michael@0 | 65 | resolveNS: function sss_xph_resolveNS(aPrefix) { |
michael@0 | 66 | return XPathGenerator.namespaceURIs[aPrefix] || null; |
michael@0 | 67 | }, |
michael@0 | 68 | |
michael@0 | 69 | /** |
michael@0 | 70 | * @returns valid XPath for the given node (usually just the local name itself) |
michael@0 | 71 | */ |
michael@0 | 72 | escapeName: function sss_xph_escapeName(aName) { |
michael@0 | 73 | // we can't just use the node's local name, if it contains |
michael@0 | 74 | // special characters (cf. bug 485482) |
michael@0 | 75 | return /^\w+$/.test(aName) ? aName : |
michael@0 | 76 | "*[local-name()=" + this.quoteArgument(aName) + "]"; |
michael@0 | 77 | }, |
michael@0 | 78 | |
michael@0 | 79 | /** |
michael@0 | 80 | * @returns a properly quoted string to insert into an XPath query |
michael@0 | 81 | */ |
michael@0 | 82 | quoteArgument: function sss_xph_quoteArgument(aArg) { |
michael@0 | 83 | return !/'/.test(aArg) ? "'" + aArg + "'" : |
michael@0 | 84 | !/"/.test(aArg) ? '"' + aArg + '"' : |
michael@0 | 85 | "concat('" + aArg.replace(/'+/g, "',\"$&\",'") + "')"; |
michael@0 | 86 | }, |
michael@0 | 87 | |
michael@0 | 88 | /** |
michael@0 | 89 | * @returns an XPath query to all savable form field nodes |
michael@0 | 90 | */ |
michael@0 | 91 | get restorableFormNodes() { |
michael@0 | 92 | // for a comprehensive list of all available <INPUT> types see |
michael@0 | 93 | // http://mxr.mozilla.org/mozilla-central/search?string=kInputTypeTable |
michael@0 | 94 | let ignoreTypes = ["password", "hidden", "button", "image", "submit", "reset"]; |
michael@0 | 95 | // XXXzeniko work-around until lower-case has been implemented (bug 398389) |
michael@0 | 96 | let toLowerCase = '"ABCDEFGHIJKLMNOPQRSTUVWXYZ", "abcdefghijklmnopqrstuvwxyz"'; |
michael@0 | 97 | let ignore = "not(translate(@type, " + toLowerCase + ")='" + |
michael@0 | 98 | ignoreTypes.join("' or translate(@type, " + toLowerCase + ")='") + "')"; |
michael@0 | 99 | let formNodesXPath = "//textarea|//select|//xhtml:textarea|//xhtml:select|" + |
michael@0 | 100 | "//input[" + ignore + "]|//xhtml:input[" + ignore + "]"; |
michael@0 | 101 | |
michael@0 | 102 | // Special case for about:config's search field. |
michael@0 | 103 | formNodesXPath += '|/xul:window[@id="config"]//xul:textbox[@id="textbox"]'; |
michael@0 | 104 | |
michael@0 | 105 | delete this.restorableFormNodes; |
michael@0 | 106 | return (this.restorableFormNodes = formNodesXPath); |
michael@0 | 107 | } |
michael@0 | 108 | }; |