preload-resource-match.https.html (6754B)
1 <!doctype html> 2 <script src="/resources/testharness.js"></script> 3 <script src="/resources/testharnessreport.js"></script> 4 <script src="/common/utils.js"></script> 5 <script src="/preload/resources/preload_helper.js"></script> 6 <script src="/common/get-host-info.sub.js"></script> 7 <script> 8 9 const {HTTPS_REMOTE_ORIGIN} = get_host_info(); 10 11 function createEchoURL(text, type) { 12 return `/preload/resources/echo-with-cors.py?type=${ 13 encodeURIComponent(type)}&content=${ 14 encodeURIComponent(text)}&uid=${token()}` 15 } 16 const urls = { 17 image: createEchoURL('<svg xmlns="http://www.w3.org/2000/svg" width="2" height="2" />', 'image/svg+xml'), 18 font: '/preload/resources/font.ttf?x', 19 text: createEchoURL('hello', 'text/plain'), 20 script: createEchoURL('function dummy() { }', 'application/javascript'), 21 style: createEchoURL('.cls { }', 'text/css'), 22 } 23 24 const resourceTypes = { 25 image: {url: urls.image, as: 'image'}, 26 font: {url: urls.font, as: 'font', config: 'anonymous'}, 27 backgroundImage: {url: urls.image, as: 'image', config: 'no-cors'}, 28 fetch: {url: urls.text, as: 'fetch'}, 29 script: {url: urls.script, as: 'script'}, 30 module: {url: urls.script, as: 'script'}, 31 style: {url: urls.style, as: 'style'} 32 } 33 34 const configs = { 35 // The requested URL is from the same origin 36 'same-origin': {crossOrigin: false, attributes: {}}, 37 38 // The requested URL is from a remote origin, without CORS 39 'no-cors': {crossOrigin: true, attributes: {}}, 40 41 // The requested URL is from a remote origin, with CORS (anonymous) 42 'anonymous': {crossOrigin: true, attributes: {crossOrigin: 'anonymous'}}, 43 44 // The requested URL is from a remote origin, with CORS (including credentials) 45 'use-credentials': {crossOrigin: true, attributes: {crossOrigin: 'use-credentials'}}, 46 } 47 48 function preload(attributes, t) { 49 const link = document.createElement('link'); 50 link.rel = "preload"; 51 Object.entries(attributes).forEach(([key, value]) => { 52 if (value) 53 link[key] = value; 54 }); 55 56 document.head.appendChild(link); 57 t.add_cleanup(() => link.remove()); 58 return new Promise(resolve => link.addEventListener('load', resolve)); 59 } 60 61 const loaders = { 62 image: (href, attr, t) => { 63 const img = document.createElement('img'); 64 Object.entries(attr).forEach(([key, value]) => { 65 img[key] = value; 66 }); 67 68 img.src = href 69 70 document.body.appendChild(img); 71 t.add_cleanup(() => img.remove()); 72 return new Promise(resolve => { 73 img.addEventListener('load', resolve); 74 img.addEventListener('error', resolve); 75 }); 76 }, 77 font: async (href, attr, t) => { 78 const style = document.createElement('style'); 79 style.innerHTML = `@font-face { 80 font-family: 'MyFont'; 81 src: url('${href}'); 82 }`; 83 84 document.head.appendChild(style); 85 t.add_cleanup(() => style.remove()); 86 const p = document.createElement('p'); 87 p.style.fontFamily = 'MyFont'; 88 document.body.appendChild(p); 89 t.add_cleanup(() => p.remove()); 90 await document.fonts.ready; 91 }, 92 shape: (href, attr, t) => { 93 const div = document.createElement('div'); 94 div.style.shapeOutside = `url(${href})`; 95 document.body.appendChild(div); 96 t.add_cleanup(() => div.remove()); 97 }, 98 backgroundImage: (href, attr, t) => { 99 const div = document.createElement('div'); 100 div.style.background = `url(${href})`; 101 document.body.appendChild(div); 102 t.add_cleanup(() => div.remove()); 103 }, 104 fetch: async (href, attr, t) => { 105 const options = {mode: attr.crossOrigin ? 'cors' : 'no-cors', 106 credentials: attr.crossOrigin === 'anonymous' ? 'same-origin' : 'include'} 107 108 const response = await fetch(href, options) 109 await response.text(); 110 }, 111 script: async (href, attr, t) => { 112 const script = document.createElement('script'); 113 t.add_cleanup(() => script.remove()); 114 if (attr.crossOrigin) 115 script.setAttribute('crossorigin', attr.crossOrigin); 116 script.src = href; 117 document.body.appendChild(script); 118 await new Promise(resolve => { script.onload = resolve }); 119 }, 120 module: async (href, attr, t) => { 121 const script = document.createElement('script'); 122 script.type = 'module'; 123 t.add_cleanup(() => script.remove()); 124 if (attr.crossOrigin) 125 script.setAttribute('crossorigin', attr.crossOrigin); 126 script.src = href; 127 document.body.appendChild(script); 128 await new Promise(resolve => { script.onload = resolve }); 129 }, 130 style: async (href, attr, t) => { 131 const style = document.createElement('link'); 132 style.rel = 'stylesheet'; 133 style.href = href; 134 t.add_cleanup(() => style.remove()); 135 if (attr.crossOrigin) 136 style.setAttribute('crossorigin', attr.crossOrigin); 137 document.body.appendChild(style); 138 await new Promise(resolve => style.addEventListener('load', resolve)); 139 } 140 } 141 142 function preload_reuse_test(type, as, url, preloadConfig, resourceConfig) { 143 const expected = (preloadConfig === resourceConfig) ? "reuse" : "discard"; 144 const key = token(); 145 const href = getAbsoluteURL(`${ 146 (configs[resourceConfig].crossOrigin ? HTTPS_REMOTE_ORIGIN : '') + url 147 }&${token()}`) 148 promise_test(async t => { 149 await preload({href, as, ...configs[preloadConfig].attributes}, t); 150 await loaders[as](href, configs[resourceConfig].attributes, t); 151 const expectedEntries = expected === "reuse" ? 1 : 2; 152 153 if (numberOfResourceTimingEntries(href) < expectedEntries) 154 await new Promise(resolve => t.step_timeout(resolve, 300)); 155 verifyNumberOfResourceTimingEntries(href, expectedEntries); 156 }, `Loading ${type} (${resourceConfig}) with link (${preloadConfig}) should ${expected} the preloaded response`); 157 } 158 159 for (const [resourceTypeName, resourceInfo] of Object.entries(resourceTypes)) { 160 const configNames = resourceInfo.config ? [resourceInfo.config, 'same-origin'] : Object.keys(configs) 161 for (const resourceConfigName of configNames) { 162 for (const preloadConfigName in configs) { 163 // Same-origin requests ignore their CORS attributes, so no need to match all of them. 164 if ((resourceConfigName === 'same-origin' && preloadConfigName === 'same-origin') || 165 (resourceConfigName !== 'same-origin' && preloadConfigName !== 'same-origin')) 166 preload_reuse_test(resourceTypeName, resourceInfo.as, resourceInfo.url, preloadConfigName, resourceConfigName); 167 } 168 } 169 170 } 171 </script>