|
1 /* Any copyright is dedicated to the Public Domain. |
|
2 http://creativecommons.org/publicdomain/zero/1.0/ */ |
|
3 |
|
4 "use strict"; |
|
5 |
|
6 Cu.import("resource://gre/modules/NetUtil.jsm"); |
|
7 Cu.import("resource://gre/modules/Log.jsm"); |
|
8 Cu.import("resource://services-common/rest.js"); |
|
9 Cu.import("resource://services-common/utils.js"); |
|
10 |
|
11 function run_test() { |
|
12 Log.repository.getLogger("Services.Common.RESTRequest").level = |
|
13 Log.Level.Trace; |
|
14 initTestLogging("Trace"); |
|
15 |
|
16 run_next_test(); |
|
17 } |
|
18 |
|
19 /** |
|
20 * Initializing a RESTRequest with an invalid URI throws |
|
21 * NS_ERROR_MALFORMED_URI. |
|
22 */ |
|
23 add_test(function test_invalid_uri() { |
|
24 do_check_throws(function() { |
|
25 new RESTRequest("an invalid URI"); |
|
26 }, Cr.NS_ERROR_MALFORMED_URI); |
|
27 run_next_test(); |
|
28 }); |
|
29 |
|
30 /** |
|
31 * Verify initial values for attributes. |
|
32 */ |
|
33 add_test(function test_attributes() { |
|
34 let uri = "http://foo.com/bar/baz"; |
|
35 let request = new RESTRequest(uri); |
|
36 |
|
37 do_check_true(request.uri instanceof Ci.nsIURI); |
|
38 do_check_eq(request.uri.spec, uri); |
|
39 do_check_eq(request.response, null); |
|
40 do_check_eq(request.status, request.NOT_SENT); |
|
41 let expectedLoadFlags = Ci.nsIRequest.LOAD_BYPASS_CACHE | |
|
42 Ci.nsIRequest.INHIBIT_CACHING | |
|
43 Ci.nsIRequest.LOAD_ANONYMOUS; |
|
44 do_check_eq(request.loadFlags, expectedLoadFlags); |
|
45 |
|
46 run_next_test(); |
|
47 }); |
|
48 |
|
49 /** |
|
50 * Verify that a proxy auth redirect doesn't break us. This has to be the first |
|
51 * request made in the file! |
|
52 */ |
|
53 add_test(function test_proxy_auth_redirect() { |
|
54 let pacFetched = false; |
|
55 function pacHandler(metadata, response) { |
|
56 pacFetched = true; |
|
57 let body = 'function FindProxyForURL(url, host) { return "DIRECT"; }'; |
|
58 response.setStatusLine(metadata.httpVersion, 200, "OK"); |
|
59 response.setHeader("Content-Type", "application/x-ns-proxy-autoconfig", false); |
|
60 response.bodyOutputStream.write(body, body.length); |
|
61 } |
|
62 |
|
63 let fetched = false; |
|
64 function original(metadata, response) { |
|
65 fetched = true; |
|
66 let body = "TADA!"; |
|
67 response.setStatusLine(metadata.httpVersion, 200, "OK"); |
|
68 response.bodyOutputStream.write(body, body.length); |
|
69 } |
|
70 |
|
71 let server = httpd_setup({ |
|
72 "/original": original, |
|
73 "/pac3": pacHandler |
|
74 }); |
|
75 PACSystemSettings.PACURI = server.baseURI + "/pac3"; |
|
76 installFakePAC(); |
|
77 |
|
78 let res = new RESTRequest(server.baseURI + "/original"); |
|
79 res.get(function (error) { |
|
80 do_check_true(pacFetched); |
|
81 do_check_true(fetched); |
|
82 do_check_true(!error); |
|
83 do_check_true(this.response.success); |
|
84 do_check_eq("TADA!", this.response.body); |
|
85 uninstallFakePAC(); |
|
86 server.stop(run_next_test); |
|
87 }); |
|
88 }); |
|
89 |
|
90 /** |
|
91 * Ensure that failures that cause asyncOpen to throw |
|
92 * result in callbacks being invoked. |
|
93 * Bug 826086. |
|
94 */ |
|
95 add_test(function test_forbidden_port() { |
|
96 let request = new RESTRequest("http://localhost:6000/"); |
|
97 request.get(function(error) { |
|
98 if (!error) { |
|
99 do_throw("Should have got an error."); |
|
100 } |
|
101 do_check_eq(error.result, Components.results.NS_ERROR_PORT_ACCESS_NOT_ALLOWED); |
|
102 run_next_test(); |
|
103 }); |
|
104 }); |
|
105 |
|
106 /** |
|
107 * Demonstrate API short-hand: create a request and dispatch it immediately. |
|
108 */ |
|
109 add_test(function test_simple_get() { |
|
110 let handler = httpd_handler(200, "OK", "Huzzah!"); |
|
111 let server = httpd_setup({"/resource": handler}); |
|
112 |
|
113 let request = new RESTRequest(server.baseURI + "/resource").get(function (error) { |
|
114 do_check_eq(error, null); |
|
115 |
|
116 do_check_eq(this.status, this.COMPLETED); |
|
117 do_check_true(this.response.success); |
|
118 do_check_eq(this.response.status, 200); |
|
119 do_check_eq(this.response.body, "Huzzah!"); |
|
120 |
|
121 server.stop(run_next_test); |
|
122 }); |
|
123 do_check_eq(request.status, request.SENT); |
|
124 do_check_eq(request.method, "GET"); |
|
125 }); |
|
126 |
|
127 /** |
|
128 * Test HTTP GET with all bells and whistles. |
|
129 */ |
|
130 add_test(function test_get() { |
|
131 let handler = httpd_handler(200, "OK", "Huzzah!"); |
|
132 let server = httpd_setup({"/resource": handler}); |
|
133 |
|
134 let request = new RESTRequest(server.baseURI + "/resource"); |
|
135 do_check_eq(request.status, request.NOT_SENT); |
|
136 |
|
137 request.onProgress = request.onComplete = function () { |
|
138 do_throw("This function should have been overwritten!"); |
|
139 }; |
|
140 |
|
141 let onProgress_called = false; |
|
142 function onProgress() { |
|
143 onProgress_called = true; |
|
144 do_check_eq(this.status, request.IN_PROGRESS); |
|
145 do_check_true(this.response.body.length > 0); |
|
146 |
|
147 do_check_true(!!(this.channel.loadFlags & Ci.nsIRequest.LOAD_BYPASS_CACHE)); |
|
148 do_check_true(!!(this.channel.loadFlags & Ci.nsIRequest.INHIBIT_CACHING)); |
|
149 }; |
|
150 |
|
151 function onComplete(error) { |
|
152 do_check_eq(error, null); |
|
153 |
|
154 do_check_eq(this.status, this.COMPLETED); |
|
155 do_check_true(this.response.success); |
|
156 do_check_eq(this.response.status, 200); |
|
157 do_check_eq(this.response.body, "Huzzah!"); |
|
158 do_check_eq(handler.request.method, "GET"); |
|
159 |
|
160 do_check_true(onProgress_called); |
|
161 CommonUtils.nextTick(function () { |
|
162 do_check_eq(request.onComplete, null); |
|
163 do_check_eq(request.onProgress, null); |
|
164 server.stop(run_next_test); |
|
165 }); |
|
166 }; |
|
167 |
|
168 do_check_eq(request.get(onComplete, onProgress), request); |
|
169 do_check_eq(request.status, request.SENT); |
|
170 do_check_eq(request.method, "GET"); |
|
171 do_check_throws(function () { |
|
172 request.get(); |
|
173 }); |
|
174 }); |
|
175 |
|
176 /** |
|
177 * Test HTTP GET with UTF-8 content, and custom Content-Type. |
|
178 */ |
|
179 add_test(function test_get_utf8() { |
|
180 let response = "Hello World or Καλημέρα κόσμε or こんにちは 世界"; |
|
181 |
|
182 let contentType = "text/plain"; |
|
183 let charset = true; |
|
184 let charsetSuffix = "; charset=UTF-8"; |
|
185 |
|
186 let server = httpd_setup({"/resource": function(req, res) { |
|
187 res.setStatusLine(req.httpVersion, 200, "OK"); |
|
188 res.setHeader("Content-Type", contentType + (charset ? charsetSuffix : "")); |
|
189 |
|
190 let converter = Cc["@mozilla.org/intl/converter-output-stream;1"] |
|
191 .createInstance(Ci.nsIConverterOutputStream); |
|
192 converter.init(res.bodyOutputStream, "UTF-8", 0, 0x0000); |
|
193 converter.writeString(response); |
|
194 converter.close(); |
|
195 }}); |
|
196 |
|
197 // Check if charset in Content-Type is propertly interpreted. |
|
198 let request1 = new RESTRequest(server.baseURI + "/resource"); |
|
199 request1.get(function(error) { |
|
200 do_check_null(error); |
|
201 |
|
202 do_check_eq(request1.response.status, 200); |
|
203 do_check_eq(request1.response.body, response); |
|
204 do_check_eq(request1.response.headers["content-type"], |
|
205 contentType + charsetSuffix); |
|
206 |
|
207 // Check that we default to UTF-8 if Content-Type doesn't have a charset. |
|
208 charset = false; |
|
209 let request2 = new RESTRequest(server.baseURI + "/resource"); |
|
210 request2.get(function(error) { |
|
211 do_check_null(error); |
|
212 |
|
213 do_check_eq(request2.response.status, 200); |
|
214 do_check_eq(request2.response.body, response); |
|
215 do_check_eq(request2.response.headers["content-type"], contentType); |
|
216 do_check_eq(request2.response.charset, "utf-8"); |
|
217 |
|
218 server.stop(run_next_test); |
|
219 }); |
|
220 }); |
|
221 }); |
|
222 |
|
223 /** |
|
224 * Test more variations of charset handling. |
|
225 */ |
|
226 add_test(function test_charsets() { |
|
227 let response = "Hello World, I can't speak Russian"; |
|
228 |
|
229 let contentType = "text/plain"; |
|
230 let charset = true; |
|
231 let charsetSuffix = "; charset=us-ascii"; |
|
232 |
|
233 let server = httpd_setup({"/resource": function(req, res) { |
|
234 res.setStatusLine(req.httpVersion, 200, "OK"); |
|
235 res.setHeader("Content-Type", contentType + (charset ? charsetSuffix : "")); |
|
236 |
|
237 let converter = Cc["@mozilla.org/intl/converter-output-stream;1"] |
|
238 .createInstance(Ci.nsIConverterOutputStream); |
|
239 converter.init(res.bodyOutputStream, "us-ascii", 0, 0x0000); |
|
240 converter.writeString(response); |
|
241 converter.close(); |
|
242 }}); |
|
243 |
|
244 // Check that provided charset overrides hint. |
|
245 let request1 = new RESTRequest(server.baseURI + "/resource"); |
|
246 request1.charset = "not-a-charset"; |
|
247 request1.get(function(error) { |
|
248 do_check_null(error); |
|
249 |
|
250 do_check_eq(request1.response.status, 200); |
|
251 do_check_eq(request1.response.body, response); |
|
252 do_check_eq(request1.response.headers["content-type"], |
|
253 contentType + charsetSuffix); |
|
254 do_check_eq(request1.response.charset, "us-ascii"); |
|
255 |
|
256 // Check that hint is used if Content-Type doesn't have a charset. |
|
257 charset = false; |
|
258 let request2 = new RESTRequest(server.baseURI + "/resource"); |
|
259 request2.charset = "us-ascii"; |
|
260 request2.get(function(error) { |
|
261 do_check_null(error); |
|
262 |
|
263 do_check_eq(request2.response.status, 200); |
|
264 do_check_eq(request2.response.body, response); |
|
265 do_check_eq(request2.response.headers["content-type"], contentType); |
|
266 do_check_eq(request2.response.charset, "us-ascii"); |
|
267 |
|
268 server.stop(run_next_test); |
|
269 }); |
|
270 }); |
|
271 }); |
|
272 |
|
273 /** |
|
274 * Test HTTP PUT with a simple string argument and default Content-Type. |
|
275 */ |
|
276 add_test(function test_put() { |
|
277 let handler = httpd_handler(200, "OK", "Got it!"); |
|
278 let server = httpd_setup({"/resource": handler}); |
|
279 |
|
280 let request = new RESTRequest(server.baseURI + "/resource"); |
|
281 do_check_eq(request.status, request.NOT_SENT); |
|
282 |
|
283 request.onProgress = request.onComplete = function () { |
|
284 do_throw("This function should have been overwritten!"); |
|
285 }; |
|
286 |
|
287 let onProgress_called = false; |
|
288 function onProgress() { |
|
289 onProgress_called = true; |
|
290 do_check_eq(this.status, request.IN_PROGRESS); |
|
291 do_check_true(this.response.body.length > 0); |
|
292 }; |
|
293 |
|
294 function onComplete(error) { |
|
295 do_check_eq(error, null); |
|
296 |
|
297 do_check_eq(this.status, this.COMPLETED); |
|
298 do_check_true(this.response.success); |
|
299 do_check_eq(this.response.status, 200); |
|
300 do_check_eq(this.response.body, "Got it!"); |
|
301 |
|
302 do_check_eq(handler.request.method, "PUT"); |
|
303 do_check_eq(handler.request.body, "Hullo?"); |
|
304 do_check_eq(handler.request.getHeader("Content-Type"), "text/plain"); |
|
305 |
|
306 do_check_true(onProgress_called); |
|
307 CommonUtils.nextTick(function () { |
|
308 do_check_eq(request.onComplete, null); |
|
309 do_check_eq(request.onProgress, null); |
|
310 server.stop(run_next_test); |
|
311 }); |
|
312 }; |
|
313 |
|
314 do_check_eq(request.put("Hullo?", onComplete, onProgress), request); |
|
315 do_check_eq(request.status, request.SENT); |
|
316 do_check_eq(request.method, "PUT"); |
|
317 do_check_throws(function () { |
|
318 request.put("Hai!"); |
|
319 }); |
|
320 }); |
|
321 |
|
322 /** |
|
323 * Test HTTP POST with a simple string argument and default Content-Type. |
|
324 */ |
|
325 add_test(function test_post() { |
|
326 let handler = httpd_handler(200, "OK", "Got it!"); |
|
327 let server = httpd_setup({"/resource": handler}); |
|
328 |
|
329 let request = new RESTRequest(server.baseURI + "/resource"); |
|
330 do_check_eq(request.status, request.NOT_SENT); |
|
331 |
|
332 request.onProgress = request.onComplete = function () { |
|
333 do_throw("This function should have been overwritten!"); |
|
334 }; |
|
335 |
|
336 let onProgress_called = false; |
|
337 function onProgress() { |
|
338 onProgress_called = true; |
|
339 do_check_eq(this.status, request.IN_PROGRESS); |
|
340 do_check_true(this.response.body.length > 0); |
|
341 }; |
|
342 |
|
343 function onComplete(error) { |
|
344 do_check_eq(error, null); |
|
345 |
|
346 do_check_eq(this.status, this.COMPLETED); |
|
347 do_check_true(this.response.success); |
|
348 do_check_eq(this.response.status, 200); |
|
349 do_check_eq(this.response.body, "Got it!"); |
|
350 |
|
351 do_check_eq(handler.request.method, "POST"); |
|
352 do_check_eq(handler.request.body, "Hullo?"); |
|
353 do_check_eq(handler.request.getHeader("Content-Type"), "text/plain"); |
|
354 |
|
355 do_check_true(onProgress_called); |
|
356 CommonUtils.nextTick(function () { |
|
357 do_check_eq(request.onComplete, null); |
|
358 do_check_eq(request.onProgress, null); |
|
359 server.stop(run_next_test); |
|
360 }); |
|
361 }; |
|
362 |
|
363 do_check_eq(request.post("Hullo?", onComplete, onProgress), request); |
|
364 do_check_eq(request.status, request.SENT); |
|
365 do_check_eq(request.method, "POST"); |
|
366 do_check_throws(function () { |
|
367 request.post("Hai!"); |
|
368 }); |
|
369 }); |
|
370 |
|
371 /** |
|
372 * Test HTTP DELETE. |
|
373 */ |
|
374 add_test(function test_delete() { |
|
375 let handler = httpd_handler(200, "OK", "Got it!"); |
|
376 let server = httpd_setup({"/resource": handler}); |
|
377 |
|
378 let request = new RESTRequest(server.baseURI + "/resource"); |
|
379 do_check_eq(request.status, request.NOT_SENT); |
|
380 |
|
381 request.onProgress = request.onComplete = function () { |
|
382 do_throw("This function should have been overwritten!"); |
|
383 }; |
|
384 |
|
385 let onProgress_called = false; |
|
386 function onProgress() { |
|
387 onProgress_called = true; |
|
388 do_check_eq(this.status, request.IN_PROGRESS); |
|
389 do_check_true(this.response.body.length > 0); |
|
390 }; |
|
391 |
|
392 function onComplete(error) { |
|
393 do_check_eq(error, null); |
|
394 |
|
395 do_check_eq(this.status, this.COMPLETED); |
|
396 do_check_true(this.response.success); |
|
397 do_check_eq(this.response.status, 200); |
|
398 do_check_eq(this.response.body, "Got it!"); |
|
399 do_check_eq(handler.request.method, "DELETE"); |
|
400 |
|
401 do_check_true(onProgress_called); |
|
402 CommonUtils.nextTick(function () { |
|
403 do_check_eq(request.onComplete, null); |
|
404 do_check_eq(request.onProgress, null); |
|
405 server.stop(run_next_test); |
|
406 }); |
|
407 }; |
|
408 |
|
409 do_check_eq(request.delete(onComplete, onProgress), request); |
|
410 do_check_eq(request.status, request.SENT); |
|
411 do_check_eq(request.method, "DELETE"); |
|
412 do_check_throws(function () { |
|
413 request.delete(); |
|
414 }); |
|
415 }); |
|
416 |
|
417 /** |
|
418 * Test an HTTP response with a non-200 status code. |
|
419 */ |
|
420 add_test(function test_get_404() { |
|
421 let handler = httpd_handler(404, "Not Found", "Cannae find it!"); |
|
422 let server = httpd_setup({"/resource": handler}); |
|
423 |
|
424 let request = new RESTRequest(server.baseURI + "/resource"); |
|
425 request.get(function (error) { |
|
426 do_check_eq(error, null); |
|
427 |
|
428 do_check_eq(this.status, this.COMPLETED); |
|
429 do_check_false(this.response.success); |
|
430 do_check_eq(this.response.status, 404); |
|
431 do_check_eq(this.response.body, "Cannae find it!"); |
|
432 |
|
433 server.stop(run_next_test); |
|
434 }); |
|
435 }); |
|
436 |
|
437 /** |
|
438 * The 'data' argument to PUT, if not a string already, is automatically |
|
439 * stringified as JSON. |
|
440 */ |
|
441 add_test(function test_put_json() { |
|
442 let handler = httpd_handler(200, "OK"); |
|
443 let server = httpd_setup({"/resource": handler}); |
|
444 |
|
445 let sample_data = { |
|
446 some: "sample_data", |
|
447 injson: "format", |
|
448 number: 42 |
|
449 }; |
|
450 let request = new RESTRequest(server.baseURI + "/resource"); |
|
451 request.put(sample_data, function (error) { |
|
452 do_check_eq(error, null); |
|
453 |
|
454 do_check_eq(this.status, this.COMPLETED); |
|
455 do_check_true(this.response.success); |
|
456 do_check_eq(this.response.status, 200); |
|
457 do_check_eq(this.response.body, ""); |
|
458 |
|
459 do_check_eq(handler.request.method, "PUT"); |
|
460 do_check_eq(handler.request.body, JSON.stringify(sample_data)); |
|
461 do_check_eq(handler.request.getHeader("Content-Type"), "text/plain"); |
|
462 |
|
463 server.stop(run_next_test); |
|
464 }); |
|
465 }); |
|
466 |
|
467 /** |
|
468 * The 'data' argument to POST, if not a string already, is automatically |
|
469 * stringified as JSON. |
|
470 */ |
|
471 add_test(function test_post_json() { |
|
472 let handler = httpd_handler(200, "OK"); |
|
473 let server = httpd_setup({"/resource": handler}); |
|
474 |
|
475 let sample_data = { |
|
476 some: "sample_data", |
|
477 injson: "format", |
|
478 number: 42 |
|
479 }; |
|
480 let request = new RESTRequest(server.baseURI + "/resource"); |
|
481 request.post(sample_data, function (error) { |
|
482 do_check_eq(error, null); |
|
483 |
|
484 do_check_eq(this.status, this.COMPLETED); |
|
485 do_check_true(this.response.success); |
|
486 do_check_eq(this.response.status, 200); |
|
487 do_check_eq(this.response.body, ""); |
|
488 |
|
489 do_check_eq(handler.request.method, "POST"); |
|
490 do_check_eq(handler.request.body, JSON.stringify(sample_data)); |
|
491 do_check_eq(handler.request.getHeader("Content-Type"), "text/plain"); |
|
492 |
|
493 server.stop(run_next_test); |
|
494 }); |
|
495 }); |
|
496 |
|
497 /** |
|
498 * HTTP PUT with a custom Content-Type header. |
|
499 */ |
|
500 add_test(function test_put_override_content_type() { |
|
501 let handler = httpd_handler(200, "OK"); |
|
502 let server = httpd_setup({"/resource": handler}); |
|
503 |
|
504 let request = new RESTRequest(server.baseURI + "/resource"); |
|
505 request.setHeader("Content-Type", "application/lolcat"); |
|
506 request.put("O HAI!!1!", function (error) { |
|
507 do_check_eq(error, null); |
|
508 |
|
509 do_check_eq(this.status, this.COMPLETED); |
|
510 do_check_true(this.response.success); |
|
511 do_check_eq(this.response.status, 200); |
|
512 do_check_eq(this.response.body, ""); |
|
513 |
|
514 do_check_eq(handler.request.method, "PUT"); |
|
515 do_check_eq(handler.request.body, "O HAI!!1!"); |
|
516 do_check_eq(handler.request.getHeader("Content-Type"), "application/lolcat"); |
|
517 |
|
518 server.stop(run_next_test); |
|
519 }); |
|
520 }); |
|
521 |
|
522 /** |
|
523 * HTTP POST with a custom Content-Type header. |
|
524 */ |
|
525 add_test(function test_post_override_content_type() { |
|
526 let handler = httpd_handler(200, "OK"); |
|
527 let server = httpd_setup({"/resource": handler}); |
|
528 |
|
529 let request = new RESTRequest(server.baseURI + "/resource"); |
|
530 request.setHeader("Content-Type", "application/lolcat"); |
|
531 request.post("O HAI!!1!", function (error) { |
|
532 do_check_eq(error, null); |
|
533 |
|
534 do_check_eq(this.status, this.COMPLETED); |
|
535 do_check_true(this.response.success); |
|
536 do_check_eq(this.response.status, 200); |
|
537 do_check_eq(this.response.body, ""); |
|
538 |
|
539 do_check_eq(handler.request.method, "POST"); |
|
540 do_check_eq(handler.request.body, "O HAI!!1!"); |
|
541 do_check_eq(handler.request.getHeader("Content-Type"), "application/lolcat"); |
|
542 |
|
543 server.stop(run_next_test); |
|
544 }); |
|
545 }); |
|
546 |
|
547 /** |
|
548 * No special headers are sent by default on a GET request. |
|
549 */ |
|
550 add_test(function test_get_no_headers() { |
|
551 let handler = httpd_handler(200, "OK"); |
|
552 let server = httpd_setup({"/resource": handler}); |
|
553 |
|
554 let ignore_headers = ["host", "user-agent", "accept", "accept-language", |
|
555 "accept-encoding", "accept-charset", "keep-alive", |
|
556 "connection", "pragma", "cache-control", |
|
557 "content-length"]; |
|
558 |
|
559 new RESTRequest(server.baseURI + "/resource").get(function (error) { |
|
560 do_check_eq(error, null); |
|
561 |
|
562 do_check_eq(this.response.status, 200); |
|
563 do_check_eq(this.response.body, ""); |
|
564 |
|
565 let server_headers = handler.request.headers; |
|
566 while (server_headers.hasMoreElements()) { |
|
567 let header = server_headers.getNext().toString(); |
|
568 if (ignore_headers.indexOf(header) == -1) { |
|
569 do_throw("Got unexpected header!"); |
|
570 } |
|
571 } |
|
572 |
|
573 server.stop(run_next_test); |
|
574 }); |
|
575 }); |
|
576 |
|
577 /** |
|
578 * Test changing the URI after having created the request. |
|
579 */ |
|
580 add_test(function test_changing_uri() { |
|
581 let handler = httpd_handler(200, "OK"); |
|
582 let server = httpd_setup({"/resource": handler}); |
|
583 |
|
584 let request = new RESTRequest("http://localhost:1234/the-wrong-resource"); |
|
585 request.uri = CommonUtils.makeURI(server.baseURI + "/resource"); |
|
586 request.get(function (error) { |
|
587 do_check_eq(error, null); |
|
588 do_check_eq(this.response.status, 200); |
|
589 server.stop(run_next_test); |
|
590 }); |
|
591 }); |
|
592 |
|
593 /** |
|
594 * Test setting HTTP request headers. |
|
595 */ |
|
596 add_test(function test_request_setHeader() { |
|
597 let handler = httpd_handler(200, "OK"); |
|
598 let server = httpd_setup({"/resource": handler}); |
|
599 |
|
600 let request = new RESTRequest(server.baseURI + "/resource"); |
|
601 |
|
602 request.setHeader("X-What-Is-Weave", "awesome"); |
|
603 request.setHeader("X-WHAT-is-Weave", "more awesomer"); |
|
604 request.setHeader("Another-Header", "Hello World"); |
|
605 |
|
606 request.get(function (error) { |
|
607 do_check_eq(error, null); |
|
608 |
|
609 do_check_eq(this.response.status, 200); |
|
610 do_check_eq(this.response.body, ""); |
|
611 |
|
612 do_check_eq(handler.request.getHeader("X-What-Is-Weave"), "more awesomer"); |
|
613 do_check_eq(handler.request.getHeader("another-header"), "Hello World"); |
|
614 |
|
615 server.stop(run_next_test); |
|
616 }); |
|
617 }); |
|
618 |
|
619 /** |
|
620 * Test receiving HTTP response headers. |
|
621 */ |
|
622 add_test(function test_response_headers() { |
|
623 function handler(request, response) { |
|
624 response.setHeader("X-What-Is-Weave", "awesome"); |
|
625 response.setHeader("Another-Header", "Hello World"); |
|
626 response.setStatusLine(request.httpVersion, 200, "OK"); |
|
627 } |
|
628 let server = httpd_setup({"/resource": handler}); |
|
629 let request = new RESTRequest(server.baseURI + "/resource"); |
|
630 |
|
631 request.get(function (error) { |
|
632 do_check_eq(error, null); |
|
633 |
|
634 do_check_eq(this.response.status, 200); |
|
635 do_check_eq(this.response.body, ""); |
|
636 |
|
637 do_check_eq(this.response.headers["x-what-is-weave"], "awesome"); |
|
638 do_check_eq(this.response.headers["another-header"], "Hello World"); |
|
639 |
|
640 server.stop(run_next_test); |
|
641 }); |
|
642 }); |
|
643 |
|
644 /** |
|
645 * The onComplete() handler gets called in case of any network errors |
|
646 * (e.g. NS_ERROR_CONNECTION_REFUSED). |
|
647 */ |
|
648 add_test(function test_connection_refused() { |
|
649 let request = new RESTRequest("http://localhost:1234/resource"); |
|
650 request.onProgress = function onProgress() { |
|
651 do_throw("Shouldn't have called request.onProgress()!"); |
|
652 }; |
|
653 request.get(function (error) { |
|
654 do_check_eq(error.result, Cr.NS_ERROR_CONNECTION_REFUSED); |
|
655 do_check_eq(error.message, "NS_ERROR_CONNECTION_REFUSED"); |
|
656 do_check_eq(this.status, this.COMPLETED); |
|
657 run_next_test(); |
|
658 }); |
|
659 do_check_eq(request.status, request.SENT); |
|
660 }); |
|
661 |
|
662 /** |
|
663 * Abort a request that just sent off. |
|
664 */ |
|
665 add_test(function test_abort() { |
|
666 function handler() { |
|
667 do_throw("Shouldn't have gotten here!"); |
|
668 } |
|
669 let server = httpd_setup({"/resource": handler}); |
|
670 |
|
671 let request = new RESTRequest(server.baseURI + "/resource"); |
|
672 |
|
673 // Aborting a request that hasn't been sent yet is pointless and will throw. |
|
674 do_check_throws(function () { |
|
675 request.abort(); |
|
676 }); |
|
677 |
|
678 request.onProgress = request.onComplete = function () { |
|
679 do_throw("Shouldn't have gotten here!"); |
|
680 }; |
|
681 request.get(); |
|
682 request.abort(); |
|
683 |
|
684 // Aborting an already aborted request is pointless and will throw. |
|
685 do_check_throws(function () { |
|
686 request.abort(); |
|
687 }); |
|
688 |
|
689 do_check_eq(request.status, request.ABORTED); |
|
690 CommonUtils.nextTick(function () { |
|
691 server.stop(run_next_test); |
|
692 }); |
|
693 }); |
|
694 |
|
695 /** |
|
696 * A non-zero 'timeout' property specifies the amount of seconds to wait after |
|
697 * channel activity until the request is automatically canceled. |
|
698 */ |
|
699 add_test(function test_timeout() { |
|
700 let server = new HttpServer(); |
|
701 let server_connection; |
|
702 server._handler.handleResponse = function(connection) { |
|
703 // This is a handler that doesn't do anything, just keeps the connection |
|
704 // open, thereby mimicking a timing out connection. We keep a reference to |
|
705 // the open connection for later so it can be properly disposed of. That's |
|
706 // why you really only want to make one HTTP request to this server ever. |
|
707 server_connection = connection; |
|
708 }; |
|
709 server.start(); |
|
710 let identity = server.identity; |
|
711 let uri = identity.primaryScheme + "://" + identity.primaryHost + ":" + |
|
712 identity.primaryPort; |
|
713 |
|
714 let request = new RESTRequest(uri + "/resource"); |
|
715 request.timeout = 0.1; // 100 milliseconds |
|
716 request.get(function (error) { |
|
717 do_check_eq(error.result, Cr.NS_ERROR_NET_TIMEOUT); |
|
718 do_check_eq(this.status, this.ABORTED); |
|
719 |
|
720 // server_connection is undefined on the Android emulator for reasons |
|
721 // unknown. Yet, we still get here. If this test is refactored, we should |
|
722 // investigate the reason why the above callback is behaving differently. |
|
723 if (server_connection) { |
|
724 _("Closing connection."); |
|
725 server_connection.close(); |
|
726 } |
|
727 |
|
728 _("Shutting down server."); |
|
729 server.stop(run_next_test); |
|
730 }); |
|
731 }); |
|
732 |
|
733 /** |
|
734 * An exception thrown in 'onProgress' propagates to the 'onComplete' handler. |
|
735 */ |
|
736 add_test(function test_exception_in_onProgress() { |
|
737 let handler = httpd_handler(200, "OK", "Foobar"); |
|
738 let server = httpd_setup({"/resource": handler}); |
|
739 |
|
740 let request = new RESTRequest(server.baseURI + "/resource"); |
|
741 request.onProgress = function onProgress() { |
|
742 it.does.not.exist(); |
|
743 }; |
|
744 request.get(function onComplete(error) { |
|
745 do_check_eq(error, "ReferenceError: it is not defined"); |
|
746 do_check_eq(this.status, this.ABORTED); |
|
747 |
|
748 server.stop(run_next_test); |
|
749 }); |
|
750 }); |
|
751 |
|
752 add_test(function test_new_channel() { |
|
753 _("Ensure a redirect to a new channel is handled properly."); |
|
754 |
|
755 function checkUA(metadata) { |
|
756 let ua = metadata.getHeader("User-Agent"); |
|
757 _("User-Agent is " + ua); |
|
758 do_check_eq("foo bar", ua); |
|
759 } |
|
760 |
|
761 let redirectRequested = false; |
|
762 let redirectURL; |
|
763 function redirectHandler(metadata, response) { |
|
764 checkUA(metadata); |
|
765 redirectRequested = true; |
|
766 |
|
767 let body = "Redirecting"; |
|
768 response.setStatusLine(metadata.httpVersion, 307, "TEMPORARY REDIRECT"); |
|
769 response.setHeader("Location", redirectURL); |
|
770 response.bodyOutputStream.write(body, body.length); |
|
771 } |
|
772 |
|
773 let resourceRequested = false; |
|
774 function resourceHandler(metadata, response) { |
|
775 checkUA(metadata); |
|
776 resourceRequested = true; |
|
777 |
|
778 let body = "Test"; |
|
779 response.setHeader("Content-Type", "text/plain"); |
|
780 response.bodyOutputStream.write(body, body.length); |
|
781 } |
|
782 |
|
783 let server1 = httpd_setup({"/redirect": redirectHandler}); |
|
784 let server2 = httpd_setup({"/resource": resourceHandler}); |
|
785 redirectURL = server2.baseURI + "/resource"; |
|
786 |
|
787 function advance() { |
|
788 server1.stop(function () { |
|
789 server2.stop(run_next_test); |
|
790 }); |
|
791 } |
|
792 |
|
793 let request = new RESTRequest(server1.baseURI + "/redirect"); |
|
794 request.setHeader("User-Agent", "foo bar"); |
|
795 |
|
796 // Swizzle in our own fakery, because this redirect is neither |
|
797 // internal nor URI-preserving. RESTRequest's policy is to only |
|
798 // copy headers under certain circumstances. |
|
799 let protoMethod = request.shouldCopyOnRedirect; |
|
800 request.shouldCopyOnRedirect = function wrapped(o, n, f) { |
|
801 // Check the default policy. |
|
802 do_check_false(protoMethod.call(this, o, n, f)); |
|
803 return true; |
|
804 }; |
|
805 |
|
806 request.get(function onComplete(error) { |
|
807 let response = this.response; |
|
808 |
|
809 do_check_eq(200, response.status); |
|
810 do_check_eq("Test", response.body); |
|
811 do_check_true(redirectRequested); |
|
812 do_check_true(resourceRequested); |
|
813 |
|
814 advance(); |
|
815 }); |
|
816 }); |
|
817 |
|
818 add_test(function test_not_sending_cookie() { |
|
819 function handler(metadata, response) { |
|
820 let body = "COOKIE!"; |
|
821 response.setStatusLine(metadata.httpVersion, 200, "OK"); |
|
822 response.bodyOutputStream.write(body, body.length); |
|
823 do_check_false(metadata.hasHeader("Cookie")); |
|
824 } |
|
825 let server = httpd_setup({"/test": handler}); |
|
826 |
|
827 let cookieSer = Cc["@mozilla.org/cookieService;1"] |
|
828 .getService(Ci.nsICookieService); |
|
829 let uri = CommonUtils.makeURI(server.baseURI); |
|
830 cookieSer.setCookieString(uri, null, "test=test; path=/;", null); |
|
831 |
|
832 let res = new RESTRequest(server.baseURI + "/test"); |
|
833 res.get(function (error) { |
|
834 do_check_null(error); |
|
835 do_check_true(this.response.success); |
|
836 do_check_eq("COOKIE!", this.response.body); |
|
837 server.stop(run_next_test); |
|
838 }); |
|
839 }); |
|
840 |