summaryrefslogtreecommitdiffstats
path: root/addon-sdk/source/test/test-request.js
blob: 3c65d768495ed343773f10b8420a128de79c49cb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

const { Request } = require("sdk/request");
const { pathFor } = require("sdk/system");
const file = require("sdk/io/file");
const { URL } = require("sdk/url");
const { extend } = require("sdk/util/object");
const { Loader } = require("sdk/test/loader");
const options = require("sdk/test/options");

const loader = Loader(module);
const httpd = loader.require("./lib/httpd");
if (options.parseable || options.verbose)
  loader.sandbox("./lib/httpd").DEBUG = true;
const { startServerAsync } = httpd;

const { Cc, Ci, Cu } = require("chrome");
const { Services } = Cu.import("resource://gre/modules/Services.jsm");

// Use the profile directory for the temporary files as that will be deleted
// when tests are complete
const basePath = pathFor("ProfD");
const port = 8099;


exports.testOptionsValidator = function(assert) {
  // First, a simple test to make sure we didn't break normal functionality.
  assert.throws(function () {
    Request({
      url: null
    });
  }, /The option "url" is invalid./);

  // Next we'll have a Request that doesn't throw from c'tor, but from a setter.
  let req = Request({
    url: "http://playground.zpao.com/jetpack/request/text.php",
    onComplete: function () {}
  });
  assert.throws(function () {
    req.url = 'www.mozilla.org';
  }, /The option "url" is invalid/);
  // The url shouldn't have changed, so check that
  assert.equal(req.url, "http://playground.zpao.com/jetpack/request/text.php");

  // Test default anonymous parameter value
  assert.equal(req.anonymous, false);
  // Test set anonymous parameter value
  req = Request({
    url: "http://playground.zpao.com/jetpack/request/text.php",
    anonymous: true,
    onComplete: function () {}
  });
  assert.equal(req.anonymous, true);
  // Test wrong value as anonymous parameter value
  assert.throws(function() {
    Request({
      url: "http://playground.zpao.com/jetpack/request/text.php",
      anonymous: "invalidvalue"
    });
  }, /The option "anonymous" must be one of the following types/);
};

exports.testContentValidator = function(assert, done) {
  runMultipleURLs(null, assert, done, {
    url: "data:text/html;charset=utf-8,response",
    content: { 'key1' : null, 'key2' : 'some value' },
    onComplete: function(response) {
      assert.equal(response.text, "response?key1=null&key2=some+value");
    }
  });
};

// This is a request to a file that exists.
exports.testStatus200 = function (assert, done) {
  let srv = startServerAsync(port, basePath);
  let content = "Look ma, no hands!\n";
  let basename = "test-request.txt"
  let requestURL = "http://localhost:" + port + "/" + basename;

  prepareFile(basename, content);

  var req = Request({
    url: requestURL,
    onComplete: function (response) {
      assert.equal(this, req, "`this` should be request");
      assert.equal(response.status, 200);
      assert.equal(response.statusText, "OK");
      assert.equal(response.headers["Content-Type"], "text/plain");
      assert.equal(response.text, content);
      assert.strictEqual(response.url, requestURL);
      srv.stop(done);
    }
  }).get();
};

// Should return the location to which have been automatically redirected
exports.testRedirection = function (assert, done) {
  let srv = startServerAsync(port, basePath);
  
  let moveLocation = "test-request-302-located.txt";
  let movedContent = "here now\n";
  let movedUrl = "http://localhost:" + port + "/" + moveLocation;
  prepareFile(moveLocation, movedContent);

  let content = "The document has moved!\n";
  let contentHeaders = "HTTP 302 Found\nLocation: "+moveLocation+"\n";
  let basename = "test-request-302.txt"
  let requestURL = "http://localhost:" + port + "/" + basename;
  prepareFile(basename, content);
  prepareFile(basename+"^headers^", contentHeaders);

  var req = Request({
    url: requestURL,
    onComplete: function (response) {
      assert.equal(this, req, "`this` should be request");
      assert.equal(response.status, 200);
      assert.equal(response.statusText, "OK");
      assert.equal(response.headers["Content-Type"], "text/plain");
      assert.equal(response.text, movedContent);
      assert.strictEqual(response.url, movedUrl);
      srv.stop(done);
    }
  }).get();
};

