early_hint_preload_test_helper.sys.mjs (5424B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 import { Assert } from "resource://testing-common/Assert.sys.mjs"; 6 import { BrowserTestUtils } from "resource://testing-common/BrowserTestUtils.sys.mjs"; 7 8 const { gBrowser } = Services.wm.getMostRecentWindow("navigator:browser"); 9 10 export async function request_count_checking(testName, got, expected) { 11 // stringify to pretty print assert output 12 let g = JSON.stringify(got); 13 let e = JSON.stringify(expected); 14 // each early hint request can starts one hinted request, but doesn't yet 15 // complete the early hint request during the test case 16 Assert.ok( 17 got.hinted == expected.hinted, 18 `${testName}: unexpected amount of hinted request made expected ${expected.hinted} (${e}), got ${got.hinted} (${g})` 19 ); 20 // when the early hint request doesn't complete fast enough, another request 21 // is currently sent from the main document 22 let expected_normal = expected.normal; 23 Assert.ok( 24 got.normal == expected_normal, 25 `${testName}: unexpected amount of normal request made expected ${expected_normal} (${e}), got ${got.normal} (${g})` 26 ); 27 } 28 29 export async function test_hint_preload( 30 testName, 31 requestFrom, 32 imgUrl, 33 expectedRequestCount, 34 uuid = undefined 35 ) { 36 // generate a uuid if none were passed 37 if (uuid == undefined) { 38 uuid = Services.uuid.generateUUID(); 39 } 40 await test_hint_preload_internal( 41 testName, 42 requestFrom, 43 [[imgUrl, uuid.toString()]], 44 expectedRequestCount 45 ); 46 } 47 48 // - testName is just there to be printed during Asserts when failing 49 // - the baseUrl can't have query strings, because they are currently used to pass 50 // the early hint the server responds with 51 // - urls are in the form [[url1, uuid1], ...]. The uuids are there to make each preload 52 // unique and not available in the cache from other test cases 53 // - expectedRequestCount is the sum of all requested objects { normal: count, hinted: count } 54 export async function test_hint_preload_internal( 55 testName, 56 requestFrom, 57 imgUrls, 58 expectedRequestCount 59 ) { 60 // reset the count 61 let headers = new Headers(); 62 headers.append("X-Early-Hint-Count-Start", ""); 63 await fetch( 64 "http://example.com/browser/netwerk/test/browser/early_hint_pixel_count.sjs", 65 { headers } 66 ); 67 68 let requestUrl = 69 requestFrom + 70 "/browser/netwerk/test/browser/early_hint_main_html.sjs?" + 71 new URLSearchParams(imgUrls).toString(); // encode the hinted images as query string 72 73 await BrowserTestUtils.withNewTab( 74 { 75 gBrowser, 76 url: requestUrl, 77 waitForLoad: true, 78 }, 79 async function () {} 80 ); 81 82 let gotRequestCount = await fetch( 83 "http://example.com/browser/netwerk/test/browser/early_hint_pixel_count.sjs" 84 ).then(response => response.json()); 85 86 await request_count_checking(testName, gotRequestCount, expectedRequestCount); 87 } 88 89 // Verify that CSP policies in both the 103 response as well as the main response are respected. 90 // e.g. 91 // 103 Early Hint 92 // Content-Security-Policy: style-src: self; 93 // Link: </style.css>; rel=preload; as=style 94 // 200 OK 95 // Content-Security-Policy: style-src: none; 96 // Link: </font.ttf>; rel=preload; as=font 97 98 // Server-side we verify that: 99 // - the hinted preload request was made as expected 100 // - the load request request was made as expected 101 // Client-side, we verify that the image was loaded or not loaded, depending on the scenario 102 103 // This verifies preload hints and requests 104 export async function test_preload_hint_and_request(input, expected_results) { 105 // reset the count 106 let headers = new Headers(); 107 headers.append("X-Early-Hint-Count-Start", ""); 108 await fetch( 109 "https://example.com/browser/netwerk/test/browser/early_hint_pixel_count.sjs", 110 { headers } 111 ); 112 113 let requestUrl = `https://example.com/browser/netwerk/test/browser/early_hint_csp_options_html.sjs?as=${ 114 input.resource_type 115 }&hinted=${input.hinted ? "1" : "0"}${input.csp ? "&csp=" + input.csp : ""}${ 116 input.csp_in_early_hint 117 ? "&csp_in_early_hint=" + input.csp_in_early_hint 118 : "" 119 }${input.host ? "&host=" + input.host : ""}`; 120 121 await BrowserTestUtils.openNewForegroundTab(gBrowser, requestUrl, true); 122 123 let gotRequestCount = await fetch( 124 "https://example.com/browser/netwerk/test/browser/early_hint_pixel_count.sjs" 125 ).then(response => response.json()); 126 127 await Assert.deepEqual(gotRequestCount, expected_results, input.test_name); 128 129 gBrowser.removeCurrentTab(); 130 Services.cache2.clear(); 131 } 132 133 // simple loading of one url and then checking the request count against the 134 // passed expected count 135 export async function test_preload_url(testName, url, expectedRequestCount) { 136 // reset the count 137 let headers = new Headers(); 138 headers.append("X-Early-Hint-Count-Start", ""); 139 await fetch( 140 "http://example.com/browser/netwerk/test/browser/early_hint_pixel_count.sjs", 141 { headers } 142 ); 143 144 await BrowserTestUtils.withNewTab( 145 { 146 gBrowser, 147 url, 148 waitForLoad: true, 149 }, 150 async function () {} 151 ); 152 153 let gotRequestCount = await fetch( 154 "http://example.com/browser/netwerk/test/browser/early_hint_pixel_count.sjs" 155 ).then(response => response.json()); 156 157 await request_count_checking(testName, gotRequestCount, expectedRequestCount); 158 Services.cache2.clear(); 159 }