test_cache-control_request.js (11882B)
1 "use strict"; 2 3 const { HttpServer } = ChromeUtils.importESModule( 4 "resource://testing-common/httpd.sys.mjs" 5 ); 6 7 var httpserver = new HttpServer(); 8 httpserver.start(-1); 9 var cache = null; 10 11 var base_url = "http://localhost:" + httpserver.identity.primaryPort; 12 var resource_age_100 = "/resource_age_100"; 13 var resource_age_100_url = base_url + resource_age_100; 14 var resource_stale_100 = "/resource_stale_100"; 15 var resource_stale_100_url = base_url + resource_stale_100; 16 var resource_fresh_100 = "/resource_fresh_100"; 17 var resource_fresh_100_url = base_url + resource_fresh_100; 18 19 // Test flags 20 var hit_server = false; 21 22 function make_channel(url, cache_control) { 23 // Reset test global status 24 hit_server = false; 25 26 var req = NetUtil.newChannel({ uri: url, loadUsingSystemPrincipal: true }); 27 req.QueryInterface(Ci.nsIHttpChannel); 28 if (cache_control) { 29 req.setRequestHeader("Cache-control", cache_control, false); 30 } 31 32 return req; 33 } 34 35 function make_uri(url) { 36 return Services.io.newURI(url); 37 } 38 39 function resource_age_100_handler(metadata, response) { 40 hit_server = true; 41 42 response.setStatusLine(metadata.httpVersion, 200, "OK"); 43 response.setHeader("Content-Type", "text/plain", false); 44 response.setHeader("Age", "100", false); 45 response.setHeader("Last-Modified", date_string_from_now(-100), false); 46 response.setHeader("Expires", date_string_from_now(+9999), false); 47 48 const body = "data1"; 49 response.bodyOutputStream.write(body, body.length); 50 } 51 52 function resource_stale_100_handler(metadata, response) { 53 hit_server = true; 54 55 response.setStatusLine(metadata.httpVersion, 200, "OK"); 56 response.setHeader("Content-Type", "text/plain", false); 57 response.setHeader("Date", date_string_from_now(-200), false); 58 response.setHeader("Last-Modified", date_string_from_now(-200), false); 59 response.setHeader("Cache-Control", "max-age=100", false); 60 response.setHeader("Expires", date_string_from_now(-100), false); 61 62 const body = "data2"; 63 response.bodyOutputStream.write(body, body.length); 64 } 65 66 function resource_fresh_100_handler(metadata, response) { 67 hit_server = true; 68 69 response.setStatusLine(metadata.httpVersion, 200, "OK"); 70 response.setHeader("Content-Type", "text/plain", false); 71 response.setHeader("Last-Modified", date_string_from_now(0), false); 72 response.setHeader("Cache-Control", "max-age=100", false); 73 response.setHeader("Expires", date_string_from_now(+100), false); 74 75 const body = "data3"; 76 response.bodyOutputStream.write(body, body.length); 77 } 78 79 function run_test() { 80 do_get_profile(); 81 82 do_test_pending(); 83 84 Services.prefs.setBoolPref("network.http.rcwn.enabled", false); 85 86 httpserver.registerPathHandler(resource_age_100, resource_age_100_handler); 87 httpserver.registerPathHandler( 88 resource_stale_100, 89 resource_stale_100_handler 90 ); 91 httpserver.registerPathHandler( 92 resource_fresh_100, 93 resource_fresh_100_handler 94 ); 95 cache = getCacheStorage("disk"); 96 97 wait_for_cache_index(run_next_test); 98 } 99 100 // Here starts the list of tests 101 102 // ============================================================================ 103 // Cache-Control: no-store 104 105 add_test(() => { 106 // Must not create a cache entry 107 var ch = make_channel(resource_age_100_url, "no-store"); 108 ch.asyncOpen( 109 new ChannelListener(function () { 110 Assert.ok(hit_server); 111 Assert.ok(!cache.exists(make_uri(resource_age_100_url), "")); 112 113 run_next_test(); 114 }, null) 115 ); 116 }); 117 118 add_test(() => { 119 // Prepare state only, cache the entry 120 var ch = make_channel(resource_age_100_url); 121 ch.asyncOpen( 122 new ChannelListener(function () { 123 Assert.ok(hit_server); 124 Assert.ok(cache.exists(make_uri(resource_age_100_url), "")); 125 126 run_next_test(); 127 }, null) 128 ); 129 }); 130 131 add_test(() => { 132 // Check the prepared cache entry is used when no special directives are added 133 var ch = make_channel(resource_age_100_url); 134 ch.asyncOpen( 135 new ChannelListener(function () { 136 Assert.ok(!hit_server); 137 Assert.ok(cache.exists(make_uri(resource_age_100_url), "")); 138 139 run_next_test(); 140 }, null) 141 ); 142 }); 143 144 add_test(() => { 145 // Try again, while we already keep a cache entry, 146 // the channel must not use it, entry should stay in the cache 147 var ch = make_channel(resource_age_100_url, "no-store"); 148 ch.asyncOpen( 149 new ChannelListener(function () { 150 Assert.ok(hit_server); 151 Assert.ok(cache.exists(make_uri(resource_age_100_url), "")); 152 153 run_next_test(); 154 }, null) 155 ); 156 }); 157 158 // ============================================================================ 159 // Cache-Control: no-cache 160 161 add_test(() => { 162 // Check the prepared cache entry is used when no special directives are added 163 var ch = make_channel(resource_age_100_url); 164 ch.asyncOpen( 165 new ChannelListener(function () { 166 Assert.ok(!hit_server); 167 Assert.ok(cache.exists(make_uri(resource_age_100_url), "")); 168 169 run_next_test(); 170 }, null) 171 ); 172 }); 173 174 add_test(() => { 175 // The existing entry should be revalidated (we expect a server hit) 176 var ch = make_channel(resource_age_100_url, "no-cache"); 177 ch.asyncOpen( 178 new ChannelListener(function () { 179 Assert.ok(hit_server); 180 Assert.ok(cache.exists(make_uri(resource_age_100_url), "")); 181 182 run_next_test(); 183 }, null) 184 ); 185 }); 186 187 // ============================================================================ 188 // Cache-Control: max-age 189 190 add_test(() => { 191 // Check the prepared cache entry is used when no special directives are added 192 var ch = make_channel(resource_age_100_url); 193 ch.asyncOpen( 194 new ChannelListener(function () { 195 Assert.ok(!hit_server); 196 Assert.ok(cache.exists(make_uri(resource_age_100_url), "")); 197 198 run_next_test(); 199 }, null) 200 ); 201 }); 202 203 add_test(() => { 204 // The existing entry's age is greater than the maximum requested, 205 // should hit server 206 var ch = make_channel(resource_age_100_url, "max-age=10"); 207 ch.asyncOpen( 208 new ChannelListener(function () { 209 Assert.ok(hit_server); 210 Assert.ok(cache.exists(make_uri(resource_age_100_url), "")); 211 212 run_next_test(); 213 }, null) 214 ); 215 }); 216 217 add_test(() => { 218 // The existing entry's age is greater than the maximum requested, 219 // but the max-stale directive says to use it when it's fresh enough 220 var ch = make_channel(resource_age_100_url, "max-age=10, max-stale=99999"); 221 ch.asyncOpen( 222 new ChannelListener(function () { 223 Assert.ok(!hit_server); 224 Assert.ok(cache.exists(make_uri(resource_age_100_url), "")); 225 226 run_next_test(); 227 }, null) 228 ); 229 }); 230 231 add_test(() => { 232 // The existing entry's age is lesser than the maximum requested, 233 // should go from cache 234 var ch = make_channel(resource_age_100_url, "max-age=1000"); 235 ch.asyncOpen( 236 new ChannelListener(function () { 237 Assert.ok(!hit_server); 238 Assert.ok(cache.exists(make_uri(resource_age_100_url), "")); 239 240 run_next_test(); 241 }, null) 242 ); 243 }); 244 245 // ============================================================================ 246 // Cache-Control: max-stale 247 248 add_test(() => { 249 // Preprate the entry first 250 var ch = make_channel(resource_stale_100_url); 251 ch.asyncOpen( 252 new ChannelListener(function () { 253 Assert.ok(hit_server); 254 Assert.ok(cache.exists(make_uri(resource_stale_100_url), "")); 255 256 // Must shift the expiration time set on the entry to |now| be in the past 257 do_timeout(1500, run_next_test); 258 }, null) 259 ); 260 }); 261 262 add_test(() => { 263 // Check it's not reused (as it's stale) when no special directives 264 // are provided 265 var ch = make_channel(resource_stale_100_url); 266 ch.asyncOpen( 267 new ChannelListener(function () { 268 Assert.ok(hit_server); 269 Assert.ok(cache.exists(make_uri(resource_stale_100_url), "")); 270 271 do_timeout(1500, run_next_test); 272 }, null) 273 ); 274 }); 275 276 add_test(() => { 277 // Accept cached responses of any stale time 278 var ch = make_channel(resource_stale_100_url, "max-stale"); 279 ch.asyncOpen( 280 new ChannelListener(function () { 281 Assert.ok(!hit_server); 282 Assert.ok(cache.exists(make_uri(resource_stale_100_url), "")); 283 284 do_timeout(1500, run_next_test); 285 }, null) 286 ); 287 }); 288 289 add_test(() => { 290 // The entry is stale only by 100 seconds, accept it 291 var ch = make_channel(resource_stale_100_url, "max-stale=1000"); 292 ch.asyncOpen( 293 new ChannelListener(function () { 294 Assert.ok(!hit_server); 295 Assert.ok(cache.exists(make_uri(resource_stale_100_url), "")); 296 297 do_timeout(1500, run_next_test); 298 }, null) 299 ); 300 }); 301 302 add_test(() => { 303 // The entry is stale by 100 seconds but we only accept a 10 seconds stale 304 // entry, go from server 305 var ch = make_channel(resource_stale_100_url, "max-stale=10"); 306 ch.asyncOpen( 307 new ChannelListener(function () { 308 Assert.ok(hit_server); 309 Assert.ok(cache.exists(make_uri(resource_stale_100_url), "")); 310 311 run_next_test(); 312 }, null) 313 ); 314 }); 315 316 // ============================================================================ 317 // Cache-Control: min-fresh 318 319 add_test(() => { 320 // Preprate the entry first 321 var ch = make_channel(resource_fresh_100_url); 322 ch.asyncOpen( 323 new ChannelListener(function () { 324 Assert.ok(hit_server); 325 Assert.ok(cache.exists(make_uri(resource_fresh_100_url), "")); 326 327 run_next_test(); 328 }, null) 329 ); 330 }); 331 332 add_test(() => { 333 // Check it's reused when no special directives are provided 334 var ch = make_channel(resource_fresh_100_url); 335 ch.asyncOpen( 336 new ChannelListener(function () { 337 Assert.ok(!hit_server); 338 Assert.ok(cache.exists(make_uri(resource_fresh_100_url), "")); 339 340 run_next_test(); 341 }, null) 342 ); 343 }); 344 345 add_test(() => { 346 // Entry fresh enough to be served from the cache 347 var ch = make_channel(resource_fresh_100_url, "min-fresh=10"); 348 ch.asyncOpen( 349 new ChannelListener(function () { 350 Assert.ok(!hit_server); 351 Assert.ok(cache.exists(make_uri(resource_fresh_100_url), "")); 352 353 run_next_test(); 354 }, null) 355 ); 356 }); 357 358 add_test(() => { 359 // The entry is not fresh enough 360 var ch = make_channel(resource_fresh_100_url, "min-fresh=1000"); 361 ch.asyncOpen( 362 new ChannelListener(function () { 363 Assert.ok(hit_server); 364 Assert.ok(cache.exists(make_uri(resource_fresh_100_url), "")); 365 366 run_next_test(); 367 }, null) 368 ); 369 }); 370 371 // ============================================================================ 372 // Parser test, if the Cache-Control header would not parse correctly, the entry 373 // doesn't load from the server. 374 375 add_test(() => { 376 var ch = make_channel( 377 resource_fresh_100_url, 378 'unknown1,unknown2 = "a,b", min-fresh = 1000 ' 379 ); 380 ch.asyncOpen( 381 new ChannelListener(function () { 382 Assert.ok(hit_server); 383 Assert.ok(cache.exists(make_uri(resource_fresh_100_url), "")); 384 385 run_next_test(); 386 }, null) 387 ); 388 }); 389 390 add_test(() => { 391 var ch = make_channel(resource_fresh_100_url, "no-cache = , min-fresh = 10"); 392 ch.asyncOpen( 393 new ChannelListener(function () { 394 Assert.ok(hit_server); 395 Assert.ok(cache.exists(make_uri(resource_fresh_100_url), "")); 396 397 run_next_test(); 398 }, null) 399 ); 400 }); 401 402 // ============================================================================ 403 // Done 404 405 add_test(() => { 406 run_next_test(); 407 httpserver.stop(do_test_finished); 408 }); 409 410 // ============================================================================ 411 // Helpers 412 413 function date_string_from_now(delta_secs) { 414 var months = [ 415 "Jan", 416 "Feb", 417 "Mar", 418 "Apr", 419 "May", 420 "Jun", 421 "Jul", 422 "Aug", 423 "Sep", 424 "Oct", 425 "Nov", 426 "Dec", 427 ]; 428 var days = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]; 429 430 var d = new Date(); 431 d.setTime(d.getTime() + delta_secs * 1000); 432 return ( 433 days[d.getUTCDay()] + 434 ", " + 435 d.getUTCDate() + 436 " " + 437 months[d.getUTCMonth()] + 438 " " + 439 d.getUTCFullYear() + 440 " " + 441 d.getUTCHours() + 442 ":" + 443 d.getUTCMinutes() + 444 ":" + 445 d.getUTCSeconds() + 446 " UTC" 447 ); 448 }