test_http3_alt_svc.js (5852B)
1 "use strict"; 2 3 const { HTTP3Server } = ChromeUtils.importESModule( 4 "resource://testing-common/NodeServer.sys.mjs" 5 ); 6 7 let httpsOrigin; 8 let h3AltSvc; 9 let h3Route; 10 let h3Port; 11 let h3ServerPath; 12 let h3DBPath; 13 let prefs; 14 15 let tests = [ 16 test_https_alt_svc, 17 test_https_alt_svc_1, 18 test_https_speculativeConnect_alt_svc, 19 testsDone, 20 ]; 21 22 let current_test = 0; 23 24 function run_next_test() { 25 if (current_test < tests.length) { 26 dump("starting test number " + current_test + "\n"); 27 tests[current_test](); 28 current_test++; 29 } 30 } 31 32 function setupAltSvc() { 33 h3AltSvc = ":" + h3Port; 34 h3Route = "foo.example.com:" + h3Port; 35 } 36 37 function run_test() { 38 let h2Port = Services.env.get("MOZHTTP2_PORT"); 39 Assert.notEqual(h2Port, null); 40 Assert.notEqual(h2Port, ""); 41 42 h3ServerPath = Services.env.get("MOZ_HTTP3_SERVER_PATH"); 43 h3DBPath = Services.env.get("MOZ_HTTP3_CERT_DB_PATH"); 44 45 do_get_profile(); 46 prefs = Services.prefs; 47 48 prefs.setBoolPref("network.http.http3.enable", true); 49 prefs.setCharPref("network.dns.localDomains", "foo.example.com"); 50 // We always resolve elements of localDomains as it's hardcoded without the 51 // following pref: 52 prefs.setBoolPref("network.proxy.allow_hijacking_localhost", true); 53 54 // The certificate for the http3server server is for foo.example.com and 55 // is signed by http2-ca.pem so add that cert to the trust list as a 56 // signing cert. 57 let certdb = Cc["@mozilla.org/security/x509certdb;1"].getService( 58 Ci.nsIX509CertDB 59 ); 60 addCertFromFile(certdb, "http2-ca.pem", "CTu,u,u"); 61 httpsOrigin = "https://foo.example.com:" + h2Port + "/"; 62 63 run_next_test(); 64 } 65 66 function createPrincipal(url) { 67 var ssm = Services.scriptSecurityManager; 68 try { 69 return ssm.createContentPrincipal(Services.io.newURI(url), {}); 70 } catch (e) { 71 return null; 72 } 73 } 74 75 function makeChan(uri) { 76 let chan = NetUtil.newChannel({ 77 uri, 78 loadingPrincipal: createPrincipal(uri), 79 securityFlags: Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_INHERITS_SEC_CONTEXT, 80 contentPolicyType: Ci.nsIContentPolicy.TYPE_DOCUMENT, 81 }).QueryInterface(Ci.nsIHttpChannel); 82 chan.loadFlags = Ci.nsIChannel.LOAD_INITIAL_DOCUMENT_URI; 83 return chan; 84 } 85 86 let WaitForHttp3Listener = function (expectedH3Version) { 87 this._expectedH3Version = expectedH3Version; 88 }; 89 90 WaitForHttp3Listener.prototype = { 91 onDataAvailableFired: false, 92 expectedRoute: "", 93 94 onStartRequest: function testOnStartRequest(request) { 95 Assert.ok(request instanceof Ci.nsIHttpChannel); 96 Assert.equal(request.responseStatus, 200); 97 }, 98 99 onDataAvailable: function testOnDataAvailable(request, stream, off, cnt) { 100 this.onDataAvailableFired = true; 101 read_stream(stream, cnt); 102 }, 103 104 onStopRequest: function testOnStopRequest(request) { 105 let routed = "NA"; 106 try { 107 routed = request.getRequestHeader("Alt-Used"); 108 } catch (e) {} 109 dump("routed is " + routed + "\n"); 110 111 if (routed == this.expectedRoute) { 112 let httpVersion = ""; 113 try { 114 httpVersion = request.protocolVersion; 115 } catch (e) {} 116 Assert.equal(httpVersion, this._expectedH3Version); 117 run_next_test(); 118 } else { 119 dump("poll later for alt svc mapping\n"); 120 do_test_pending(); 121 do_timeout(500, () => { 122 doTest( 123 this.uri, 124 this.expectedRoute, 125 this.h3AltSvc, 126 this._expectedH3Version 127 ); 128 }); 129 } 130 131 do_test_finished(); 132 }, 133 }; 134 135 function doTest(uri, expectedRoute, altSvc, expectedH3Version) { 136 let chan = makeChan(uri); 137 let listener = new WaitForHttp3Listener(expectedH3Version); 138 listener.uri = uri; 139 listener.expectedRoute = expectedRoute; 140 listener.h3AltSvc = altSvc; 141 chan.setRequestHeader("x-altsvc", altSvc, false); 142 chan.asyncOpen(listener); 143 } 144 145 // Test Alt-Svc for http3. 146 // H2 server returns alt-svc=h2=foo2.example.com:8000,h3=:h3port 147 function test_https_alt_svc() { 148 dump("test_https_alt_svc()\n"); 149 150 do_test_pending(); 151 152 let server = new HTTP3Server(); 153 server 154 .start(h3ServerPath, h3DBPath) 155 .then(() => { 156 h3Port = server.port(); 157 setupAltSvc(); 158 doTest(httpsOrigin + "http3-test2", h3Route, h3AltSvc, "h3"); 159 }) 160 .catch(_ => {}); 161 } 162 163 // Test if we use the latest version of HTTP/3. 164 // H2 server returns alt-svc=h3=:h3port,h3=:h3port 165 function test_https_alt_svc_1() { 166 dump("test_https_alt_svc_1()\n"); 167 Services.obs.notifyObservers(null, "last-pb-context-exited"); 168 Services.obs.notifyObservers(null, "net:cancel-all-connections"); 169 170 do_test_pending(); 171 172 let server = new HTTP3Server(); 173 server 174 .start(h3ServerPath, h3DBPath) 175 .then(() => { 176 h3Port = server.port(); 177 setupAltSvc(); 178 doTest(httpsOrigin + "http3-test3", h3Route, h3AltSvc, "h3"); 179 }) 180 .catch(_ => {}); 181 } 182 183 function test_https_speculativeConnect_alt_svc() { 184 dump("test_https_speculativeConnect_alt_svc()\n"); 185 186 do_test_pending(); 187 188 let observer = { 189 QueryInterface: ChromeUtils.generateQI(["nsIObserver"]), 190 observe(aSubject, aTopic, aData) { 191 if (aTopic == "speculative-connect-request") { 192 Services.obs.removeObserver(observer, "speculative-connect-request"); 193 info("h3Route=" + h3Route + "\n"); 194 info("aData=" + aData + "\n"); 195 Assert.ok(aData.includes(`<ROUTE-via ${h3Route}`)); 196 do_test_finished(); 197 } 198 }, 199 }; 200 Services.obs.addObserver(observer, "speculative-connect-request"); 201 202 Services.prefs.setBoolPref("network.http.debug-observations", true); 203 204 let uri = Services.io.newURI(httpsOrigin); 205 Services.io.speculativeConnect( 206 uri, 207 Services.scriptSecurityManager.getSystemPrincipal(), 208 null, 209 false 210 ); 211 } 212 213 function testsDone() { 214 prefs.clearUserPref("network.http.http3.enable"); 215 prefs.clearUserPref("network.dns.localDomains"); 216 prefs.clearUserPref("network.proxy.allow_hijacking_localhost"); 217 dump("testDone\n"); 218 }