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 | const Cu = Components.utils; |
michael@0 | 2 | Cu.import("resource://gre/modules/Services.jsm"); |
michael@0 | 3 | let tempScope = {}; |
michael@0 | 4 | Cu.import("resource://gre/modules/devtools/dbg-client.jsm", tempScope); |
michael@0 | 5 | Cu.import("resource://gre/modules/devtools/dbg-server.jsm", tempScope); |
michael@0 | 6 | Cu.import("resource://gre/modules/Promise.jsm", tempScope); |
michael@0 | 7 | let {DebuggerServer, DebuggerClient, Promise} = tempScope; |
michael@0 | 8 | tempScope = null; |
michael@0 | 9 | |
michael@0 | 10 | const {StorageFront} = require("devtools/server/actors/storage"); |
michael@0 | 11 | let gFront, gWindow; |
michael@0 | 12 | |
michael@0 | 13 | const beforeReload = { |
michael@0 | 14 | cookies: { |
michael@0 | 15 | "test1.example.org": ["c1", "cs2", "c3", "uc1"], |
michael@0 | 16 | "sectest1.example.org": ["uc1", "cs2"] |
michael@0 | 17 | }, |
michael@0 | 18 | localStorage: { |
michael@0 | 19 | "http://test1.example.org": ["ls1", "ls2"], |
michael@0 | 20 | "http://sectest1.example.org": ["iframe-u-ls1"] |
michael@0 | 21 | }, |
michael@0 | 22 | sessionStorage: { |
michael@0 | 23 | "http://test1.example.org": ["ss1"], |
michael@0 | 24 | "http://sectest1.example.org": ["iframe-u-ss1", "iframe-u-ss2"] |
michael@0 | 25 | }, |
michael@0 | 26 | indexedDB: { |
michael@0 | 27 | "http://test1.example.org": [ |
michael@0 | 28 | JSON.stringify(["idb1", "obj1"]), |
michael@0 | 29 | JSON.stringify(["idb1", "obj2"]), |
michael@0 | 30 | JSON.stringify(["idb2", "obj3"]), |
michael@0 | 31 | ], |
michael@0 | 32 | "http://sectest1.example.org": [] |
michael@0 | 33 | } |
michael@0 | 34 | }; |
michael@0 | 35 | |
michael@0 | 36 | function finishTests(client) { |
michael@0 | 37 | // Cleanup so that indexed db created from this test do not interfere next ones |
michael@0 | 38 | |
michael@0 | 39 | /** |
michael@0 | 40 | * This method iterates over iframes in a window and clears the indexed db |
michael@0 | 41 | * created by this test. |
michael@0 | 42 | */ |
michael@0 | 43 | let clearIDB = (w, i, c) => { |
michael@0 | 44 | if (w[i] && w[i].clear) { |
michael@0 | 45 | w[i].clearIterator = w[i].clear(() => clearIDB(w, i + 1, c)); |
michael@0 | 46 | w[i].clearIterator.next(); |
michael@0 | 47 | } |
michael@0 | 48 | else if (w[i] && w[i + 1]) { |
michael@0 | 49 | clearIDB(w, i + 1, c); |
michael@0 | 50 | } |
michael@0 | 51 | else { |
michael@0 | 52 | c(); |
michael@0 | 53 | } |
michael@0 | 54 | }; |
michael@0 | 55 | |
michael@0 | 56 | let closeConnection = () => { |
michael@0 | 57 | // Forcing GC/CC to get rid of docshells and windows created by this test. |
michael@0 | 58 | forceCollections(); |
michael@0 | 59 | client.close(() => { |
michael@0 | 60 | forceCollections(); |
michael@0 | 61 | DebuggerServer.destroy(); |
michael@0 | 62 | forceCollections(); |
michael@0 | 63 | gFront = gWindow = DebuggerClient = DebuggerServer = null; |
michael@0 | 64 | finish(); |
michael@0 | 65 | }); |
michael@0 | 66 | } |
michael@0 | 67 | gWindow.clearIterator = gWindow.clear(() => { |
michael@0 | 68 | clearIDB(gWindow, 0, closeConnection); |
michael@0 | 69 | }); |
michael@0 | 70 | gWindow.clearIterator.next(); |
michael@0 | 71 | } |
michael@0 | 72 | |
michael@0 | 73 | function testStores(data, client) { |
michael@0 | 74 | testWindowsBeforeReload(data); |
michael@0 | 75 | testReload().then(() => |
michael@0 | 76 | testAddIframe()).then(() => |
michael@0 | 77 | testRemoveIframe()).then(() => |
michael@0 | 78 | finishTests(client)); |
michael@0 | 79 | } |
michael@0 | 80 | |
michael@0 | 81 | function testWindowsBeforeReload(data) { |
michael@0 | 82 | for (let storageType in beforeReload) { |
michael@0 | 83 | ok(data[storageType], storageType + " storage actor is present"); |
michael@0 | 84 | is(Object.keys(data[storageType].hosts).length, |
michael@0 | 85 | Object.keys(beforeReload[storageType]).length, |
michael@0 | 86 | "Number of hosts for " + storageType + "match"); |
michael@0 | 87 | for (let host in beforeReload[storageType]) { |
michael@0 | 88 | ok(data[storageType].hosts[host], "Host " + host + " is present"); |
michael@0 | 89 | } |
michael@0 | 90 | } |
michael@0 | 91 | } |
michael@0 | 92 | |
michael@0 | 93 | function markOutMatched(toBeEmptied, data, deleted) { |
michael@0 | 94 | if (!Object.keys(toBeEmptied).length) { |
michael@0 | 95 | info("Object empty") |
michael@0 | 96 | return; |
michael@0 | 97 | } |
michael@0 | 98 | ok(Object.keys(data).length, |
michael@0 | 99 | "Atleast some storage types should be present in deleted"); |
michael@0 | 100 | for (let storageType in toBeEmptied) { |
michael@0 | 101 | if (!data[storageType]) { |
michael@0 | 102 | continue; |
michael@0 | 103 | } |
michael@0 | 104 | info("Testing for " + storageType); |
michael@0 | 105 | for (let host in data[storageType]) { |
michael@0 | 106 | ok(toBeEmptied[storageType][host], "Host " + host + " found"); |
michael@0 | 107 | if (!deleted) { |
michael@0 | 108 | for (let item of data[storageType][host]) { |
michael@0 | 109 | let index = toBeEmptied[storageType][host].indexOf(item); |
michael@0 | 110 | ok(index > -1, "Item found - " + item); |
michael@0 | 111 | if (index > -1) { |
michael@0 | 112 | toBeEmptied[storageType][host].splice(index, 1); |
michael@0 | 113 | } |
michael@0 | 114 | } |
michael@0 | 115 | if (!toBeEmptied[storageType][host].length) { |
michael@0 | 116 | delete toBeEmptied[storageType][host]; |
michael@0 | 117 | } |
michael@0 | 118 | } |
michael@0 | 119 | else { |
michael@0 | 120 | delete toBeEmptied[storageType][host]; |
michael@0 | 121 | } |
michael@0 | 122 | } |
michael@0 | 123 | if (!Object.keys(toBeEmptied[storageType]).length) { |
michael@0 | 124 | delete toBeEmptied[storageType]; |
michael@0 | 125 | } |
michael@0 | 126 | } |
michael@0 | 127 | } |
michael@0 | 128 | |
michael@0 | 129 | function testReload() { |
michael@0 | 130 | info("Testing if reload works properly"); |
michael@0 | 131 | |
michael@0 | 132 | let shouldBeEmptyFirst = Cu.cloneInto(beforeReload, {}); |
michael@0 | 133 | let shouldBeEmptyLast = Cu.cloneInto(beforeReload, {}); |
michael@0 | 134 | let reloaded = Promise.defer(); |
michael@0 | 135 | |
michael@0 | 136 | let onStoresUpdate = data => { |
michael@0 | 137 | info("in stores update of testReload"); |
michael@0 | 138 | // This might be second time stores update is happening, in which case, |
michael@0 | 139 | // data.deleted will be null. |
michael@0 | 140 | // OR.. This might be the first time on a super slow machine where both |
michael@0 | 141 | // data.deleted and data.added is missing in the first update. |
michael@0 | 142 | if (data.deleted) { |
michael@0 | 143 | markOutMatched(shouldBeEmptyFirst, data.deleted, true); |
michael@0 | 144 | } |
michael@0 | 145 | |
michael@0 | 146 | if (!Object.keys(shouldBeEmptyFirst).length) { |
michael@0 | 147 | info("shouldBeEmptyFirst is empty now"); |
michael@0 | 148 | } |
michael@0 | 149 | |
michael@0 | 150 | // stores-update call might not have data.added for the first time on slow |
michael@0 | 151 | // machines, in which case, data.added will be null |
michael@0 | 152 | if (data.added) { |
michael@0 | 153 | markOutMatched(shouldBeEmptyLast, data.added); |
michael@0 | 154 | } |
michael@0 | 155 | |
michael@0 | 156 | if (!Object.keys(shouldBeEmptyLast).length) { |
michael@0 | 157 | info("Everything to be received is received."); |
michael@0 | 158 | endTestReloaded(); |
michael@0 | 159 | } |
michael@0 | 160 | }; |
michael@0 | 161 | |
michael@0 | 162 | let endTestReloaded = () => { |
michael@0 | 163 | gFront.off("stores-update", onStoresUpdate); |
michael@0 | 164 | reloaded.resolve(); |
michael@0 | 165 | }; |
michael@0 | 166 | |
michael@0 | 167 | gFront.on("stores-update", onStoresUpdate); |
michael@0 | 168 | |
michael@0 | 169 | content.location.reload(); |
michael@0 | 170 | return reloaded.promise; |
michael@0 | 171 | } |
michael@0 | 172 | |
michael@0 | 173 | function testAddIframe() { |
michael@0 | 174 | info("Testing if new iframe addition works properly"); |
michael@0 | 175 | let reloaded = Promise.defer(); |
michael@0 | 176 | |
michael@0 | 177 | let shouldBeEmpty = { |
michael@0 | 178 | localStorage: { |
michael@0 | 179 | "https://sectest1.example.org": ["iframe-s-ls1"] |
michael@0 | 180 | }, |
michael@0 | 181 | sessionStorage: { |
michael@0 | 182 | "https://sectest1.example.org": ["iframe-s-ss1"] |
michael@0 | 183 | }, |
michael@0 | 184 | cookies: { |
michael@0 | 185 | "sectest1.example.org": ["sc1"] |
michael@0 | 186 | }, |
michael@0 | 187 | indexedDB: { |
michael@0 | 188 | // empty because indexed db creation happens after the page load, so at |
michael@0 | 189 | // the time of window-ready, there was no indexed db present. |
michael@0 | 190 | "https://sectest1.example.org": [] |
michael@0 | 191 | } |
michael@0 | 192 | }; |
michael@0 | 193 | |
michael@0 | 194 | let onStoresUpdate = data => { |
michael@0 | 195 | info("checking if the hosts list is correct for this iframe addition"); |
michael@0 | 196 | |
michael@0 | 197 | markOutMatched(shouldBeEmpty, data.added); |
michael@0 | 198 | |
michael@0 | 199 | ok(!data.changed || !data.changed.cookies || |
michael@0 | 200 | !data.changed.cookies["https://sectest1.example.org"], |
michael@0 | 201 | "Nothing got changed for cookies"); |
michael@0 | 202 | ok(!data.changed || !data.changed.localStorage || |
michael@0 | 203 | !data.changed.localStorage["https://sectest1.example.org"], |
michael@0 | 204 | "Nothing got changed for local storage"); |
michael@0 | 205 | ok(!data.changed || !data.changed.sessionStorage || |
michael@0 | 206 | !data.changed.sessionStorage["https://sectest1.example.org"], |
michael@0 | 207 | "Nothing got changed for session storage"); |
michael@0 | 208 | ok(!data.changed || !data.changed.indexedDB || |
michael@0 | 209 | !data.changed.indexedDB["https://sectest1.example.org"], |
michael@0 | 210 | "Nothing got changed for indexed db"); |
michael@0 | 211 | |
michael@0 | 212 | ok(!data.deleted || !data.deleted.cookies || |
michael@0 | 213 | !data.deleted.cookies["https://sectest1.example.org"], |
michael@0 | 214 | "Nothing got deleted for cookies"); |
michael@0 | 215 | ok(!data.deleted || !data.deleted.localStorage || |
michael@0 | 216 | !data.deleted.localStorage["https://sectest1.example.org"], |
michael@0 | 217 | "Nothing got deleted for local storage"); |
michael@0 | 218 | ok(!data.deleted || !data.deleted.sessionStorage || |
michael@0 | 219 | !data.deleted.sessionStorage["https://sectest1.example.org"], |
michael@0 | 220 | "Nothing got deleted for session storage"); |
michael@0 | 221 | ok(!data.deleted || !data.deleted.indexedDB || |
michael@0 | 222 | !data.deleted.indexedDB["https://sectest1.example.org"], |
michael@0 | 223 | "Nothing got deleted for indexed db"); |
michael@0 | 224 | |
michael@0 | 225 | if (!Object.keys(shouldBeEmpty).length) { |
michael@0 | 226 | info("Everything to be received is received."); |
michael@0 | 227 | endTestReloaded(); |
michael@0 | 228 | } |
michael@0 | 229 | }; |
michael@0 | 230 | |
michael@0 | 231 | let endTestReloaded = () => { |
michael@0 | 232 | gFront.off("stores-update", onStoresUpdate); |
michael@0 | 233 | reloaded.resolve(); |
michael@0 | 234 | }; |
michael@0 | 235 | |
michael@0 | 236 | gFront.on("stores-update", onStoresUpdate); |
michael@0 | 237 | |
michael@0 | 238 | let iframe = content.document.createElement("iframe"); |
michael@0 | 239 | iframe.src = ALT_DOMAIN_SECURED + "storage-secured-iframe.html"; |
michael@0 | 240 | content.document.querySelector("body").appendChild(iframe); |
michael@0 | 241 | return reloaded.promise; |
michael@0 | 242 | } |
michael@0 | 243 | |
michael@0 | 244 | function testRemoveIframe() { |
michael@0 | 245 | info("Testing if iframe removal works properly"); |
michael@0 | 246 | let reloaded = Promise.defer(); |
michael@0 | 247 | |
michael@0 | 248 | let shouldBeEmpty = { |
michael@0 | 249 | localStorage: { |
michael@0 | 250 | "http://sectest1.example.org": [] |
michael@0 | 251 | }, |
michael@0 | 252 | sessionStorage: { |
michael@0 | 253 | "http://sectest1.example.org": [] |
michael@0 | 254 | } |
michael@0 | 255 | }; |
michael@0 | 256 | |
michael@0 | 257 | let onStoresUpdate = data => { |
michael@0 | 258 | info("checking if the hosts list is correct for this iframe deletion"); |
michael@0 | 259 | |
michael@0 | 260 | markOutMatched(shouldBeEmpty, data.deleted, true); |
michael@0 | 261 | |
michael@0 | 262 | ok(!data.deleted.cookies || !data.deleted.cookies["sectest1.example.org"], |
michael@0 | 263 | "Nothing got deleted for Cookies as the same hostname is still present"); |
michael@0 | 264 | |
michael@0 | 265 | ok(!data.changed || !data.changed.cookies || |
michael@0 | 266 | !data.changed.cookies["http://sectest1.example.org"], |
michael@0 | 267 | "Nothing got changed for cookies"); |
michael@0 | 268 | ok(!data.changed || !data.changed.localStorage || |
michael@0 | 269 | !data.changed.localStorage["http://sectest1.example.org"], |
michael@0 | 270 | "Nothing got changed for local storage"); |
michael@0 | 271 | ok(!data.changed || !data.changed.sessionStorage || |
michael@0 | 272 | !data.changed.sessionStorage["http://sectest1.example.org"], |
michael@0 | 273 | "Nothing got changed for session storage"); |
michael@0 | 274 | |
michael@0 | 275 | ok(!data.added || !data.added.cookies || |
michael@0 | 276 | !data.added.cookies["http://sectest1.example.org"], |
michael@0 | 277 | "Nothing got added for cookies"); |
michael@0 | 278 | ok(!data.added || !data.added.localStorage || |
michael@0 | 279 | !data.added.localStorage["http://sectest1.example.org"], |
michael@0 | 280 | "Nothing got added for local storage"); |
michael@0 | 281 | ok(!data.added || !data.added.sessionStorage || |
michael@0 | 282 | !data.added.sessionStorage["http://sectest1.example.org"], |
michael@0 | 283 | "Nothing got added for session storage"); |
michael@0 | 284 | |
michael@0 | 285 | if (!Object.keys(shouldBeEmpty).length) { |
michael@0 | 286 | info("Everything to be received is received."); |
michael@0 | 287 | endTestReloaded(); |
michael@0 | 288 | } |
michael@0 | 289 | }; |
michael@0 | 290 | |
michael@0 | 291 | let endTestReloaded = () => { |
michael@0 | 292 | gFront.off("stores-update", onStoresUpdate); |
michael@0 | 293 | reloaded.resolve(); |
michael@0 | 294 | }; |
michael@0 | 295 | |
michael@0 | 296 | gFront.on("stores-update", onStoresUpdate); |
michael@0 | 297 | |
michael@0 | 298 | for (let iframe of content.document.querySelectorAll("iframe")) { |
michael@0 | 299 | if (iframe.src.startsWith("http:")) { |
michael@0 | 300 | iframe.remove(); |
michael@0 | 301 | break; |
michael@0 | 302 | } |
michael@0 | 303 | } |
michael@0 | 304 | return reloaded.promise; |
michael@0 | 305 | } |
michael@0 | 306 | |
michael@0 | 307 | function test() { |
michael@0 | 308 | waitForExplicitFinish(); |
michael@0 | 309 | addTab(MAIN_DOMAIN + "storage-dynamic-windows.html", function(doc) { |
michael@0 | 310 | try { |
michael@0 | 311 | // Sometimes debugger server does not get destroyed correctly by previous |
michael@0 | 312 | // tests. |
michael@0 | 313 | DebuggerServer.destroy(); |
michael@0 | 314 | } catch (ex) { } |
michael@0 | 315 | DebuggerServer.init(function () { return true; }); |
michael@0 | 316 | DebuggerServer.addBrowserActors(); |
michael@0 | 317 | |
michael@0 | 318 | let createConnection = () => { |
michael@0 | 319 | let client = new DebuggerClient(DebuggerServer.connectPipe()); |
michael@0 | 320 | client.connect(function onConnect() { |
michael@0 | 321 | client.listTabs(function onListTabs(aResponse) { |
michael@0 | 322 | let form = aResponse.tabs[aResponse.selected]; |
michael@0 | 323 | gFront = StorageFront(client, form); |
michael@0 | 324 | |
michael@0 | 325 | gFront.listStores().then(data => testStores(data, client)); |
michael@0 | 326 | }); |
michael@0 | 327 | }); |
michael@0 | 328 | }; |
michael@0 | 329 | |
michael@0 | 330 | /** |
michael@0 | 331 | * This method iterates over iframes in a window and setups the indexed db |
michael@0 | 332 | * required for this test. |
michael@0 | 333 | */ |
michael@0 | 334 | let setupIDBInFrames = (w, i, c) => { |
michael@0 | 335 | if (w[i] && w[i].idbGenerator) { |
michael@0 | 336 | w[i].setupIDB = w[i].idbGenerator(() => setupIDBInFrames(w, i + 1, c)); |
michael@0 | 337 | w[i].setupIDB.next(); |
michael@0 | 338 | } |
michael@0 | 339 | else if (w[i] && w[i + 1]) { |
michael@0 | 340 | setupIDBInFrames(w, i + 1, c); |
michael@0 | 341 | } |
michael@0 | 342 | else { |
michael@0 | 343 | c(); |
michael@0 | 344 | } |
michael@0 | 345 | }; |
michael@0 | 346 | // Setup the indexed db in main window. |
michael@0 | 347 | gWindow = doc.defaultView.wrappedJSObject; |
michael@0 | 348 | gWindow.setupIDB = gWindow.idbGenerator(() => { |
michael@0 | 349 | setupIDBInFrames(gWindow, 0, createConnection); |
michael@0 | 350 | }); |
michael@0 | 351 | gWindow.setupIDB.next(); |
michael@0 | 352 | }); |
michael@0 | 353 | } |