test-request.js 13 KB

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