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 | <?xml version="1.0"?> |
michael@0 | 2 | <?xml-stylesheet href="chrome://global/skin" type="text/css"?> |
michael@0 | 3 | <?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" |
michael@0 | 4 | type="text/css"?> |
michael@0 | 5 | <!-- |
michael@0 | 6 | https://bugzilla.mozilla.org/show_bug.cgi?id=500931 |
michael@0 | 7 | --> |
michael@0 | 8 | <window title="Mozilla Bug 522764" |
michael@0 | 9 | xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> |
michael@0 | 10 | <script type="application/javascript" |
michael@0 | 11 | src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> |
michael@0 | 12 | |
michael@0 | 13 | <!-- test results are displayed in the html:body --> |
michael@0 | 14 | <body xmlns="http://www.w3.org/1999/xhtml"> |
michael@0 | 15 | <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=522764 " |
michael@0 | 16 | target="_blank">Mozilla Bug 522764 </a> |
michael@0 | 17 | </body> |
michael@0 | 18 | |
michael@0 | 19 | <!-- test code goes here --> |
michael@0 | 20 | <script type="application/javascript"><![CDATA[ |
michael@0 | 21 | const Ci = Components.interfaces; |
michael@0 | 22 | const Cu = Components.utils; |
michael@0 | 23 | |
michael@0 | 24 | var sandbox = new Cu.Sandbox("about:blank"); |
michael@0 | 25 | |
michael@0 | 26 | var test_utils = window.QueryInterface(Ci.nsIInterfaceRequestor). |
michael@0 | 27 | getInterface(Ci.nsIDOMWindowUtils); |
michael@0 | 28 | |
michael@0 | 29 | function getCOW(x) { |
michael@0 | 30 | if (typeof x != 'object' && typeof x != 'function') |
michael@0 | 31 | return x; |
michael@0 | 32 | var rval = {}; |
michael@0 | 33 | if (typeof x == "function") |
michael@0 | 34 | rval = eval(uneval(x)); |
michael@0 | 35 | for (var i in x) { |
michael@0 | 36 | if (x.__lookupGetter__(i)) |
michael@0 | 37 | rval.__defineGetter__(i, eval(uneval(x.__lookupGetter__(i)))) |
michael@0 | 38 | else |
michael@0 | 39 | rval[i] = getCOW(x[i]); |
michael@0 | 40 | } |
michael@0 | 41 | return rval; |
michael@0 | 42 | } |
michael@0 | 43 | |
michael@0 | 44 | // Give the sandbox a way to create ChromeObjectWrapped objects. |
michael@0 | 45 | sandbox.getCOW = getCOW; |
michael@0 | 46 | |
michael@0 | 47 | // Define test API functions in the sandbox. |
michael@0 | 48 | const TEST_API = ['is', 'isnot', 'ok', 'todo_is', 'todo_isnot', 'todo']; |
michael@0 | 49 | TEST_API.forEach(function(name) { sandbox[name] = window[name]; }); |
michael@0 | 50 | |
michael@0 | 51 | sandbox.alienObject = { |
michael@0 | 52 | __exposedProps__: {funProp: 'r'}, |
michael@0 | 53 | funProp: function foo(x) { |
michael@0 | 54 | return x + 1; |
michael@0 | 55 | } |
michael@0 | 56 | }; |
michael@0 | 57 | |
michael@0 | 58 | sandbox.chromeGet = function (obj, prop) { return obj[prop]; }; |
michael@0 | 59 | |
michael@0 | 60 | function COWTests() { |
michael@0 | 61 | // This function is actually decompiled and run inside a |
michael@0 | 62 | // sandbox with content privileges. |
michael@0 | 63 | |
michael@0 | 64 | // TODO: This could use some refactoring; creating helper |
michael@0 | 65 | // functions like assertIsWritable(myObj, 'someproperty') might |
michael@0 | 66 | // be useful. |
michael@0 | 67 | |
michael@0 | 68 | function isProp(obj, propName, value, desc) { |
michael@0 | 69 | try { |
michael@0 | 70 | is(obj[propName], value, "getting " + propName + " on " + desc); |
michael@0 | 71 | ok(propName in obj, |
michael@0 | 72 | propName + " on " + desc + " should exist"); |
michael@0 | 73 | ok(Object.hasOwnProperty.call(obj, propName), |
michael@0 | 74 | propName + " on " + desc + " should exist"); |
michael@0 | 75 | } catch (e) { |
michael@0 | 76 | ok(false, "getting " + propName + " on " + desc + " threw " + e); |
michael@0 | 77 | } |
michael@0 | 78 | } |
michael@0 | 79 | function isPropHidden(obj, propName, desc) { |
michael@0 | 80 | try { |
michael@0 | 81 | is(obj[propName], undefined, |
michael@0 | 82 | "getting " + propName + " on " + desc + " should return undefined"); |
michael@0 | 83 | ok(!(propName in obj), |
michael@0 | 84 | propName + " on " + desc + " should act as if it doesn't exist"); |
michael@0 | 85 | ok(!Object.hasOwnProperty.call(obj, propName), |
michael@0 | 86 | propName + " on " + desc + " should act as if it doesn't exist"); |
michael@0 | 87 | } catch (e) { |
michael@0 | 88 | ok(false, "getting " + propName + " on " + desc + " threw " + e); |
michael@0 | 89 | } |
michael@0 | 90 | } |
michael@0 | 91 | |
michael@0 | 92 | const PROPS_TO_TEST = ['foo', 'bar', 'prototype']; |
michael@0 | 93 | |
michael@0 | 94 | var empty = {}; |
michael@0 | 95 | var nonempty = {foo: 42, bar: 33}; |
michael@0 | 96 | is(getCOW(empty).foo, undefined, |
michael@0 | 97 | "shouldn't throw when accessing exposed properties that doesn't exist"); |
michael@0 | 98 | |
michael@0 | 99 | PROPS_TO_TEST.forEach(function(name) { |
michael@0 | 100 | isPropHidden(getCOW(nonempty), name, "object without exposedProps"); |
michael@0 | 101 | }); |
michael@0 | 102 | |
michael@0 | 103 | // Test function objects without __exposedProps__ |
michael@0 | 104 | var func = function(x) { return 42; }; |
michael@0 | 105 | func.foo = "foo property"; |
michael@0 | 106 | var funcCOW = getCOW(func); |
michael@0 | 107 | PROPS_TO_TEST.forEach(function(name) { |
michael@0 | 108 | isPropHidden(funcCOW, name, "function without exposedProps"); |
michael@0 | 109 | }); |
michael@0 | 110 | is([name for (name in funcCOW)].length, 0, |
michael@0 | 111 | "function without exposedProps shouldn't have any properties"); |
michael@0 | 112 | is(funcCOW(), 42, "COW without exposedProps should still be callable"); |
michael@0 | 113 | |
michael@0 | 114 | // Test function objects with __exposedProps__ |
michael@0 | 115 | var func = function(x) { return 42; }; |
michael@0 | 116 | func.foo = "foo property"; |
michael@0 | 117 | func.__exposedProps__ = { foo: "r" }; |
michael@0 | 118 | var funcCOWr = getCOW(func); |
michael@0 | 119 | PROPS_TO_TEST.forEach(function(name) { |
michael@0 | 120 | if (name == "foo") { |
michael@0 | 121 | isProp(funcCOWr, name, "foo property", |
michael@0 | 122 | "function with exposedProps"); |
michael@0 | 123 | } |
michael@0 | 124 | else { |
michael@0 | 125 | isPropHidden(funcCOWr, name, "function with exposedProps"); |
michael@0 | 126 | } |
michael@0 | 127 | }); |
michael@0 | 128 | is([name for (name in funcCOWr)].length, 1, |
michael@0 | 129 | "function with exposedProps should only enumerate exposed props"); |
michael@0 | 130 | is([name for (name in funcCOWr)][0], "foo", |
michael@0 | 131 | "function with exposedProps should only enumerate exposed props"); |
michael@0 | 132 | is(funcCOWr(), 42, "COW with exposedProps should be callable"); |
michael@0 | 133 | |
michael@0 | 134 | // Test function objects with __exposedProps__ |
michael@0 | 135 | var func = function(x) { return 42; }; |
michael@0 | 136 | func.foo = "foo property"; |
michael@0 | 137 | func.__exposedProps__ = { foo: "r", bar: "r" }; |
michael@0 | 138 | var funcCOWr2 = getCOW(func); |
michael@0 | 139 | PROPS_TO_TEST.forEach(function(name) { |
michael@0 | 140 | if (name == "foo") { |
michael@0 | 141 | isProp(funcCOWr2, name, "foo property", |
michael@0 | 142 | "function with more exposedProps"); |
michael@0 | 143 | } |
michael@0 | 144 | else { |
michael@0 | 145 | isPropHidden(funcCOWr2, name, "function with more exposedProps"); |
michael@0 | 146 | } |
michael@0 | 147 | }); |
michael@0 | 148 | is([name for (name in funcCOWr2)].length, 1, |
michael@0 | 149 | "function with exposedProps should only enumerate exposed props"); |
michael@0 | 150 | is([name for (name in funcCOWr2)][0], "foo", |
michael@0 | 151 | "function with exposedProps should only enumerate exposed props"); |
michael@0 | 152 | |
michael@0 | 153 | // Test object with empty exposedProps |
michael@0 | 154 | var strict = { __exposedProps__: {}, foo: "foo property" }; |
michael@0 | 155 | var strictCOW = getCOW(strict); |
michael@0 | 156 | PROPS_TO_TEST.forEach(function(name) { |
michael@0 | 157 | isPropHidden(strictCOW, name, "object with empty exposedProps"); |
michael@0 | 158 | }); |
michael@0 | 159 | is([name for (name in strictCOW)].length, 0, |
michael@0 | 160 | "object with empty exposedProps shouldn't have any properties"); |
michael@0 | 161 | |
michael@0 | 162 | // Test object with one exposed property |
michael@0 | 163 | var strict = { __exposedProps__: { foo: "r" }, foo: "foo property" }; |
michael@0 | 164 | var strictCOWr = getCOW(strict); |
michael@0 | 165 | PROPS_TO_TEST.forEach(function(name) { |
michael@0 | 166 | if (name == "foo") { |
michael@0 | 167 | isProp(strictCOWr, name, "foo property", |
michael@0 | 168 | "object with exposed 'foo'"); |
michael@0 | 169 | } |
michael@0 | 170 | else { |
michael@0 | 171 | isPropHidden(strictCOW, name, "object with exposed 'foo'"); |
michael@0 | 172 | } |
michael@0 | 173 | }); |
michael@0 | 174 | is([name for (name in strictCOWr)].length, 1, |
michael@0 | 175 | "object with exposedProps only enumerate exposed props"); |
michael@0 | 176 | is([name for (name in strictCOWr)][0], "foo", |
michael@0 | 177 | "object with exposedProps only enumerate exposed props"); |
michael@0 | 178 | |
michael@0 | 179 | // Test writable property |
michael@0 | 180 | var writable = getCOW({ __exposedProps__: {foo: 'w'}}); |
michael@0 | 181 | try { |
michael@0 | 182 | ok(!("foo" in writable), |
michael@0 | 183 | "non-existing write-only property shouldn't exist"); |
michael@0 | 184 | writable.foo = 5; |
michael@0 | 185 | is(chromeGet(writable, "foo"), 5, "writing to a write-only exposed prop works"); |
michael@0 | 186 | todo("foo" in writable, |
michael@0 | 187 | "existing write-only property should exist"); |
michael@0 | 188 | } catch (e) { |
michael@0 | 189 | ok(false, "writing to a write-only exposed prop shouldn't throw " + e); |
michael@0 | 190 | } |
michael@0 | 191 | try { |
michael@0 | 192 | writable.foo; |
michael@0 | 193 | todo(false, "reading from a write-only exposed prop should throw"); |
michael@0 | 194 | } catch (e) { |
michael@0 | 195 | todo(/Permission denied/.test(e), |
michael@0 | 196 | "reading from a write-only exposed prop should throw"); |
michael@0 | 197 | } |
michael@0 | 198 | try { |
michael@0 | 199 | delete writable.foo; |
michael@0 | 200 | is(chromeGet(writable, "foo"), undefined, |
michael@0 | 201 | "deleting a write-only exposed prop works"); |
michael@0 | 202 | } catch (e) { |
michael@0 | 203 | ok(false, "deleting a write-only exposed prop shouldn't throw " + e); |
michael@0 | 204 | } |
michael@0 | 205 | |
michael@0 | 206 | // Test readable property |
michael@0 | 207 | var readable = { __exposedProps__: {foo: 'r'}, |
michael@0 | 208 | foo: 5, |
michael@0 | 209 | bar: 6 }; |
michael@0 | 210 | try { |
michael@0 | 211 | isProp(getCOW(readable), "foo", 5, |
michael@0 | 212 | "reading from a readable exposed prop works"); |
michael@0 | 213 | } catch (e) { |
michael@0 | 214 | ok(false, "reading from a readable exposed prop shouldn't throw " + e); |
michael@0 | 215 | } |
michael@0 | 216 | try { |
michael@0 | 217 | getCOW(readable).foo = 1; |
michael@0 | 218 | ok(false, "writing to a read-only exposed prop should fail"); |
michael@0 | 219 | } catch (e) { |
michael@0 | 220 | ok(/Permission denied/.test(e), |
michael@0 | 221 | "writing to a read-only exposed prop should fail"); |
michael@0 | 222 | } |
michael@0 | 223 | try { |
michael@0 | 224 | delete getCOW(readable).foo; |
michael@0 | 225 | ok(false, "deleting a read-only exposed prop shouldn't work"); |
michael@0 | 226 | } catch (e) { |
michael@0 | 227 | ok(/Permission denied/.test(e), |
michael@0 | 228 | "deleting a read-only exposed prop should throw error"); |
michael@0 | 229 | } |
michael@0 | 230 | |
michael@0 | 231 | try { |
michael@0 | 232 | var props = [name for (name in getCOW(readable))]; |
michael@0 | 233 | is(props.length, 1, "COW w/ one exposed prop should enumerate once"); |
michael@0 | 234 | is(props[0], 'foo', "COW w/ one exposed prop should enumerate it"); |
michael@0 | 235 | } catch (e) { |
michael@0 | 236 | ok(false, "COW w/ a readable prop should not raise exc " + |
michael@0 | 237 | "on enumeration: " + e); |
michael@0 | 238 | } |
michael@0 | 239 | |
michael@0 | 240 | // Test read/write property |
michael@0 | 241 | var readwrite = getCOW({ __exposedProps__: {foo: 'rw'}}); |
michael@0 | 242 | try { |
michael@0 | 243 | ok(!("foo" in readwrite), |
michael@0 | 244 | "non-existing readwrite property shouldn't exist"); |
michael@0 | 245 | readwrite.foo = 5; |
michael@0 | 246 | is(readwrite.foo, 5, "writing to a readwrite exposed prop looks like it worked"); |
michael@0 | 247 | is(chromeGet(readwrite, "foo"), 5, "writing to a readwrite exposed prop works"); |
michael@0 | 248 | ok("foo" in readwrite, |
michael@0 | 249 | "existing readwrite property should exist"); |
michael@0 | 250 | } catch (e) { |
michael@0 | 251 | ok(false, "writing to a readwrite exposed prop shouldn't throw " + e); |
michael@0 | 252 | } |
michael@0 | 253 | try { |
michael@0 | 254 | delete readwrite.foo; |
michael@0 | 255 | is(readwrite.foo, undefined, "deleting readwrite prop looks like it worked"); |
michael@0 | 256 | ok(!("foo" in readwrite), "deleting readwrite prop looks like it really worked"); |
michael@0 | 257 | is(chromeGet(readwrite, "foo"), undefined, |
michael@0 | 258 | "deleting a readwrite exposed prop works"); |
michael@0 | 259 | } catch (e) { |
michael@0 | 260 | ok(false, "deleting a readwrite exposed prop shouldn't throw " + e); |
michael@0 | 261 | } |
michael@0 | 262 | |
michael@0 | 263 | // Readables and functions |
michael@0 | 264 | try { |
michael@0 | 265 | var COWFunc = getCOW((function() { return 5; })); |
michael@0 | 266 | is(COWFunc(), 5, "COWed functions should be callable"); |
michael@0 | 267 | } catch (e) { |
michael@0 | 268 | todo(false, "COWed functions should not raise " + e); |
michael@0 | 269 | } |
michael@0 | 270 | try { |
michael@0 | 271 | var objWithFunc = {__exposedProps__: {foo: 'r'}, |
michael@0 | 272 | foo: function foo() { return 5; }}; |
michael@0 | 273 | is(getCOW((objWithFunc)).foo(), 5, |
michael@0 | 274 | "Readable function exposed props should be callable"); |
michael@0 | 275 | } catch (e) { |
michael@0 | 276 | ok(false, "Readable function exposed props should be callable" + e); |
michael@0 | 277 | } |
michael@0 | 278 | |
michael@0 | 279 | // Readables with getters |
michael@0 | 280 | var obj = { |
michael@0 | 281 | get prop() { return { __exposedProps__: {}, test: "FAIL" } }, |
michael@0 | 282 | __exposedProps__: {prop: 'r'} |
michael@0 | 283 | }; |
michael@0 | 284 | is(getCOW(obj).prop.test, undefined, "getting prop.test shouldn't return anything"); |
michael@0 | 285 | ok(!("test" in getCOW(obj).prop), "getting prop.test shouldn't return anything"); |
michael@0 | 286 | |
michael@0 | 287 | // Alien objects |
michael@0 | 288 | try { |
michael@0 | 289 | is(alienObject.funProp(1), 2, |
michael@0 | 290 | "COWs wrapping objects from different principals should work"); |
michael@0 | 291 | } catch (e) { |
michael@0 | 292 | ok(false, "COWs wrapping objs from different principals " + |
michael@0 | 293 | "shouldn't throw " + e); |
michael@0 | 294 | } |
michael@0 | 295 | |
michael@0 | 296 | try { |
michael@0 | 297 | is(alienObject.funProp(1), 2, |
michael@0 | 298 | "COWs wrapping objs from different principals should work twice"); |
michael@0 | 299 | } catch (e) { |
michael@0 | 300 | ok(false, "COWs wrapping objs from different principals " + |
michael@0 | 301 | "shouldn't throw on second access but not first: " + e); |
michael@0 | 302 | } |
michael@0 | 303 | } |
michael@0 | 304 | |
michael@0 | 305 | // Decompile the COW test suite, re-evaluate it in the sandbox and execute it. |
michael@0 | 306 | Cu.evalInSandbox('(' + uneval(COWTests) + ')()', sandbox); |
michael@0 | 307 | |
michael@0 | 308 | // Test that COWed objects passing from content to chrome get unwrapped. |
michael@0 | 309 | function returnCOW() { |
michael@0 | 310 | return getCOW({__exposedProps__: {}, |
michael@0 | 311 | bar: 6}); |
michael@0 | 312 | } |
michael@0 | 313 | |
michael@0 | 314 | var unwrapped = Cu.evalInSandbox( |
michael@0 | 315 | '(' + uneval(returnCOW) + ')()', |
michael@0 | 316 | sandbox |
michael@0 | 317 | ); |
michael@0 | 318 | |
michael@0 | 319 | try { |
michael@0 | 320 | is(unwrapped.bar, 6, |
michael@0 | 321 | "COWs should be unwrapped when entering chrome space"); |
michael@0 | 322 | } catch (e) { |
michael@0 | 323 | todo(false, "COWs should be unwrapped when entering chrome space, " + |
michael@0 | 324 | "not raise " + e); |
michael@0 | 325 | } |
michael@0 | 326 | ]]></script> |
michael@0 | 327 | </window> |