// This tries to get a file that doesn't exist
exports.testStatus404 = function (assert, done) {
  var srv = startServerAsync(port, basePath);
  let requestURL = "http://localhost:" + port + "/test-request-404.txt";

  runMultipleURLs(srv, assert, done, {
    // the following URL doesn't exist
    url: requestURL,
    onComplete: function (response) {
      assert.equal(response.status, 404);
      assert.equal(response.statusText, "Not Found");
      assert.strictEqual(response.url, requestURL);
    }
  });
};

// a simple file with a known header
exports.testKnownHeader = function (assert, done) {
  var srv = startServerAsync(port, basePath);

 // Create the file that will be requested with the associated headers file
  let content = "This tests adding headers to the server's response.\n";
  let basename = "test-request-headers.txt";
  let headerContent = "x-jetpack-header: Jamba Juice\n";
  let headerBasename = "test-request-headers.txt^headers^";
  prepareFile(basename, content);
  prepareFile(headerBasename, headerContent);

  runMultipleURLs(srv, assert, done, {
    url: "http://localhost:" + port + "/test-request-headers.txt",
    onComplete: function (response) {
      assert.equal(response.headers["x-jetpack-header"], "Jamba Juice");
    }
  });
};

// complex headers
exports.testComplexHeader = function (assert, done) {
  let srv = startServerAsync(port, basePath);

  let basename = "test-request-complex-headers.sjs";
  let content = handleRequest.toString();
  prepareFile(basename, content);

  let headers = {
    "x-jetpack-header": "Jamba Juice is: delicious",
    "x-jetpack-header-2": "foo,bar",
    "x-jetpack-header-3": "sup dawg, i heard you like x, so we put a x in " +
      "yo x so you can y while you y",
    "Set-Cookie": "foo=bar\nbaz=foo"
  };

  runMultipleURLs(srv, assert, done, {
    url: "http://localhost:" + port + "/test-request-complex-headers.sjs",
    onComplete: function (response) {
      for (k in headers) {
        assert.equal(response.headers[k], headers[k]);
      }
    }
  });
};

// Force Allow Third Party cookies
exports.test3rdPartyCookies = function (assert, done) {
  let srv = startServerAsync(port, basePath);

  let basename = "test-request-3rd-party-cookies.sjs";

  // Function to handle the requests in the server
  let content = function handleRequest(request, response) {
    var cookiePresent = request.hasHeader("Cookie");
    // If no cookie, set it
    if(!cookiePresent) {
      response.setHeader("Set-Cookie", "cookie=monster;", "true");
      response.setHeader("x-jetpack-3rd-party", "false", "true");
    } else {
      // We got the cookie, say so
      response.setHeader("x-jetpack-3rd-party", "true", "true");
    }

    response.write("<html><body>This tests 3rd party cookies.</body></html>");
  }.toString();

  prepareFile(basename, content);

  // Disable the 3rd party cookies
  Services.prefs.setIntPref("network.cookie.cookieBehavior", 1);

  Request({
    url: "http://localhost:" + port + "/test-request-3rd-party-cookies.sjs",
    onComplete: function (response) {
      // Check that the server created the cookie
      assert.equal(response.headers['Set-Cookie'], 'cookie=monster;');

      // Check it wasn't there before
      assert.equal(response.headers['x-jetpack-3rd-party'], 'false');

      // Make a second request, and check that the server this time
      // got the cookie
      Request({
        url: "http://localhost:" + port + "/test-request-3rd-party-cookies.sjs",
        onComplete: function (response) {
          assert.equal(response.headers['x-jetpack-3rd-party'], 'true');
          srv.stop(done);
        }
      }).get();
    }
  }).get();
};

