Thu, 15 Jan 2015 15:59:08 +0100
Implement a real Private Browsing Mode condition by changing the API/ABI;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.
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 |
michael@0 | 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 4 | |
michael@0 | 5 | const { Request } = require("sdk/request"); |
michael@0 | 6 | const { pathFor } = require("sdk/system"); |
michael@0 | 7 | const file = require("sdk/io/file"); |
michael@0 | 8 | const { URL } = require("sdk/url"); |
michael@0 | 9 | const { extend } = require("sdk/util/object"); |
michael@0 | 10 | const { Loader } = require("sdk/test/loader"); |
michael@0 | 11 | const options = require("@test/options"); |
michael@0 | 12 | |
michael@0 | 13 | const loader = Loader(module); |
michael@0 | 14 | const httpd = loader.require("sdk/test/httpd"); |
michael@0 | 15 | if (options.parseable || options.verbose) |
michael@0 | 16 | loader.sandbox("sdk/test/httpd").DEBUG = true; |
michael@0 | 17 | const { startServerAsync } = httpd; |
michael@0 | 18 | |
michael@0 | 19 | const { Cc, Ci, Cu } = require("chrome"); |
michael@0 | 20 | const { Services } = Cu.import("resource://gre/modules/Services.jsm"); |
michael@0 | 21 | |
michael@0 | 22 | // Use the profile directory for the temporary files as that will be deleted |
michael@0 | 23 | // when tests are complete |
michael@0 | 24 | const basePath = pathFor("ProfD"); |
michael@0 | 25 | const port = 8099; |
michael@0 | 26 | |
michael@0 | 27 | |
michael@0 | 28 | exports.testOptionsValidator = function(assert) { |
michael@0 | 29 | // First, a simple test to make sure we didn't break normal functionality. |
michael@0 | 30 | assert.throws(function () { |
michael@0 | 31 | Request({ |
michael@0 | 32 | url: null |
michael@0 | 33 | }); |
michael@0 | 34 | }, /The option "url" is invalid./); |
michael@0 | 35 | |
michael@0 | 36 | // Next we'll have a Request that doesn't throw from c'tor, but from a setter. |
michael@0 | 37 | let req = Request({ |
michael@0 | 38 | url: "http://playground.zpao.com/jetpack/request/text.php", |
michael@0 | 39 | onComplete: function () {} |
michael@0 | 40 | }); |
michael@0 | 41 | assert.throws(function () { |
michael@0 | 42 | req.url = 'www.mozilla.org'; |
michael@0 | 43 | }, /The option "url" is invalid/); |
michael@0 | 44 | // The url shouldn't have changed, so check that |
michael@0 | 45 | assert.equal(req.url, "http://playground.zpao.com/jetpack/request/text.php"); |
michael@0 | 46 | }; |
michael@0 | 47 | |
michael@0 | 48 | exports.testContentValidator = function(assert, done) { |
michael@0 | 49 | runMultipleURLs(null, assert, done, { |
michael@0 | 50 | url: "data:text/html;charset=utf-8,response", |
michael@0 | 51 | content: { 'key1' : null, 'key2' : 'some value' }, |
michael@0 | 52 | onComplete: function(response) { |
michael@0 | 53 | assert.equal(response.text, "response?key1=null&key2=some+value"); |
michael@0 | 54 | } |
michael@0 | 55 | }); |
michael@0 | 56 | }; |
michael@0 | 57 | |
michael@0 | 58 | // This is a request to a file that exists. |
michael@0 | 59 | exports.testStatus200 = function (assert, done) { |
michael@0 | 60 | let srv = startServerAsync(port, basePath); |
michael@0 | 61 | let content = "Look ma, no hands!\n"; |
michael@0 | 62 | let basename = "test-request.txt" |
michael@0 | 63 | prepareFile(basename, content); |
michael@0 | 64 | |
michael@0 | 65 | var req = Request({ |
michael@0 | 66 | url: "http://localhost:" + port + "/" + basename, |
michael@0 | 67 | onComplete: function (response) { |
michael@0 | 68 | assert.equal(this, req, "`this` should be request"); |
michael@0 | 69 | assert.equal(response.status, 200); |
michael@0 | 70 | assert.equal(response.statusText, "OK"); |
michael@0 | 71 | assert.equal(response.headers["Content-Type"], "text/plain"); |
michael@0 | 72 | assert.equal(response.text, content); |
michael@0 | 73 | srv.stop(done); |
michael@0 | 74 | } |
michael@0 | 75 | }).get(); |
michael@0 | 76 | }; |
michael@0 | 77 | |
michael@0 | 78 | // This tries to get a file that doesn't exist |
michael@0 | 79 | exports.testStatus404 = function (assert, done) { |
michael@0 | 80 | var srv = startServerAsync(port, basePath); |
michael@0 | 81 | |
michael@0 | 82 | runMultipleURLs(srv, assert, done, { |
michael@0 | 83 | // the following URL doesn't exist |
michael@0 | 84 | url: "http://localhost:" + port + "/test-request-404.txt", |
michael@0 | 85 | onComplete: function (response) { |
michael@0 | 86 | assert.equal(response.status, 404); |
michael@0 | 87 | assert.equal(response.statusText, "Not Found"); |
michael@0 | 88 | } |
michael@0 | 89 | }); |
michael@0 | 90 | }; |
michael@0 | 91 | |
michael@0 | 92 | // a simple file with a known header |
michael@0 | 93 | exports.testKnownHeader = function (assert, done) { |
michael@0 | 94 | var srv = startServerAsync(port, basePath); |
michael@0 | 95 | |
michael@0 | 96 | // Create the file that will be requested with the associated headers file |
michael@0 | 97 | let content = "This tests adding headers to the server's response.\n"; |
michael@0 | 98 | let basename = "test-request-headers.txt"; |
michael@0 | 99 | let headerContent = "x-jetpack-header: Jamba Juice\n"; |
michael@0 | 100 | let headerBasename = "test-request-headers.txt^headers^"; |
michael@0 | 101 | prepareFile(basename, content); |
michael@0 | 102 | prepareFile(headerBasename, headerContent); |
michael@0 | 103 | |
michael@0 | 104 | runMultipleURLs(srv, assert, done, { |
michael@0 | 105 | url: "http://localhost:" + port + "/test-request-headers.txt", |
michael@0 | 106 | onComplete: function (response) { |
michael@0 | 107 | assert.equal(response.headers["x-jetpack-header"], "Jamba Juice"); |
michael@0 | 108 | } |
michael@0 | 109 | }); |
michael@0 | 110 | }; |
michael@0 | 111 | |
michael@0 | 112 | // complex headers |
michael@0 | 113 | exports.testComplexHeader = function (assert, done) { |
michael@0 | 114 | let srv = startServerAsync(port, basePath); |
michael@0 | 115 | |
michael@0 | 116 | let basename = "test-request-complex-headers.sjs"; |
michael@0 | 117 | let content = handleRequest.toString(); |
michael@0 | 118 | prepareFile(basename, content); |
michael@0 | 119 | |
michael@0 | 120 | let headers = { |
michael@0 | 121 | "x-jetpack-header": "Jamba Juice is: delicious", |
michael@0 | 122 | "x-jetpack-header-2": "foo,bar", |
michael@0 | 123 | "x-jetpack-header-3": "sup dawg, i heard you like x, so we put a x in " + |
michael@0 | 124 | "yo x so you can y while you y", |
michael@0 | 125 | "Set-Cookie": "foo=bar\nbaz=foo" |
michael@0 | 126 | }; |
michael@0 | 127 | |
michael@0 | 128 | runMultipleURLs(srv, assert, done, { |
michael@0 | 129 | url: "http://localhost:" + port + "/test-request-complex-headers.sjs", |
michael@0 | 130 | onComplete: function (response) { |
michael@0 | 131 | for (k in headers) { |
michael@0 | 132 | assert.equal(response.headers[k], headers[k]); |
michael@0 | 133 | } |
michael@0 | 134 | } |
michael@0 | 135 | }); |
michael@0 | 136 | }; |
michael@0 | 137 | |
michael@0 | 138 | // Force Allow Third Party cookies |
michael@0 | 139 | exports.test3rdPartyCookies = function (assert, done) { |
michael@0 | 140 | let srv = startServerAsync(port, basePath); |
michael@0 | 141 | |
michael@0 | 142 | let basename = "test-request-3rd-party-cookies.sjs"; |
michael@0 | 143 | |
michael@0 | 144 | // Function to handle the requests in the server |
michael@0 | 145 | let content = function handleRequest(request, response) { |
michael@0 | 146 | var cookiePresent = request.hasHeader("Cookie"); |
michael@0 | 147 | // If no cookie, set it |
michael@0 | 148 | if(!cookiePresent) { |
michael@0 | 149 | response.setHeader("Set-Cookie", "cookie=monster;", "true"); |
michael@0 | 150 | response.setHeader("x-jetpack-3rd-party", "false", "true"); |
michael@0 | 151 | } else { |
michael@0 | 152 | // We got the cookie, say so |
michael@0 | 153 | response.setHeader("x-jetpack-3rd-party", "true", "true"); |
michael@0 | 154 | } |
michael@0 | 155 | |
michael@0 | 156 | response.write("<html><body>This tests 3rd party cookies.</body></html>"); |
michael@0 | 157 | }.toString(); |
michael@0 | 158 | |
michael@0 | 159 | prepareFile(basename, content); |
michael@0 | 160 | |
michael@0 | 161 | // Disable the 3rd party cookies |
michael@0 | 162 | Services.prefs.setIntPref("network.cookie.cookieBehavior", 1); |
michael@0 | 163 | |
michael@0 | 164 | Request({ |
michael@0 | 165 | url: "http://localhost:" + port + "/test-request-3rd-party-cookies.sjs", |
michael@0 | 166 | onComplete: function (response) { |
michael@0 | 167 | // Check that the server created the cookie |
michael@0 | 168 | assert.equal(response.headers['Set-Cookie'], 'cookie=monster;'); |
michael@0 | 169 | |
michael@0 | 170 | // Check it wasn't there before |
michael@0 | 171 | assert.equal(response.headers['x-jetpack-3rd-party'], 'false'); |
michael@0 | 172 | |
michael@0 | 173 | // Make a second request, and check that the server this time |
michael@0 | 174 | // got the cookie |
michael@0 | 175 | Request({ |
michael@0 | 176 | url: "http://localhost:" + port + "/test-request-3rd-party-cookies.sjs", |
michael@0 | 177 | onComplete: function (response) { |
michael@0 | 178 | assert.equal(response.headers['x-jetpack-3rd-party'], 'true'); |
michael@0 | 179 | srv.stop(done); |
michael@0 | 180 | } |
michael@0 | 181 | }).get(); |
michael@0 | 182 | } |
michael@0 | 183 | }).get(); |
michael@0 | 184 | }; |
michael@0 | 185 | |
michael@0 | 186 | exports.testSimpleJSON = function (assert, done) { |
michael@0 | 187 | let srv = startServerAsync(port, basePath); |
michael@0 | 188 | let json = { foo: "bar" }; |
michael@0 | 189 | let basename = "test-request.json"; |
michael@0 | 190 | prepareFile(basename, JSON.stringify(json)); |
michael@0 | 191 | |
michael@0 | 192 | runMultipleURLs(srv, assert, done, { |
michael@0 | 193 | url: "http://localhost:" + port + "/" + basename, |
michael@0 | 194 | onComplete: function (response) { |
michael@0 | 195 | assert.deepEqual(response.json, json); |
michael@0 | 196 | } |
michael@0 | 197 | }); |
michael@0 | 198 | }; |
michael@0 | 199 | |
michael@0 | 200 | exports.testInvalidJSON = function (assert, done) { |
michael@0 | 201 | let srv = startServerAsync(port, basePath); |
michael@0 | 202 | let basename = "test-request-invalid.json"; |
michael@0 | 203 | prepareFile(basename, '"this": "isn\'t JSON"'); |
michael@0 | 204 | |
michael@0 | 205 | runMultipleURLs(srv, assert, done, { |
michael@0 | 206 | url: "http://localhost:" + port + "/" + basename, |
michael@0 | 207 | onComplete: function (response) { |
michael@0 | 208 | assert.equal(response.json, null); |
michael@0 | 209 | } |
michael@0 | 210 | }); |
michael@0 | 211 | }; |
michael@0 | 212 | |
michael@0 | 213 | exports.testDelete = function (assert, done) { |
michael@0 | 214 | let srv = startServerAsync(port, basePath); |
michael@0 | 215 | |
michael@0 | 216 | srv.registerPathHandler("/test-delete", |
michael@0 | 217 | function handle(request, response) { |
michael@0 | 218 | response.setHeader("Content-Type", "text/plain", false); |
michael@0 | 219 | }); |
michael@0 | 220 | |
michael@0 | 221 | Request({ |
michael@0 | 222 | url: "http://localhost:" + port + "/test-delete", |
michael@0 | 223 | onComplete: function (response) { |
michael@0 | 224 | // We cannot access the METHOD of the request to verify it's set |
michael@0 | 225 | // correctly. |
michael@0 | 226 | assert.equal(response.text, ""); |
michael@0 | 227 | assert.equal(response.statusText, "OK"); |
michael@0 | 228 | assert.equal(response.headers["Content-Type"], "text/plain"); |
michael@0 | 229 | srv.stop(done); |
michael@0 | 230 | } |
michael@0 | 231 | }).delete(); |
michael@0 | 232 | }; |
michael@0 | 233 | |
michael@0 | 234 | exports.testHead = function (assert, done) { |
michael@0 | 235 | let srv = startServerAsync(port, basePath); |
michael@0 | 236 | |
michael@0 | 237 | srv.registerPathHandler("/test-head", |
michael@0 | 238 | function handle(request, response) { |
michael@0 | 239 | response.setHeader("Content-Type", "text/plain", false); |
michael@0 | 240 | }); |
michael@0 | 241 | |
michael@0 | 242 | Request({ |
michael@0 | 243 | url: "http://localhost:" + port + "/test-head", |
michael@0 | 244 | onComplete: function (response) { |
michael@0 | 245 | assert.equal(response.text, ""); |
michael@0 | 246 | assert.equal(response.statusText, "OK"); |
michael@0 | 247 | assert.equal(response.headers["Content-Type"], "text/plain"); |
michael@0 | 248 | srv.stop(done); |
michael@0 | 249 | } |
michael@0 | 250 | }).head(); |
michael@0 | 251 | }; |
michael@0 | 252 | |
michael@0 | 253 | function runMultipleURLs (srv, assert, done, options) { |
michael@0 | 254 | let urls = [options.url, URL(options.url)]; |
michael@0 | 255 | let cb = options.onComplete; |
michael@0 | 256 | let ran = 0; |
michael@0 | 257 | let onComplete = function (res) { |
michael@0 | 258 | cb(res); |
michael@0 | 259 | if (++ran === urls.length) |
michael@0 | 260 | srv ? srv.stop(done) : done(); |
michael@0 | 261 | }; |
michael@0 | 262 | urls.forEach(function (url) { |
michael@0 | 263 | Request(extend(options, { url: url, onComplete: onComplete })).get(); |
michael@0 | 264 | }); |
michael@0 | 265 | } |
michael@0 | 266 | |
michael@0 | 267 | // All tests below here require a network connection. They will be commented out |
michael@0 | 268 | // when checked in. If you'd like to run them, simply uncomment them. |
michael@0 | 269 | // |
michael@0 | 270 | // When we have the means, these tests will be converted so that they don't |
michael@0 | 271 | // require an external server nor a network connection. |
michael@0 | 272 | |
michael@0 | 273 | /* |
michael@0 | 274 | exports.testGetWithParamsNotContent = function (assert, done) { |
michael@0 | 275 | Request({ |
michael@0 | 276 | url: "http://playground.zpao.com/jetpack/request/getpost.php?foo=bar", |
michael@0 | 277 | onComplete: function (response) { |
michael@0 | 278 | let expected = { |
michael@0 | 279 | "POST": [], |
michael@0 | 280 | "GET" : { foo: "bar" } |
michael@0 | 281 | }; |
michael@0 | 282 | assert.deepEqual(response.json, expected); |
michael@0 | 283 | done(); |
michael@0 | 284 | } |
michael@0 | 285 | }).get(); |
michael@0 | 286 | } |
michael@0 | 287 | |
michael@0 | 288 | exports.testGetWithContent = function (assert, done) { |
michael@0 | 289 | Request({ |
michael@0 | 290 | url: "http://playground.zpao.com/jetpack/request/getpost.php", |
michael@0 | 291 | content: { foo: "bar" }, |
michael@0 | 292 | onComplete: function (response) { |
michael@0 | 293 | let expected = { |
michael@0 | 294 | "POST": [], |
michael@0 | 295 | "GET" : { foo: "bar" } |
michael@0 | 296 | }; |
michael@0 | 297 | assert.deepEqual(response.json, expected); |
michael@0 | 298 | done(); |
michael@0 | 299 | } |
michael@0 | 300 | }).get(); |
michael@0 | 301 | } |
michael@0 | 302 | |
michael@0 | 303 | exports.testGetWithParamsAndContent = function (assert, done) { |
michael@0 | 304 | Request({ |
michael@0 | 305 | url: "http://playground.zpao.com/jetpack/request/getpost.php?foo=bar", |
michael@0 | 306 | content: { baz: "foo" }, |
michael@0 | 307 | onComplete: function (response) { |
michael@0 | 308 | let expected = { |
michael@0 | 309 | "POST": [], |
michael@0 | 310 | "GET" : { foo: "bar", baz: "foo" } |
michael@0 | 311 | }; |
michael@0 | 312 | assert.deepEqual(response.json, expected); |
michael@0 | 313 | done(); |
michael@0 | 314 | } |
michael@0 | 315 | }).get(); |
michael@0 | 316 | } |
michael@0 | 317 | |
michael@0 | 318 | exports.testSimplePost = function (assert, done) { |
michael@0 | 319 | Request({ |
michael@0 | 320 | url: "http://playground.zpao.com/jetpack/request/getpost.php", |
michael@0 | 321 | content: { foo: "bar" }, |
michael@0 | 322 | onComplete: function (response) { |
michael@0 | 323 | let expected = { |
michael@0 | 324 | "POST": { foo: "bar" }, |
michael@0 | 325 | "GET" : [] |
michael@0 | 326 | }; |
michael@0 | 327 | assert.deepEqual(response.json, expected); |
michael@0 | 328 | done(); |
michael@0 | 329 | } |
michael@0 | 330 | }).post(); |
michael@0 | 331 | } |
michael@0 | 332 | |
michael@0 | 333 | exports.testEncodedContent = function (assert, done) { |
michael@0 | 334 | Request({ |
michael@0 | 335 | url: "http://playground.zpao.com/jetpack/request/getpost.php", |
michael@0 | 336 | content: "foo=bar&baz=foo", |
michael@0 | 337 | onComplete: function (response) { |
michael@0 | 338 | let expected = { |
michael@0 | 339 | "POST": [], |
michael@0 | 340 | "GET" : { foo: "bar", baz: "foo" } |
michael@0 | 341 | }; |
michael@0 | 342 | assert.deepEqual(response.json, expected); |
michael@0 | 343 | done(); |
michael@0 | 344 | } |
michael@0 | 345 | }).get(); |
michael@0 | 346 | } |
michael@0 | 347 | |
michael@0 | 348 | exports.testEncodedContentWithSpaces = function (assert, done) { |
michael@0 | 349 | Request({ |
michael@0 | 350 | url: "http://playground.zpao.com/jetpack/request/getpost.php", |
michael@0 | 351 | content: "foo=bar+hop!&baz=foo", |
michael@0 | 352 | onComplete: function (response) { |
michael@0 | 353 | let expected = { |
michael@0 | 354 | "POST": [], |
michael@0 | 355 | "GET" : { foo: "bar hop!", baz: "foo" } |
michael@0 | 356 | }; |
michael@0 | 357 | assert.deepEqual(response.json, expected); |
michael@0 | 358 | done(); |
michael@0 | 359 | } |
michael@0 | 360 | }).get(); |
michael@0 | 361 | } |
michael@0 | 362 | |
michael@0 | 363 | exports.testGetWithArray = function (assert, done) { |
michael@0 | 364 | Request({ |
michael@0 | 365 | url: "http://playground.zpao.com/jetpack/request/getpost.php", |
michael@0 | 366 | content: { foo: [1, 2], baz: "foo" }, |
michael@0 | 367 | onComplete: function (response) { |
michael@0 | 368 | let expected = { |
michael@0 | 369 | "POST": [], |
michael@0 | 370 | "GET" : { foo: [1, 2], baz: "foo" } |
michael@0 | 371 | }; |
michael@0 | 372 | assert.deepEqual(response.json, expected); |
michael@0 | 373 | done(); |
michael@0 | 374 | } |
michael@0 | 375 | }).get(); |
michael@0 | 376 | } |
michael@0 | 377 | |
michael@0 | 378 | exports.testGetWithNestedArray = function (assert, done) { |
michael@0 | 379 | Request({ |
michael@0 | 380 | url: "http://playground.zpao.com/jetpack/request/getpost.php", |
michael@0 | 381 | content: { foo: [1, 2, [3, 4]], bar: "baz" }, |
michael@0 | 382 | onComplete: function (response) { |
michael@0 | 383 | let expected = { |
michael@0 | 384 | "POST": [], |
michael@0 | 385 | "GET" : this.content |
michael@0 | 386 | }; |
michael@0 | 387 | assert.deepEqual(response.json, expected); |
michael@0 | 388 | done(); |
michael@0 | 389 | } |
michael@0 | 390 | }).get(); |
michael@0 | 391 | } |
michael@0 | 392 | |
michael@0 | 393 | exports.testGetWithNestedArray = function (assert, done) { |
michael@0 | 394 | let request = Request({ |
michael@0 | 395 | url: "http://playground.zpao.com/jetpack/request/getpost.php", |
michael@0 | 396 | content: { |
michael@0 | 397 | foo: [1, 2, { |
michael@0 | 398 | omg: "bbq", |
michael@0 | 399 | "all your base!": "are belong to us" |
michael@0 | 400 | }], |
michael@0 | 401 | bar: "baz" |
michael@0 | 402 | }, |
michael@0 | 403 | onComplete: function (response) { |
michael@0 | 404 | let expected = { |
michael@0 | 405 | "POST": [], |
michael@0 | 406 | "GET" : request.content |
michael@0 | 407 | }; |
michael@0 | 408 | assert.deepEqual(response.json, expected); |
michael@0 | 409 | done(); |
michael@0 | 410 | } |
michael@0 | 411 | }).get(); |
michael@0 | 412 | } |
michael@0 | 413 | */ |
michael@0 | 414 | |
michael@0 | 415 | function prepareFile(basename, content) { |
michael@0 | 416 | let filePath = file.join(basePath, basename); |
michael@0 | 417 | let fileStream = file.open(filePath, 'w'); |
michael@0 | 418 | fileStream.write(content); |
michael@0 | 419 | fileStream.close(); |
michael@0 | 420 | } |
michael@0 | 421 | |
michael@0 | 422 | // Helper function for testComplexHeaders |
michael@0 | 423 | function handleRequest(request, response) { |
michael@0 | 424 | // Test header with an extra colon |
michael@0 | 425 | response.setHeader("x-jetpack-header", "Jamba Juice is: delicious", "true"); |
michael@0 | 426 | |
michael@0 | 427 | // Test that multiple headers with the same name coalesce |
michael@0 | 428 | response.setHeader("x-jetpack-header-2", "foo", "true"); |
michael@0 | 429 | response.setHeader("x-jetpack-header-2", "bar", "true"); |
michael@0 | 430 | |
michael@0 | 431 | // Test that headers with commas work |
michael@0 | 432 | response.setHeader("x-jetpack-header-3", "sup dawg, i heard you like x, " + |
michael@0 | 433 | "so we put a x in yo x so you can y while you y", "true"); |
michael@0 | 434 | |
michael@0 | 435 | // Test that multiple cookies work |
michael@0 | 436 | response.setHeader("Set-Cookie", "foo=bar", "true"); |
michael@0 | 437 | response.setHeader("Set-Cookie", "baz=foo", "true"); |
michael@0 | 438 | |
michael@0 | 439 | response.write("<html><body>This file tests more complex headers.</body></html>"); |
michael@0 | 440 | } |
michael@0 | 441 | |
michael@0 | 442 | require('sdk/test').run(exports); |