head.js (7245B)
1 /* Any copyright is dedicated to the Public Domain. 2 * http://creativecommons.org/publicdomain/zero/1.0/ */ 3 4 "use strict"; 5 6 const { NetUtil } = ChromeUtils.importESModule( 7 "resource://gre/modules/NetUtil.sys.mjs" 8 ); 9 const { MockRegistrar } = ChromeUtils.importESModule( 10 "resource://testing-common/MockRegistrar.sys.mjs" 11 ); 12 const { MozCachedOHTTPProtocolHandler } = ChromeUtils.importESModule( 13 "moz-src:///browser/components/mozcachedohttp/MozCachedOHTTPProtocolHandler.sys.mjs" 14 ); 15 16 do_get_profile(); 17 18 ChromeUtils.registerProcessActor("MozCachedOHTTP", { 19 parent: { 20 esModuleURI: 21 "moz-src:///browser/components/mozcachedohttp/actors/MozCachedOHTTPParent.sys.mjs", 22 }, 23 includeParent: true, 24 }); 25 26 /** 27 * Creates a test URI for the moz-cached-ohttp protocol. 28 * 29 * @param {string} resourceURL - The target resource URL to encode 30 * @returns {string} The moz-cached-ohttp:// URI 31 */ 32 function createTestOHTTPResourceURI(resourceURL) { 33 const encodedURL = encodeURIComponent(resourceURL); 34 return `moz-cached-ohttp://newtab-image/?url=${encodedURL}`; 35 } 36 37 /** 38 * Creates a test channel with proper load info for privileged about content. 39 * Always creates a MozCachedOHTTPChannel with the injected mock service. 40 * 41 * @param {string} uri - The URI to create a channel for 42 * @returns {nsIChannel} The created channel 43 */ 44 function createTestChannel(uri) { 45 const testURI = Services.io.newURI(uri); 46 const principal = Services.scriptSecurityManager.getSystemPrincipal(); 47 const protocolHandler = new MozCachedOHTTPProtocolHandler(); 48 protocolHandler.injectOHTTPService(MockOHTTPService); 49 50 const loadInfo = createLoadInfo( 51 testURI, 52 principal, 53 Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_INHERITS_SEC_CONTEXT, 54 Ci.nsIContentPolicy.TYPE_OTHER 55 ); 56 57 return protocolHandler.newChannel(testURI, loadInfo); 58 } 59 60 /** 61 * Creates a LoadInfo object for testing using the NetUtil.newChannel pattern. 62 * 63 * @param {nsIURI} uri - The URI to use for the temporary channel 64 * @param {nsIPrincipal} loadingPrincipal - The loading principal 65 * @param {number} securityFlags - Security flags 66 * @param {number} contentPolicyType - Content policy type 67 * @returns {nsILoadInfo} LoadInfo object 68 */ 69 function createLoadInfo( 70 uri, 71 loadingPrincipal, 72 securityFlags, 73 contentPolicyType 74 ) { 75 return NetUtil.newChannel({ 76 uri, 77 loadingPrincipal, 78 securityFlags, 79 contentPolicyType, 80 }).loadInfo; 81 } 82 83 /** 84 * Creates a reusable data collecting listener for testing channel responses. 85 * 86 * @param {Function} onComplete 87 * Callback executed on completion with (data, success). 88 * @returns {nsIStreamListener} 89 * Stream listener implementation 90 */ 91 function createDataCollectingListener(onComplete) { 92 let receivedData = ""; 93 94 return { 95 onStartRequest() {}, 96 97 onDataAvailable(request, inputStream, offset, count) { 98 const binaryInputStream = Cc[ 99 "@mozilla.org/binaryinputstream;1" 100 ].createInstance(Ci.nsIBinaryInputStream); 101 binaryInputStream.setInputStream(inputStream); 102 receivedData += binaryInputStream.readBytes(count); 103 }, 104 105 onStopRequest(request, status) { 106 const success = Components.isSuccessCode(status); 107 onComplete(receivedData, success); 108 }, 109 }; 110 } 111 112 /** 113 * Creates a simple completion listener for testing channel success/failure. 114 * 115 * @param {Function} onComplete 116 * Callback executed on completion with (success). 117 * @returns {nsIStreamListener} 118 * Stream listener implementation 119 */ 120 function createCompletionListener(onComplete) { 121 let receivedData = false; 122 123 return { 124 onStartRequest() {}, 125 126 onDataAvailable() { 127 receivedData = true; 128 }, 129 130 onStopRequest(request, status) { 131 const success = Components.isSuccessCode(status); 132 onComplete(success, receivedData); 133 }, 134 }; 135 } 136 137 /** 138 * Mock OHTTP service for testing. 139 * Simulates nsIObliviousHttpService behavior for protocol handler testing. 140 */ 141 const MockOHTTPService = { 142 channelCreated: false, 143 totalChannels: 0, 144 lastRelayURI: null, 145 lastTargetURI: null, 146 lastConfig: null, 147 shouldSucceed: true, 148 shouldUseContentTypeHeader: "", 149 150 /** 151 * Creates a mock channel that simulates OHTTP behavior. 152 * 153 * @param {nsIURI} relayURI 154 * The OHTTP relay URI. 155 * @param {nsIURI} targetURI 156 * The target resource URI. 157 * @param {Uint8Array} config 158 * OHTTP configuration. 159 * @returns {nsIChannel} 160 * Mock channel implementation. 161 */ 162 newChannel(relayURI, targetURI, config) { 163 this.channelCreated = true; 164 this.lastRelayURI = relayURI; 165 this.lastTargetURI = targetURI; 166 this.lastConfig = config; 167 this.totalChannels++; 168 169 return this._createMockChannel( 170 targetURI, 171 this.shouldSucceed, 172 this.shouldUseContentTypeHeader 173 ); 174 }, 175 176 /** 177 * Creates a mock channel with configurable success behavior. 178 * 179 * @param {nsIURI} targetURI 180 * The URI for the channel. 181 * @param {boolean} shouldSucceed 182 * Whether the channel should succeed. 183 * @param {string} shouldUseContentTypeHeader 184 * The Content-Type to have a header value set to, or the empty string 185 * for no Content-Type. 186 * @returns {nsIChannel} 187 * Mock channel implementation. 188 */ 189 _createMockChannel(targetURI, shouldSucceed, shouldUseContentTypeHeader) { 190 return { 191 URI: targetURI, 192 loadInfo: null, 193 loadFlags: 0, 194 notificationCallbacks: null, 195 loadGroup: null, 196 197 asyncOpen(listener) { 198 Services.tm.dispatchToMainThread(() => { 199 this._simulateChannelResponse(listener, shouldSucceed); 200 }); 201 }, 202 203 _simulateChannelResponse(listener, success) { 204 try { 205 listener.onStartRequest(this); 206 207 if (success) { 208 const data = new ArrayBuffer(1024); 209 const inputStream = Cc[ 210 "@mozilla.org/io/arraybuffer-input-stream;1" 211 ].createInstance(Ci.nsIArrayBufferInputStream); 212 inputStream.setData(data, 0, data.byteLength); 213 listener.onDataAvailable(this, inputStream, 0, data.byteLength); 214 } 215 216 listener.onStopRequest( 217 this, 218 success ? Cr.NS_OK : Cr.NS_ERROR_FAILURE 219 ); 220 } catch (e) { 221 listener.onStopRequest(this, Cr.NS_ERROR_FAILURE); 222 } 223 }, 224 225 visitResponseHeaders(visitor) { 226 if (shouldUseContentTypeHeader) { 227 visitor.visitHeader("Content-Type", shouldUseContentTypeHeader); 228 } 229 }, 230 231 QueryInterface: ChromeUtils.generateQI(["nsIChannel", "nsIRequest"]), 232 }; 233 }, 234 235 /** 236 * Resets the mock service state to initial values. 237 */ 238 reset() { 239 this.channelCreated = false; 240 this.totalChannels = 0; 241 this.lastRelayURI = null; 242 this.lastTargetURI = null; 243 this.lastConfig = null; 244 this.shouldSucceed = true; 245 this.shouldUseContentTypeHeader = ""; 246 }, 247 248 QueryInterface: ChromeUtils.generateQI(["nsIObliviousHttpService"]), 249 }; 250 251 add_setup(async () => { 252 registerCleanupFunction(() => { 253 // Invokes OnHandleClosed on any nsICacheEntry instances that have been 254 // used, allowing them to be closed out before the nsICacheStorageService 255 // shuts down (which causes leak assertion failures in debug builds). 256 Cu.forceGC(); 257 }); 258 });