test_bug203271.js (5958B)
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 "use strict"; 8 9 const { HttpServer } = ChromeUtils.importESModule( 10 "resource://testing-common/httpd.sys.mjs" 11 ); 12 13 var httpserver = new HttpServer(); 14 var index = 0; 15 var tests = [ 16 // original problem described in bug#203271 17 { 18 url: "/precedence", 19 server: "0", 20 expected: "0", 21 responseheader: [ 22 "Expires: " + getDateString(-1), 23 "Cache-Control: max-age=3600", 24 ], 25 }, 26 27 { 28 url: "/precedence?0", 29 server: "0", 30 expected: "0", 31 responseheader: [ 32 "Cache-Control: max-age=3600", 33 "Expires: " + getDateString(-1), 34 ], 35 }, 36 37 // max-age=1s, expires=1 year from now 38 { 39 url: "/precedence?1", 40 server: "0", 41 expected: "0", 42 responseheader: [ 43 "Expires: " + getDateString(1), 44 "Cache-Control: max-age=1", 45 ], 46 }, 47 48 // expires=now 49 { 50 url: "/precedence?2", 51 server: "0", 52 expected: "0", 53 responseheader: ["Expires: " + getDateString(0)], 54 }, 55 56 // max-age=1s 57 { 58 url: "/precedence?3", 59 server: "0", 60 expected: "0", 61 responseheader: ["Cache-Control: max-age=1"], 62 }, 63 64 // The test below is the example from 65 // 66 // https://bugzilla.mozilla.org/show_bug.cgi?id=203271#c27 67 // 68 // max-age=2592000s (1 month), expires=1 year from now, date=1 year ago 69 { 70 url: "/precedence?4", 71 server: "0", 72 expected: "0", 73 responseheader: [ 74 "Cache-Control: private, max-age=2592000", 75 "Expires: " + getDateString(+1), 76 ], 77 explicitDate: getDateString(-1), 78 }, 79 80 // The two tests below are also examples of clocks really out of synch 81 // max-age=1s, date=1 year from now 82 { 83 url: "/precedence?5", 84 server: "0", 85 expected: "0", 86 responseheader: ["Cache-Control: max-age=1"], 87 explicitDate: getDateString(1), 88 }, 89 90 // max-age=60s, date=1 year from now 91 { 92 url: "/precedence?6", 93 server: "0", 94 expected: "0", 95 responseheader: ["Cache-Control: max-age=60"], 96 explicitDate: getDateString(1), 97 }, 98 99 // this is just to get a pause of 3s to allow cache-entries to expire 100 { url: "/precedence?999", server: "0", expected: "0", delay: "3000" }, 101 102 // Below are the cases which actually matters 103 { url: "/precedence", server: "1", expected: "0" }, // should be cached 104 105 { url: "/precedence?0", server: "1", expected: "0" }, // should be cached 106 107 { url: "/precedence?1", server: "1", expected: "1" }, // should have expired 108 109 { url: "/precedence?2", server: "1", expected: "1" }, // should have expired 110 111 { url: "/precedence?3", server: "1", expected: "1" }, // should have expired 112 113 { url: "/precedence?4", server: "1", expected: "1" }, // should have expired 114 115 { url: "/precedence?5", server: "1", expected: "1" }, // should have expired 116 117 { url: "/precedence?6", server: "1", expected: "0" }, // should be cached 118 ]; 119 120 function logit(i, data, ctx) { 121 dump( 122 "requested [" + 123 tests[i].server + 124 "] " + 125 "got [" + 126 data + 127 "] " + 128 "expected [" + 129 tests[i].expected + 130 "]" 131 ); 132 133 if (tests[i].responseheader) { 134 dump("\t[" + tests[i].responseheader + "]"); 135 } 136 dump("\n"); 137 // Dump all response-headers 138 dump("\n===================================\n"); 139 ctx.visitResponseHeaders({ 140 visitHeader(key, val) { 141 dump("\t" + key + ":" + val + "\n"); 142 }, 143 }); 144 dump("===================================\n"); 145 } 146 147 function setupChannel(suffix, value) { 148 var chan = NetUtil.newChannel({ 149 uri: "http://localhost:" + httpserver.identity.primaryPort + suffix, 150 loadUsingSystemPrincipal: true, 151 }); 152 var httpChan = chan.QueryInterface(Ci.nsIHttpChannel); 153 httpChan.requestMethod = "GET"; // default value, just being paranoid... 154 httpChan.setRequestHeader("x-request", value, false); 155 return httpChan; 156 } 157 158 function triggerNextTest() { 159 var channel = setupChannel(tests[index].url, tests[index].server); 160 channel.asyncOpen(new ChannelListener(checkValueAndTrigger, channel)); 161 } 162 163 function checkValueAndTrigger(request, data, ctx) { 164 logit(index, data, ctx); 165 Assert.equal(tests[index].expected, data); 166 167 if (index < tests.length - 1) { 168 var delay = tests[index++].delay; 169 if (delay) { 170 do_timeout(delay, triggerNextTest); 171 } else { 172 triggerNextTest(); 173 } 174 } else { 175 httpserver.stop(do_test_finished); 176 } 177 } 178 179 function run_test() { 180 httpserver.registerPathHandler("/precedence", handler); 181 httpserver.start(-1); 182 183 // clear cache 184 evict_cache_entries(); 185 186 triggerNextTest(); 187 do_test_pending(); 188 } 189 190 function handler(metadata, response) { 191 var body = metadata.getHeader("x-request"); 192 response.setHeader("Content-Type", "text/plain", false); 193 194 var date = tests[index].explicitDate; 195 if (date == undefined) { 196 response.setHeader("Date", getDateString(0), false); 197 } else { 198 response.setHeader("Date", date, false); 199 } 200 201 var header = tests[index].responseheader; 202 if (header == undefined) { 203 response.setHeader("Last-Modified", getDateString(-1), false); 204 } else { 205 for (var i = 0; i < header.length; i++) { 206 var splitHdr = header[i].split(": "); 207 response.setHeader(splitHdr[0], splitHdr[1], false); 208 } 209 } 210 211 response.setStatusLine(metadata.httpVersion, 200, "OK"); 212 response.bodyOutputStream.write(body, body.length); 213 } 214 215 function getDateString(yearDelta) { 216 var months = [ 217 "Jan", 218 "Feb", 219 "Mar", 220 "Apr", 221 "May", 222 "Jun", 223 "Jul", 224 "Aug", 225 "Sep", 226 "Oct", 227 "Nov", 228 "Dec", 229 ]; 230 var days = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]; 231 232 var d = new Date(); 233 return ( 234 days[d.getUTCDay()] + 235 ", " + 236 d.getUTCDate() + 237 " " + 238 months[d.getUTCMonth()] + 239 " " + 240 (d.getUTCFullYear() + yearDelta) + 241 " " + 242 d.getUTCHours() + 243 ":" + 244 d.getUTCMinutes() + 245 ":" + 246 d.getUTCSeconds() + 247 " UTC" 248 ); 249 }