|
1 Cu.import("resource://testing-common/httpd.js"); |
|
2 |
|
3 var httpserver = null; |
|
4 |
|
5 function make_channel(url, callback, ctx) { |
|
6 var ios = Cc["@mozilla.org/network/io-service;1"]. |
|
7 getService(Ci.nsIIOService); |
|
8 return ios.newChannel(url, "", null); |
|
9 } |
|
10 |
|
11 const responseBody = "response body"; |
|
12 |
|
13 function cachedHandler(metadata, response) { |
|
14 var body = responseBody; |
|
15 if (metadata.hasHeader("Range")) { |
|
16 var matches = metadata.getHeader("Range").match(/^\s*bytes=(\d+)?-(\d+)?\s*$/); |
|
17 var from = (matches[1] === undefined) ? 0 : matches[1]; |
|
18 var to = (matches[2] === undefined) ? responseBody.length - 1 : matches[2]; |
|
19 if (from >= responseBody.length) { |
|
20 response.setStatusLine(metadata.httpVersion, 416, "Start pos too high"); |
|
21 response.setHeader("Content-Range", "*/" + responseBody.length, false); |
|
22 return; |
|
23 } |
|
24 body = responseBody.slice(from, to + 1); |
|
25 // always respond to successful range requests with 206 |
|
26 response.setStatusLine(metadata.httpVersion, 206, "Partial Content"); |
|
27 response.setHeader("Content-Range", from + "-" + to + "/" + responseBody.length, false); |
|
28 } |
|
29 |
|
30 response.setHeader("Content-Type", "text/plain", false); |
|
31 response.setHeader("ETag", "Just testing"); |
|
32 response.setHeader("Accept-Ranges", "bytes"); |
|
33 |
|
34 response.bodyOutputStream.write(body, body.length); |
|
35 } |
|
36 |
|
37 function Canceler(continueFn) { |
|
38 this.continueFn = continueFn; |
|
39 } |
|
40 |
|
41 Canceler.prototype = { |
|
42 QueryInterface: function(iid) { |
|
43 if (iid.equals(Ci.nsIStreamListener) || |
|
44 iid.equals(Ci.nsIRequestObserver) || |
|
45 iid.equals(Ci.nsISupports)) |
|
46 return this; |
|
47 throw Components.results.NS_ERROR_NO_INTERFACE; |
|
48 }, |
|
49 |
|
50 onStartRequest: function(request, context) { |
|
51 }, |
|
52 |
|
53 onDataAvailable: function(request, context, stream, offset, count) { |
|
54 request.QueryInterface(Ci.nsIChannel) |
|
55 .cancel(Components.results.NS_BINDING_ABORTED); |
|
56 }, |
|
57 |
|
58 onStopRequest: function(request, context, status) { |
|
59 do_check_eq(status, Components.results.NS_BINDING_ABORTED); |
|
60 this.continueFn(); |
|
61 } |
|
62 }; |
|
63 |
|
64 function finish_test() { |
|
65 httpserver.stop(do_test_finished); |
|
66 } |
|
67 |
|
68 function start_cache_read() { |
|
69 var chan = make_channel("http://localhost:" + |
|
70 httpserver.identity.primaryPort + "/cached/test.gz"); |
|
71 chan.asyncOpen(new ChannelListener(finish_test, null), null); |
|
72 } |
|
73 |
|
74 function start_canceler() { |
|
75 var chan = make_channel("http://localhost:" + |
|
76 httpserver.identity.primaryPort + "/cached/test.gz"); |
|
77 chan.asyncOpen(new Canceler(start_cache_read), null); |
|
78 } |
|
79 |
|
80 function run_test() { |
|
81 httpserver = new HttpServer(); |
|
82 httpserver.registerPathHandler("/cached/test.gz", cachedHandler); |
|
83 httpserver.start(-1); |
|
84 |
|
85 var chan = make_channel("http://localhost:" + |
|
86 httpserver.identity.primaryPort + "/cached/test.gz"); |
|
87 chan.asyncOpen(new ChannelListener(start_canceler, null), null); |
|
88 do_test_pending(); |
|
89 } |