// test bug 1312774. // Create 6 (=network.http.max-persistent-connections-per-server) // common Http requests and 2 urgent-start Http requests to a single // host and path, in parallel. // Let all the requests unanswered by the server handler. (process them // async and don't finish) // The first 6 pending common requests will fill the limit for per-server // parallelism. // But the two urgent requests must reach the server despite those 6 common // pending requests. // The server handler doesn't let the test finish until all 8 expected requests // arrive. // Note: if the urgent request handling is broken (the urgent-marked requests // get blocked by queuing) this test will time out "use strict"; const { HttpServer } = ChromeUtils.importESModule( "resource://testing-common/httpd.sys.mjs" ); var server = new HttpServer(); server.start(-1); var baseURL = "http://localhost:" + server.identity.primaryPort + "/"; var maxConnections = 0; var urgentRequests = 0; var debug = false; function log(msg) { if (!debug) { return; } if (msg) { dump("TEST INFO | " + msg + "\n"); } } function make_channel(url) { var request = NetUtil.newChannel({ uri: url, loadUsingSystemPrincipal: true, }); request.QueryInterface(Ci.nsIHttpChannel); return request; } function serverStopListener() { server.stop(); } function commonHttpRequest(id) { let uri = baseURL; var chan = make_channel(uri); var listner = new HttpResponseListener(id); chan.setRequestHeader("X-ID", id, false); chan.setRequestHeader("Cache-control", "no-store", false); chan.asyncOpen(listner); log("Create common http request id=" + id); } function urgentStartHttpRequest(id) { let uri = baseURL; var chan = make_channel(uri); var listner = new HttpResponseListener(id); var cos = chan.QueryInterface(Ci.nsIClassOfService); cos.addClassFlags(Ci.nsIClassOfService.UrgentStart); chan.setRequestHeader("X-ID", id, false); chan.setRequestHeader("Cache-control", "no-store", false); chan.asyncOpen(listner); log("Create urgent-start http request id=" + id); } function setup_httpRequests() { log("setup_httpRequests"); for (var i = 0; i < maxConnections; i++) { commonHttpRequest(i); do_test_pending(); } } function setup_urgentStartRequests() { for (var i = 0; i < urgentRequests; i++) { urgentStartHttpRequest(1000 + i); do_test_pending(); } } function HttpResponseListener(id) { this.id = id; } HttpResponseListener.prototype = { onStartRequest(request) {}, onDataAvailable(request, stream, off, cnt) {}, onStopRequest(request, status) { log("STOP id=" + this.id); do_test_finished(); }, }; var responseQueue = []; function setup_http_server() { log("setup_http_server"); maxConnections = Services.prefs.getIntPref( "network.http.max-persistent-connections-per-server" ); urgentRequests = 2; var allCommonHttpRequestReceived = false; // Start server; will be stopped at test cleanup time. server.registerPathHandler("/", function (metadata, response) { var id = metadata.getHeader("X-ID"); log("Server recived the response id=" + id); response.processAsync(); responseQueue.push(response); if ( responseQueue.length == maxConnections && !allCommonHttpRequestReceived ) { allCommonHttpRequestReceived = true; setup_urgentStartRequests(); } // Wait for all expected requests to come but don't process then. // Collect them in a queue for later processing. We don't want to // respond to the client until all the expected requests are made // to the server. if (responseQueue.length == maxConnections + urgentRequests) { processResponse(); } }); registerCleanupFunction(function () { server.stop(serverStopListener); }); } function processResponse() { while (responseQueue.length) { var resposne = responseQueue.pop(); resposne.finish(); } } function run_test() { setup_http_server(); setup_httpRequests(); }