test_stale-while-revalidate_max-age-0.js (3248B)
1 /* 2 3 Tests the Cache-control: stale-while-revalidate response directive. 4 5 Purpose is to check we perform the background revalidation when max-age=0 but 6 the window is set and we hit it. 7 8 * Make request #1. 9 - response is from the server and version=1 10 - max-age=0, stale-while-revalidate=9999 11 * Switch version of the data on the server and prolong the max-age to not let req #3 12 do a bck reval at the end of the test (prevent leaks/shutdown races.) 13 * Make request #2 in 2 seconds (entry should be expired by that time, but fall into 14 the reval window.) 15 - response is from the cache, version=1 16 - a new background request should be made for the data 17 * Wait for "http-on-background-revalidation" notifying finish of the background reval. 18 * Make request #3. 19 - response is from the cache, version=2 20 * Done. 21 22 */ 23 24 "use strict"; 25 26 const { HttpServer } = ChromeUtils.importESModule( 27 "resource://testing-common/httpd.sys.mjs" 28 ); 29 30 let max_age; 31 let version; 32 let generate_response = ver => `response version=${ver}`; 33 34 function test_handler(metadata, response) { 35 const originalBody = generate_response(version); 36 response.setHeader("Content-Type", "text/html", false); 37 response.setHeader( 38 "Cache-control", 39 `max-age=${max_age}, stale-while-revalidate=9999`, 40 false 41 ); 42 response.setStatusLine(metadata.httpVersion, 200, "OK"); 43 response.bodyOutputStream.write(originalBody, originalBody.length); 44 } 45 46 function make_channel(url) { 47 return NetUtil.newChannel({ 48 uri: url, 49 loadUsingSystemPrincipal: true, 50 }).QueryInterface(Ci.nsIHttpChannel); 51 } 52 53 async function get_response(channel, fromCache) { 54 return new Promise(resolve => { 55 channel.asyncOpen( 56 new ChannelListener((request, buffer, ctx, isFromCache) => { 57 Assert.equal( 58 fromCache, 59 isFromCache, 60 `got response from cache = ${fromCache}` 61 ); 62 resolve(buffer); 63 }) 64 ); 65 }); 66 } 67 68 async function sleep(time) { 69 return new Promise(resolve => { 70 do_timeout(time * 1000, resolve); 71 }); 72 } 73 74 async function stop_server(httpserver) { 75 return new Promise(resolve => { 76 httpserver.stop(resolve); 77 }); 78 } 79 80 async function background_reval_promise() { 81 return new Promise(resolve => { 82 Services.obs.addObserver(resolve, "http-on-background-revalidation"); 83 }); 84 } 85 86 add_task(async function () { 87 let httpserver = new HttpServer(); 88 httpserver.registerPathHandler("/testdir", test_handler); 89 httpserver.start(-1); 90 const PORT = httpserver.identity.primaryPort; 91 const URI = `http://localhost:${PORT}/testdir`; 92 93 let response; 94 95 version = 1; 96 max_age = 0; 97 response = await get_response(make_channel(URI), false); 98 Assert.equal(response, generate_response(1), "got response ver 1"); 99 100 await sleep(2); 101 102 // must specifically wait for the internal channel to finish the reval to make 103 // the test race-free. 104 let reval_done = background_reval_promise(); 105 106 version = 2; 107 max_age = 100; 108 response = await get_response(make_channel(URI), true); 109 Assert.equal(response, generate_response(1), "got response ver 1"); 110 111 await reval_done; 112 113 response = await get_response(make_channel(URI), true); 114 Assert.equal(response, generate_response(2), "got response ver 2"); 115 116 await stop_server(httpserver); 117 });