cache-add.https.any.js (13924B)
1 // META: title=Cache.add and Cache.addAll 2 // META: global=window,worker 3 // META: script=/common/get-host-info.sub.js 4 // META: script=./resources/test-helpers.js 5 // META: timeout=long 6 7 const { REMOTE_HOST } = get_host_info(); 8 9 cache_test(function(cache, test) { 10 return promise_rejects_js( 11 test, 12 TypeError, 13 cache.add(), 14 'Cache.add should throw a TypeError when no arguments are given.'); 15 }, 'Cache.add called with no arguments'); 16 17 cache_test(function(cache) { 18 return cache.add('./resources/simple.txt') 19 .then(function(result) { 20 assert_equals(result, undefined, 21 'Cache.add should resolve with undefined on success.'); 22 return cache.match('./resources/simple.txt'); 23 }) 24 .then(function(response) { 25 assert_class_string(response, 'Response', 26 'Cache.add should put a resource in the cache.'); 27 return response.text(); 28 }) 29 .then(function(body) { 30 assert_equals(body, 'a simple text file\n', 31 'Cache.add should retrieve the correct body.'); 32 }); 33 }, 'Cache.add called with relative URL specified as a string'); 34 35 cache_test(function(cache, test) { 36 return promise_rejects_js( 37 test, 38 TypeError, 39 cache.add('javascript://this-is-not-http-mmkay'), 40 'Cache.add should throw a TypeError for non-HTTP/HTTPS URLs.'); 41 }, 'Cache.add called with non-HTTP/HTTPS URL'); 42 43 cache_test(function(cache) { 44 var request = new Request('./resources/simple.txt'); 45 return cache.add(request) 46 .then(function(result) { 47 assert_equals(result, undefined, 48 'Cache.add should resolve with undefined on success.'); 49 }); 50 }, 'Cache.add called with Request object'); 51 52 cache_test(function(cache, test) { 53 var request = new Request('./resources/simple.txt', 54 {method: 'POST', body: 'This is a body.'}); 55 return promise_rejects_js( 56 test, 57 TypeError, 58 cache.add(request), 59 'Cache.add should throw a TypeError for non-GET requests.'); 60 }, 'Cache.add called with POST request'); 61 62 cache_test(function(cache) { 63 var request = new Request('./resources/simple.txt'); 64 return cache.add(request) 65 .then(function(result) { 66 assert_equals(result, undefined, 67 'Cache.add should resolve with undefined on success.'); 68 }) 69 .then(function() { 70 return cache.add(request); 71 }) 72 .then(function(result) { 73 assert_equals(result, undefined, 74 'Cache.add should resolve with undefined on success.'); 75 }); 76 }, 'Cache.add called twice with the same Request object'); 77 78 cache_test(function(cache) { 79 var request = new Request('./resources/simple.txt'); 80 return request.text() 81 .then(function() { 82 assert_false(request.bodyUsed); 83 }) 84 .then(function() { 85 return cache.add(request); 86 }); 87 }, 'Cache.add with request with null body (not consumed)'); 88 89 cache_test(function(cache, test) { 90 return promise_rejects_js( 91 test, 92 TypeError, 93 cache.add('./resources/fetch-status.py?status=206'), 94 'Cache.add should reject on partial response'); 95 }, 'Cache.add with 206 response'); 96 97 cache_test(function(cache, test) { 98 var urls = ['./resources/fetch-status.py?status=206', 99 './resources/fetch-status.py?status=200']; 100 var requests = urls.map(function(url) { 101 return new Request(url); 102 }); 103 return promise_rejects_js( 104 test, 105 TypeError, 106 cache.addAll(requests), 107 'Cache.addAll should reject with TypeError if any request fails'); 108 }, 'Cache.addAll with 206 response'); 109 110 cache_test(function(cache, test) { 111 var urls = ['./resources/fetch-status.py?status=206', 112 './resources/fetch-status.py?status=200']; 113 var requests = urls.map(function(url) { 114 var cross_origin_url = new URL(url, location.href); 115 cross_origin_url.hostname = REMOTE_HOST; 116 return new Request(cross_origin_url.href, { mode: 'no-cors' }); 117 }); 118 return promise_rejects_js( 119 test, 120 TypeError, 121 cache.addAll(requests), 122 'Cache.addAll should reject with TypeError if any request fails'); 123 }, 'Cache.addAll with opaque-filtered 206 response'); 124 125 cache_test(function(cache, test) { 126 return promise_rejects_js( 127 test, 128 TypeError, 129 cache.add('this-does-not-exist-please-dont-create-it'), 130 'Cache.add should reject if response is !ok'); 131 }, 'Cache.add with request that results in a status of 404'); 132 133 134 cache_test(function(cache, test) { 135 return promise_rejects_js( 136 test, 137 TypeError, 138 cache.add('./resources/fetch-status.py?status=500'), 139 'Cache.add should reject if response is !ok'); 140 }, 'Cache.add with request that results in a status of 500'); 141 142 cache_test(function(cache, test) { 143 return promise_rejects_js( 144 test, 145 TypeError, 146 cache.addAll(), 147 'Cache.addAll with no arguments should throw TypeError.'); 148 }, 'Cache.addAll with no arguments'); 149 150 cache_test(function(cache, test) { 151 // Assumes the existence of ../resources/simple.txt and ../resources/blank.html 152 var urls = ['./resources/simple.txt', undefined, './resources/blank.html']; 153 return promise_rejects_js( 154 test, 155 TypeError, 156 cache.addAll(urls), 157 'Cache.addAll should throw TypeError for an undefined argument.'); 158 }, 'Cache.addAll with a mix of valid and undefined arguments'); 159 160 cache_test(function(cache) { 161 return cache.addAll([]) 162 .then(function(result) { 163 assert_equals(result, undefined, 164 'Cache.addAll should resolve with undefined on ' + 165 'success.'); 166 return cache.keys(); 167 }) 168 .then(function(result) { 169 assert_equals(result.length, 0, 170 'There should be no entry in the cache.'); 171 }); 172 }, 'Cache.addAll with an empty array'); 173 174 cache_test(function(cache) { 175 // Assumes the existence of ../resources/simple.txt and 176 // ../resources/blank.html 177 var urls = ['./resources/simple.txt', 178 self.location.href, 179 './resources/blank.html']; 180 return cache.addAll(urls) 181 .then(function(result) { 182 assert_equals(result, undefined, 183 'Cache.addAll should resolve with undefined on ' + 184 'success.'); 185 return Promise.all( 186 urls.map(function(url) { return cache.match(url); })); 187 }) 188 .then(function(responses) { 189 assert_class_string( 190 responses[0], 'Response', 191 'Cache.addAll should put a resource in the cache.'); 192 assert_class_string( 193 responses[1], 'Response', 194 'Cache.addAll should put a resource in the cache.'); 195 assert_class_string( 196 responses[2], 'Response', 197 'Cache.addAll should put a resource in the cache.'); 198 return Promise.all( 199 responses.map(function(response) { return response.text(); })); 200 }) 201 .then(function(bodies) { 202 assert_equals( 203 bodies[0], 'a simple text file\n', 204 'Cache.add should retrieve the correct body.'); 205 assert_equals( 206 bodies[2], '<!DOCTYPE html>\n<title>Empty doc</title>\n', 207 'Cache.add should retrieve the correct body.'); 208 }); 209 }, 'Cache.addAll with string URL arguments'); 210 211 cache_test(function(cache) { 212 // Assumes the existence of ../resources/simple.txt and 213 // ../resources/blank.html 214 var urls = ['./resources/simple.txt', 215 self.location.href, 216 './resources/blank.html']; 217 var requests = urls.map(function(url) { 218 return new Request(url); 219 }); 220 return cache.addAll(requests) 221 .then(function(result) { 222 assert_equals(result, undefined, 223 'Cache.addAll should resolve with undefined on ' + 224 'success.'); 225 return Promise.all( 226 urls.map(function(url) { return cache.match(url); })); 227 }) 228 .then(function(responses) { 229 assert_class_string( 230 responses[0], 'Response', 231 'Cache.addAll should put a resource in the cache.'); 232 assert_class_string( 233 responses[1], 'Response', 234 'Cache.addAll should put a resource in the cache.'); 235 assert_class_string( 236 responses[2], 'Response', 237 'Cache.addAll should put a resource in the cache.'); 238 return Promise.all( 239 responses.map(function(response) { return response.text(); })); 240 }) 241 .then(function(bodies) { 242 assert_equals( 243 bodies[0], 'a simple text file\n', 244 'Cache.add should retrieve the correct body.'); 245 assert_equals( 246 bodies[2], '<!DOCTYPE html>\n<title>Empty doc</title>\n', 247 'Cache.add should retrieve the correct body.'); 248 }); 249 }, 'Cache.addAll with Request arguments'); 250 251 cache_test(function(cache, test) { 252 // Assumes that ../resources/simple.txt and ../resources/blank.html exist. 253 // The second resource does not. 254 var urls = ['./resources/simple.txt', 255 'this-resource-should-not-exist', 256 './resources/blank.html']; 257 var requests = urls.map(function(url) { 258 return new Request(url); 259 }); 260 return promise_rejects_js( 261 test, 262 TypeError, 263 cache.addAll(requests), 264 'Cache.addAll should reject with TypeError if any request fails') 265 .then(function() { 266 return Promise.all(urls.map(function(url) { 267 return cache.match(url); 268 })); 269 }) 270 .then(function(matches) { 271 assert_array_equals( 272 matches, 273 [undefined, undefined, undefined], 274 'If any response fails, no response should be added to cache'); 275 }); 276 }, 'Cache.addAll with a mix of succeeding and failing requests'); 277 278 cache_test(function(cache, test) { 279 var request = new Request('../resources/simple.txt'); 280 return promise_rejects_dom( 281 test, 282 'InvalidStateError', 283 cache.addAll([request, request]), 284 'Cache.addAll should throw InvalidStateError if the same request is added ' + 285 'twice.'); 286 }, 'Cache.addAll called with the same Request object specified twice'); 287 288 cache_test(async function(cache, test) { 289 const url = './resources/vary.py?vary=x-shape'; 290 let requests = [ 291 new Request(url, { headers: { 'x-shape': 'circle' }}), 292 new Request(url, { headers: { 'x-shape': 'square' }}), 293 ]; 294 let result = await cache.addAll(requests); 295 assert_equals(result, undefined, 'Cache.addAll() should succeed'); 296 }, 'Cache.addAll should succeed when entries differ by vary header'); 297 298 cache_test(async function(cache, test) { 299 const url = './resources/vary.py?vary=x-shape'; 300 let requests = [ 301 new Request(url, { headers: { 'x-shape': 'circle' }}), 302 new Request(url, { headers: { 'x-shape': 'circle' }}), 303 ]; 304 await promise_rejects_dom( 305 test, 306 'InvalidStateError', 307 cache.addAll(requests), 308 'Cache.addAll() should reject when entries are duplicate by vary header'); 309 }, 'Cache.addAll should reject when entries are duplicate by vary header'); 310 311 // VARY header matching is asymmetric. Determining if two entries are duplicate 312 // depends on which entry's response is used in the comparison. The target 313 // response's VARY header determines what request headers are examined. This 314 // test verifies that Cache.addAll() duplicate checking handles this asymmetric 315 // behavior correctly. 316 cache_test(async function(cache, test) { 317 const base_url = './resources/vary.py'; 318 319 // Define a request URL that sets a VARY header in the 320 // query string to be echoed back by the server. 321 const url = base_url + '?vary=x-size'; 322 323 // Set a cookie to override the VARY header of the response 324 // when the request is made with credentials. This will 325 // take precedence over the query string vary param. This 326 // is a bit confusing, but it's necessary to construct a test 327 // where the URL is the same, but the VARY headers differ. 328 // 329 // Note, the test could also pass this information in additional 330 // request headers. If the cookie approach becomes too unwieldy 331 // this test could be rewritten to use that technique. 332 await fetch(base_url + '?set-vary-value-override-cookie=x-shape'); 333 test.add_cleanup(_ => fetch(base_url + '?clear-vary-value-override-cookie')); 334 335 let requests = [ 336 // This request will result in a Response with a "Vary: x-shape" 337 // header. This *will not* result in a duplicate match with the 338 // other entry. 339 new Request(url, { headers: { 'x-shape': 'circle', 340 'x-size': 'big' }, 341 credentials: 'same-origin' }), 342 343 // This request will result in a Response with a "Vary: x-size" 344 // header. This *will* result in a duplicate match with the other 345 // entry. 346 new Request(url, { headers: { 'x-shape': 'square', 347 'x-size': 'big' }, 348 credentials: 'omit' }), 349 ]; 350 await promise_rejects_dom( 351 test, 352 'InvalidStateError', 353 cache.addAll(requests), 354 'Cache.addAll() should reject when one entry has a vary header ' + 355 'matching an earlier entry.'); 356 357 // Test the reverse order now. 358 await promise_rejects_dom( 359 test, 360 'InvalidStateError', 361 cache.addAll(requests.reverse()), 362 'Cache.addAll() should reject when one entry has a vary header ' + 363 'matching a later entry.'); 364 365 }, 'Cache.addAll should reject when one entry has a vary header ' + 366 'matching another entry'); 367 368 done();