// // HTTP headers test // Response headers can be changed after they have been received, e.g. empty // headers are deleted, some duplicate header are merged (if no error is // thrown), etc. // // The "original header" is introduced to hold the header array in the order // and the form as they have been received from the network. // Here, the "original headers" are tested. // // Original headers will be stored in the cache as well. This test checks // that too. // Note: sets Cc and Ci variables "use strict"; const { HttpServer } = ChromeUtils.importESModule( "resource://testing-common/httpd.sys.mjs" ); ChromeUtils.defineLazyGetter(this, "URL", function () { return "http://localhost:" + httpserver.identity.primaryPort; }); var httpserver = new HttpServer(); var testpath = "/simple"; var httpbody = "0123456789"; var dbg = 1; function run_test() { if (dbg) { print("============== START =========="); } httpserver.registerPathHandler(testpath, serverHandler); httpserver.start(-1); run_next_test(); } add_test(function test_headerChange() { if (dbg) { print("============== test_headerChange setup: in"); } var channel1 = setupChannel(testpath); channel1.loadFlags = Ci.nsIRequest.LOAD_BYPASS_CACHE; // ChannelListener defined in head_channels.js channel1.asyncOpen(new ChannelListener(checkResponse, null)); if (dbg) { print("============== test_headerChange setup: out"); } }); add_test(function test_fromCache() { if (dbg) { print("============== test_fromCache setup: in"); } var channel2 = setupChannel(testpath); channel2.loadFlags = Ci.nsIRequest.LOAD_FROM_CACHE; // ChannelListener defined in head_channels.js channel2.asyncOpen(new ChannelListener(checkResponse, null)); if (dbg) { print("============== test_fromCache setup: out"); } }); add_test(function finish() { if (dbg) { print("============== STOP =========="); } httpserver.stop(do_test_finished); }); function setupChannel(path) { var chan = NetUtil.newChannel({ uri: URL + path, loadUsingSystemPrincipal: true, }).QueryInterface(Ci.nsIHttpChannel); chan.requestMethod = "GET"; return chan; } function serverHandler(metadata, response) { if (dbg) { print("============== serverHandler: in"); } let etag; try { etag = metadata.getHeader("If-None-Match"); } catch (ex) { etag = ""; } if (etag == "testtag") { if (dbg) { print("============== 304 answerr: in"); } response.setStatusLine("1.1", 304, "Not Modified"); } else { response.setHeader("Content-Type", "text/plain", false); response.setStatusLine("1.1", 200, "OK"); // Set a empty header. A empty link header will not appear in header list, // but in the "original headers", it will be still exactly as received. response.setHeaderNoCheck("Link", "", true); response.setHeaderNoCheck("Link", "value1"); response.setHeaderNoCheck("Link", "value2"); response.setHeaderNoCheck("Location", "loc"); response.setHeader("Cache-Control", "max-age=10000", false); response.setHeader("ETag", "testtag", false); response.bodyOutputStream.write(httpbody, httpbody.length); } if (dbg) { print("============== serverHandler: out"); } } function checkResponse(request) { if (dbg) { print("============== checkResponse: in"); } request.QueryInterface(Ci.nsIHttpChannel); Assert.equal(request.responseStatus, 200); Assert.equal(request.responseStatusText, "OK"); Assert.ok(request.requestSucceeded); // Response header have only one link header. var linkHeaderFound = 0; var locationHeaderFound = 0; request.visitResponseHeaders({ visitHeader: function visit(aName, aValue) { if (aName == "link") { linkHeaderFound++; Assert.equal(aValue, "value1, value2"); } if (aName == "location") { locationHeaderFound++; Assert.equal(aValue, "loc"); } }, }); Assert.equal(linkHeaderFound, 1); Assert.equal(locationHeaderFound, 1); // The "original header" still contains 3 link headers. var linkOrgHeaderFound = 0; var locationOrgHeaderFound = 0; request.visitOriginalResponseHeaders({ visitHeader: function visitOrg(aName, aValue) { if (aName == "link") { if (linkOrgHeaderFound == 0) { Assert.equal(aValue, ""); } else if (linkOrgHeaderFound == 1) { Assert.equal(aValue, "value1"); } else { Assert.equal(aValue, "value2"); } linkOrgHeaderFound++; } if (aName == "location") { locationOrgHeaderFound++; Assert.equal(aValue, "loc"); } }, }); Assert.equal(linkOrgHeaderFound, 3); Assert.equal(locationOrgHeaderFound, 1); if (dbg) { print("============== Remove headers"); } // Remove header. request.setResponseHeader("Link", "", false); request.setResponseHeader("Location", "", false); var linkHeaderFound2 = false; var locationHeaderFound2 = 0; request.visitResponseHeaders({ visitHeader: function visit(aName) { if (aName == "Link") { linkHeaderFound2 = true; } if (aName == "Location") { locationHeaderFound2 = true; } }, }); Assert.ok(!linkHeaderFound2, "There should be no link header"); Assert.ok(!locationHeaderFound2, "There should be no location headers."); // The "original header" still contains the empty header. var linkOrgHeaderFound2 = 0; var locationOrgHeaderFound2 = 0; request.visitOriginalResponseHeaders({ visitHeader: function visitOrg(aName, aValue) { if (aName == "link") { if (linkOrgHeaderFound2 == 0) { Assert.equal(aValue, ""); } else if (linkOrgHeaderFound2 == 1) { Assert.equal(aValue, "value1"); } else { Assert.equal(aValue, "value2"); } linkOrgHeaderFound2++; } if (aName == "location") { locationOrgHeaderFound2++; Assert.equal(aValue, "loc"); } }, }); Assert.ok(linkOrgHeaderFound2 == 3, "Original link header still here."); Assert.ok( locationOrgHeaderFound2 == 1, "Original location header still here." ); if (dbg) { print("============== Test GetResponseHeader"); } var linkOrgHeaderFound3 = 0; request.getOriginalResponseHeader("link", { visitHeader: function visitOrg(aName, aValue) { if (linkOrgHeaderFound3 == 0) { Assert.equal(aValue, ""); } else if (linkOrgHeaderFound3 == 1) { Assert.equal(aValue, "value1"); } else { Assert.equal(aValue, "value2"); } linkOrgHeaderFound3++; }, }); Assert.ok(linkOrgHeaderFound2 == 3, "Original link header still here."); if (dbg) { print("============== checkResponse: out"); } run_next_test(); }