// Test anonymous request behavior
exports.testAnonymousRequest = function(assert, done) {
  let srv = startServerAsync(port, basePath);
  let basename = "test-anonymous-request.sjs";
  let testUrl = "http://localhost:" + port + "/" + basename;
  // Function to handle the requests in the server
  let content = function handleRequest(request, response) {
    // Request to store cookie
    response.setHeader("Set-Cookie", "anonymousKey=anonymousValue;", "true");
    // Set response content type
    response.setHeader("Content-Type", "application/json");
    // Check if cookie was send during request
    var cookiePresent = request.hasHeader("Cookie");
    // Create server respone content
    response.write(JSON.stringify({ "hasCookie": cookiePresent }));
  }.toString();
  prepareFile(basename, content);
  // Create request callbacks
  var checkCookieCreated = function (response) {
    // Check that the server created the cookie
    assert.equal(response.headers['Set-Cookie'], 'anonymousKey=anonymousValue;');
    // Make an other request and check that the server this time got the cookie
    Request({
      url: testUrl,
      onComplete: checkCookieSend
    }).get();
  },
  checkCookieSend = function (response) {
    // Check the response sent headers and cookies
    assert.equal(response.anonymous, false);
    // Check the server got the created cookie
    assert.equal(response.json.hasCookie, true);
    // Make a anonymous request and check the server did not get the cookie
    Request({
      url: testUrl,
      anonymous: true,
      onComplete: checkCookieNotSend
    }).get();
  },
  checkCookieNotSend = function (response) {
    // Check the response is anonymous
    assert.equal(response.anonymous, true);
    // Check the server did not get the cookie
    assert.equal(response.json.hasCookie, false);
    // Stop the server
    srv.stop(done);
  };
  // Make the first request to create cookie
  Request({
    url: testUrl,
    onComplete: checkCookieCreated
  }).get();
};

exports.testSimpleJSON = function (assert, done) {
  let srv = startServerAsync(port, basePath);
  let json = { foo: "bar" };
  let basename = "test-request.json";
  prepareFile(basename, JSON.stringify(json));

  runMultipleURLs(srv, assert, done, {
    url: "http://localhost:" + port + "/" + basename,
    onComplete: function (response) {
      assert.deepEqual(response.json, json);
    }
  });
};

exports.testInvalidJSON = function (assert, done) {
  let srv = startServerAsync(port, basePath);
  let basename = "test-request-invalid.json";
  prepareFile(basename, '"this": "isn\'t JSON"');

  runMultipleURLs(srv, assert, done, {
    url: "http://localhost:" + port + "/" + basename,
    onComplete: function (response) {
      assert.equal(response.json, null);
    }
  });
};

exports.testDelete = function (assert, done) {
  let srv = startServerAsync(port, basePath);

  srv.registerPathHandler("/test-delete",
      function handle(request, response) {
    response.setHeader("Content-Type", "text/plain", false);
  });

  Request({
    url: "http://localhost:" + port + "/test-delete",
    onComplete: function (response) {
      // We cannot access the METHOD of the request to verify it's set
      // correctly.
      assert.equal(response.text, "");
      assert.equal(response.statusText, "OK");
      assert.equal(response.headers["Content-Type"], "text/plain");
      srv.stop(done);
    }
  }).delete();
};

exports.testHead = function (assert, done) {
  let srv = startServerAsync(port, basePath);

  srv.registerPathHandler("/test-head",
      function handle(request, response) {
    response.setHeader("Content-Type", "text/plain", false);
  });

  Request({
    url: "http://localhost:" + port + "/test-head",
    onComplete: function (response) {
      assert.equal(response.text, "");
      assert.equal(response.statusText, "OK");
      assert.equal(response.headers["Content-Type"], "text/plain");
      srv.stop(done);
    }
  }).head();
};

function runMultipleURLs (srv, assert, done, options) {
  let urls = [options.url, URL(options.url)];
  let cb = options.onComplete;
  let ran = 0;
  let onComplete = function (res) {
    cb(res);
    if (++ran === urls.length)
      srv ? srv.stop(done) : done();
  };
  urls.forEach(function (url) {
    Request(extend(options, { url: url, onComplete: onComplete })).get();
  });
}

// All tests below here require a network connection. They will be commented out
// when checked in. If you'd like to run them, simply uncomment them.
//
// When we have the means, these tests will be converted so that they don't
// require an external server nor a network connection.

