summaryrefslogtreecommitdiffstats
path: root/netwerk/test/unit/test_verify_traffic.js
blob: 2b806332c9242ca8a0b893bd3bd07e1f65102f1d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

/* import-globals-from head_cache.js */
/* import-globals-from head_cookies.js */
/* import-globals-from head_channels.js */
/* import-globals-from head_servers.js */

const gDashboard = Cc["@mozilla.org/network/dashboard;1"].getService(
  Ci.nsIDashboard
);

const { TestUtils } = ChromeUtils.importESModule(
  "resource://testing-common/TestUtils.sys.mjs"
);

function makeChan(uri) {
  let chan = NetUtil.newChannel({
    uri,
    loadUsingSystemPrincipal: true,
  }).QueryInterface(Ci.nsIHttpChannel);
  chan.loadFlags = Ci.nsIChannel.LOAD_INITIAL_DOCUMENT_URI;
  return chan;
}

function channelOpenPromise(chan, flags) {
  return new Promise(resolve => {
    function finish(req, buffer) {
      resolve([req, buffer]);
    }
    chan.asyncOpen(new ChannelListener(finish, null, flags));
  });
}

async function registerSimplePathHandler(server, path) {
  return server.registerPathHandler(path, (req, resp) => {
    resp.writeHead(200);
    resp.end("done");
  });
}

add_task(async function test_verify_traffic_for_http2() {
  Services.prefs.setBoolPref(
    "network.http.http2.move_to_pending_list_after_network_change",
    true
  );

  // Bug 1878505: It seems when HTTPS RR is enabled, a speculative
  // connection that waits to receive a HTTPS response will receive it
  // after the actual connection is established, leading to an extra
  // connection being established.
  Services.prefs.setIntPref("network.http.speculative-parallel-limit", 0);

  let certdb = Cc["@mozilla.org/security/x509certdb;1"].getService(
    Ci.nsIX509CertDB
  );
  addCertFromFile(certdb, "http2-ca.pem", "CTu,u,u");

  let server = new NodeHTTP2Server();
  await server.start();
  registerCleanupFunction(async () => {
    Services.prefs.clearUserPref(
      "network.http.http2.move_to_pending_list_after_network_change"
    );
    await server.stop();
  });

  try {
    await server.registerPathHandler("/longDelay", (req, resp) => {
      // eslint-disable-next-line mozilla/no-arbitrary-setTimeout, no-undef
      setTimeout(function () {
        resp.writeHead(200);
        resp.end("done");
      }, 8000);
    });
  } catch (e) {}

  await registerSimplePathHandler(server, "/test");

  // Send some requests and check if we have only one h2 session.
  for (let i = 0; i < 2; i++) {
    let chan = makeChan(`https://localhost:${server.port()}/test`);
    await channelOpenPromise(chan, CL_ALLOW_UNKNOWN_CL);
  }
  let sessionCount = await server.sessionCount();
  Assert.equal(sessionCount, 1);

  let res = await new Promise(resolve => {
    // Create a request that takes 8s to finish.
    let chan = makeChan(`https://localhost:${server.port()}/longDelay`);
    chan.asyncOpen(new ChannelListener(resolve, null, CL_ALLOW_UNKNOWN_CL));

    // Send a network change event to trigger VerifyTraffic(). After this,
    // the connnection will be put in the pending list.
    // We'll crate a new connection for the new request.
    Services.obs.notifyObservers(
      null,
      "network:link-status-changed",
      "changed"
    );

    // This request will use the new connection.
    let chan1 = makeChan(`https://localhost:${server.port()}/test`);
    chan1.asyncOpen(new ChannelListener(() => {}, null, CL_ALLOW_UNKNOWN_CL));
  });

  // The connection in the pending list should be still working.
  Assert.equal(res.status, Cr.NS_OK);
  Assert.equal(res.QueryInterface(Ci.nsIHttpChannel).responseStatus, 200);

  sessionCount = await server.sessionCount();
  Assert.equal(sessionCount, 2);

  // Create another request and trigger the network change event again.
  // The second network change event is to put the second connection into the
  // pending list.
  res = await new Promise(resolve => {
    // Create a request that takes 8s to finish.
    let chan = makeChan(`https://localhost:${server.port()}/longDelay`);
    chan.asyncOpen(new ChannelListener(resolve, null, CL_ALLOW_UNKNOWN_CL));

    Services.obs.notifyObservers(
      null,
      "network:link-status-changed",
      "changed"
    );
  });

  Assert.equal(res.status, Cr.NS_OK);
  Assert.equal(res.QueryInterface(Ci.nsIHttpChannel).responseStatus, 200);

  async function getSocketCount() {
    return new Promise(resolve => {
      gDashboard.requestSockets(function (data) {
        resolve(data.sockets.length);
      });
    });
  }

  await TestUtils.waitForCondition(async () => {
    const socketCount = await getSocketCount();
    return socketCount === 0;
  }, "Socket count should be 0");

  await server.stop();
});