|
1 // |
|
2 // Tests if a response with an Expires-header in the past |
|
3 // and Cache-Control: max-age in the future works as |
|
4 // specified in RFC 2616 section 14.9.3 by letting max-age |
|
5 // take precedence |
|
6 |
|
7 Cu.import("resource://testing-common/httpd.js"); |
|
8 const BUGID = "203271"; |
|
9 |
|
10 var httpserver = new HttpServer(); |
|
11 var index = 0; |
|
12 var tests = [ |
|
13 // original problem described in bug#203271 |
|
14 {url: "/precedence", server: "0", expected: "0", |
|
15 responseheader: [ "Expires: " + getDateString(-1), |
|
16 "Cache-Control: max-age=3600"]}, |
|
17 |
|
18 {url: "/precedence?0", server: "0", expected: "0", |
|
19 responseheader: [ "Cache-Control: max-age=3600", |
|
20 "Expires: " + getDateString(-1)]}, |
|
21 |
|
22 // max-age=1s, expires=1 year from now |
|
23 {url: "/precedence?1", server: "0", expected: "0", |
|
24 responseheader: [ "Expires: " + getDateString(1), |
|
25 "Cache-Control: max-age=1"]}, |
|
26 |
|
27 // expires=now |
|
28 {url: "/precedence?2", server: "0", expected: "0", |
|
29 responseheader: [ "Expires: " + getDateString(0)]}, |
|
30 |
|
31 // max-age=1s |
|
32 {url: "/precedence?3", server: "0", expected: "0", |
|
33 responseheader: ["Cache-Control: max-age=1"]}, |
|
34 |
|
35 // The test below is the example from |
|
36 // |
|
37 // https://bugzilla.mozilla.org/show_bug.cgi?id=203271#c27 |
|
38 // |
|
39 // max-age=2592000s (1 month), expires=1 year from now, date=1 year ago |
|
40 {url: "/precedence?4", server: "0", expected: "0", |
|
41 responseheader: [ "Cache-Control: private, max-age=2592000", |
|
42 "Expires: " + getDateString(+1)], |
|
43 explicitDate: getDateString(-1)}, |
|
44 |
|
45 // The two tests below are also examples of clocks really out of synch |
|
46 // max-age=1s, date=1 year from now |
|
47 {url: "/precedence?5", server: "0", expected: "0", |
|
48 responseheader: [ "Cache-Control: max-age=1"], |
|
49 explicitDate: getDateString(1)}, |
|
50 |
|
51 // max-age=60s, date=1 year from now |
|
52 {url: "/precedence?6", server: "0", expected: "0", |
|
53 responseheader: [ "Cache-Control: max-age=60"], |
|
54 explicitDate: getDateString(1)}, |
|
55 |
|
56 // this is just to get a pause of 3s to allow cache-entries to expire |
|
57 {url: "/precedence?999", server: "0", expected: "0", delay: "3000"}, |
|
58 |
|
59 // Below are the cases which actually matters |
|
60 {url: "/precedence", server: "1", expected: "0"}, // should be cached |
|
61 |
|
62 {url: "/precedence?0", server: "1", expected: "0"}, // should be cached |
|
63 |
|
64 {url: "/precedence?1", server: "1", expected: "1"}, // should have expired |
|
65 |
|
66 {url: "/precedence?2", server: "1", expected: "1"}, // should have expired |
|
67 |
|
68 {url: "/precedence?3", server: "1", expected: "1"}, // should have expired |
|
69 |
|
70 {url: "/precedence?4", server: "1", expected: "1"}, // should have expired |
|
71 |
|
72 {url: "/precedence?5", server: "1", expected: "1"}, // should have expired |
|
73 |
|
74 {url: "/precedence?6", server: "1", expected: "0"}, // should be cached |
|
75 |
|
76 ]; |
|
77 |
|
78 function logit(i, data, ctx) { |
|
79 dump("requested [" + tests[i].server + "] " + |
|
80 "got [" + data + "] " + |
|
81 "expected [" + tests[i].expected + "]"); |
|
82 |
|
83 if (tests[i].responseheader) |
|
84 dump("\t[" + tests[i].responseheader + "]"); |
|
85 dump("\n"); |
|
86 // Dump all response-headers |
|
87 dump("\n===================================\n") |
|
88 ctx.visitResponseHeaders({ |
|
89 visitHeader: function(key, val) { |
|
90 dump("\t" + key + ":"+val + "\n"); |
|
91 }} |
|
92 ); |
|
93 dump("===================================\n") |
|
94 } |
|
95 |
|
96 function setupChannel(suffix, value) { |
|
97 var ios = Components.classes["@mozilla.org/network/io-service;1"]. |
|
98 getService(Ci.nsIIOService); |
|
99 var chan = ios.newChannel("http://localhost:" + |
|
100 httpserver.identity.primaryPort + suffix, |
|
101 "", null); |
|
102 var httpChan = chan.QueryInterface(Components.interfaces.nsIHttpChannel); |
|
103 httpChan.requestMethod = "GET"; // default value, just being paranoid... |
|
104 httpChan.setRequestHeader("x-request", value, false); |
|
105 return httpChan; |
|
106 } |
|
107 |
|
108 function triggerNextTest() { |
|
109 var channel = setupChannel(tests[index].url, tests[index].server); |
|
110 channel.asyncOpen(new ChannelListener(checkValueAndTrigger, channel), null); |
|
111 } |
|
112 |
|
113 function checkValueAndTrigger(request, data, ctx) { |
|
114 logit(index, data, ctx); |
|
115 do_check_eq(tests[index].expected, data); |
|
116 |
|
117 if (index < tests.length - 1) { |
|
118 var delay = tests[index++].delay; |
|
119 if (delay) { |
|
120 do_timeout(delay, triggerNextTest); |
|
121 } else { |
|
122 triggerNextTest(); |
|
123 } |
|
124 } else { |
|
125 httpserver.stop(do_test_finished); |
|
126 } |
|
127 } |
|
128 |
|
129 function run_test() { |
|
130 httpserver.registerPathHandler("/precedence", handler); |
|
131 httpserver.start(-1); |
|
132 |
|
133 // clear cache |
|
134 evict_cache_entries(); |
|
135 |
|
136 triggerNextTest(); |
|
137 do_test_pending(); |
|
138 } |
|
139 |
|
140 function handler(metadata, response) { |
|
141 var body = metadata.getHeader("x-request"); |
|
142 response.setHeader("Content-Type", "text/plain", false); |
|
143 |
|
144 var date = tests[index].explicitDate; |
|
145 if (date == undefined) { |
|
146 response.setHeader("Date", getDateString(0), false); |
|
147 } else { |
|
148 response.setHeader("Date", date, false); |
|
149 } |
|
150 |
|
151 var header = tests[index].responseheader; |
|
152 if (header == undefined) { |
|
153 response.setHeader("Last-Modified", getDateString(-1), false); |
|
154 } else { |
|
155 for (var i = 0; i < header.length; i++) { |
|
156 var splitHdr = header[i].split(": "); |
|
157 response.setHeader(splitHdr[0], splitHdr[1], false); |
|
158 } |
|
159 } |
|
160 |
|
161 response.setStatusLine(metadata.httpVersion, 200, "OK"); |
|
162 response.bodyOutputStream.write(body, body.length); |
|
163 } |
|
164 |
|
165 function getDateString(yearDelta) { |
|
166 var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', |
|
167 'Sep', 'Oct', 'Nov', 'Dec']; |
|
168 var days = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']; |
|
169 |
|
170 var d = new Date(); |
|
171 return days[d.getUTCDay()] + ", " + |
|
172 d.getUTCDate() + " " + |
|
173 months[d.getUTCMonth()] + " " + |
|
174 (d.getUTCFullYear() + yearDelta) + " " + |
|
175 d.getUTCHours() + ":" + d.getUTCMinutes() + ":" + |
|
176 d.getUTCSeconds() + " UTC"; |
|
177 } |