/*
exports.testGetWithParamsNotContent = function (assert, done) {
  Request({
    url: "http://playground.zpao.com/jetpack/request/getpost.php?foo=bar",
    onComplete: function (response) {
      let expected = {
        "POST": [],
        "GET" : { foo: "bar" }
      };
      assert.deepEqual(response.json, expected);
      done();
    }
  }).get();
}

exports.testGetWithContent = function (assert, done) {
  Request({
    url: "http://playground.zpao.com/jetpack/request/getpost.php",
    content: { foo: "bar" },
    onComplete: function (response) {
      let expected = {
        "POST": [],
        "GET" : { foo: "bar" }
      };
      assert.deepEqual(response.json, expected);
      done();
    }
  }).get();
}

exports.testGetWithParamsAndContent = function (assert, done) {
  Request({
    url: "http://playground.zpao.com/jetpack/request/getpost.php?foo=bar",
    content: { baz: "foo" },
    onComplete: function (response) {
      let expected = {
        "POST": [],
        "GET" : { foo: "bar", baz: "foo" }
      };
      assert.deepEqual(response.json, expected);
      done();
    }
  }).get();
}

exports.testSimplePost = function (assert, done) {
  Request({
    url: "http://playground.zpao.com/jetpack/request/getpost.php",
    content: { foo: "bar" },
    onComplete: function (response) {
      let expected = {
        "POST": { foo: "bar" },
        "GET" : []
      };
      assert.deepEqual(response.json, expected);
      done();
    }
  }).post();
}

exports.testEncodedContent = function (assert, done) {
  Request({
    url: "http://playground.zpao.com/jetpack/request/getpost.php",
    content: "foo=bar&baz=foo",
    onComplete: function (response) {
      let expected = {
        "POST": [],
        "GET" : { foo: "bar", baz: "foo" }
      };
      assert.deepEqual(response.json, expected);
      done();
    }
  }).get();
}

exports.testEncodedContentWithSpaces = function (assert, done) {
  Request({
    url: "http://playground.zpao.com/jetpack/request/getpost.php",
    content: "foo=bar+hop!&baz=foo",
    onComplete: function (response) {
      let expected = {
        "POST": [],
        "GET" : { foo: "bar hop!", baz: "foo" }
      };
      assert.deepEqual(response.json, expected);
      done();
    }
  }).get();
}

exports.testGetWithArray = function (assert, done) {
  Request({
    url: "http://playground.zpao.com/jetpack/request/getpost.php",
    content: { foo: [1, 2], baz: "foo" },
    onComplete: function (response) {
      let expected = {
        "POST": [],
        "GET" : { foo: [1, 2], baz: "foo" }
      };
      assert.deepEqual(response.json, expected);
      done();
    }
  }).get();
}

exports.testGetWithNestedArray = function (assert, done) {
  Request({
    url: "http://playground.zpao.com/jetpack/request/getpost.php",
    content: { foo: [1, 2, [3, 4]], bar: "baz" },
    onComplete: function (response) {
      let expected = {
        "POST": [],
        "GET" : this.content
      };
      assert.deepEqual(response.json, expected);
      done();
    }
  }).get();
}

exports.testGetWithNestedArray = function (assert, done) {
  let request = Request({
    url: "http://playground.zpao.com/jetpack/request/getpost.php",
    content: {
      foo: [1, 2, {
        omg: "bbq",
        "all your base!": "are belong to us"
      }],
      bar: "baz"
    },
    onComplete: function (response) {
      let expected = {
        "POST": [],
        "GET" : request.content
      };
      assert.deepEqual(response.json, expected);
      done();
    }
  }).get();
}
*/

function prepareFile(basename, content) {
  let filePath = file.join(basePath, basename);
  let fileStream = file.open(filePath, 'w');
  fileStream.write(content);
  fileStream.close();
}

// Helper function for testComplexHeaders
function handleRequest(request, response) {
  // Test header with an extra colon
  response.setHeader("x-jetpack-header", "Jamba Juice is: delicious", "true");

  // Test that multiple headers with the same name coalesce
  response.setHeader("x-jetpack-header-2", "foo", "true");
  response.setHeader("x-jetpack-header-2", "bar", "true");

  // Test that headers with commas work
  response.setHeader("x-jetpack-header-3", "sup dawg, i heard you like x, " +
    "so we put a x in yo x so you can y while you y", "true");

  // Test that multiple cookies work
  response.setHeader("Set-Cookie", "foo=bar", "true");
  response.setHeader("Set-Cookie", "baz=foo", "true");

  response.write("<html><body>This file tests more complex headers.</body></html>");
}

require('sdk/test').run(exports);