File: common.js

package info (click to toggle)
firefox 144.0-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 4,637,504 kB
  • sloc: cpp: 7,576,692; javascript: 6,430,831; ansic: 3,748,119; python: 1,398,978; xml: 628,810; asm: 438,679; java: 186,194; sh: 63,212; makefile: 19,159; objc: 13,086; perl: 12,986; yacc: 4,583; cs: 3,846; pascal: 3,448; lex: 1,720; ruby: 1,003; exp: 762; php: 436; lisp: 258; awk: 247; sql: 66; sed: 53; csh: 10
file content (212 lines) | stat: -rw-r--r-- 7,857 bytes parent folder | download | duplicates (12)
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
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212

const executor_path = '/common/dispatcher/executor.html?pipe=';
const remote_executor_path = '/common/dispatcher/remote-executor.html?pipe=';
const executor_worker_path = '/common/dispatcher/executor-worker.js?pipe=';
const remote_executor_worker_path = '/common/dispatcher/remote-executor-worker.js?pipe=';
const executor_service_worker_path = '/common/dispatcher/executor-service-worker.js?pipe=';

// COEP
const coep_none =
    '|header(Cross-Origin-Embedder-Policy,none)';
const coep_credentialless =
    '|header(Cross-Origin-Embedder-Policy,credentialless)';

// DIP
const dip_none =
    '|header(Document-Isolation-Policy,none)';
const dip_credentialless =
    '|header(Document-Isolation-Policy,isolate-and-credentialless)';
const dip_require_corp =
    '|header(Document-Isolation-Policy,isolate-and-require-corp)';

// DIP-Report-Only
const dip_report_only_credentialless =
    '|header(Document-Isolation-Policy-Report-Only,isolate-and-credentialless)';

// CORP
const corp_cross_origin =
    '|header(Cross-Origin-Resource-Policy,cross-origin)';

const cookie_same_site_none = ';SameSite=None;Secure';

// Test using the modern async/await primitives are easier to read/write.
// However they run sequentially, contrary to async_test. This is the parallel
// version, to avoid timing out.
let promise_test_parallel = (promise, description) => {
  async_test(test => {
    promise(test)
      .then(() => test.done())
      .catch(test.step_func(error => { throw error; }));
  }, description);
};

// Add a cookie |cookie_key|=|cookie_value| on an |origin|.
// Note: cookies visibility depends on the path of the document. Those are set
// from a document from: /html/cross-origin-embedder-policy/credentialless/. So
// the cookie is visible to every path underneath.
const setCookie = async (origin, cookie_key, cookie_value) => {
  const popup_token = token();
  const popup_url = origin + executor_path + `&uuid=${popup_token}`;
  const popup = window.open(popup_url);

  const reply_token = token();
  send(popup_token, `
    document.cookie = "${cookie_key}=${cookie_value}";
    send("${reply_token}", "done");
  `);
  assert_equals(await receive(reply_token), "done");
  popup.close();
}

let parseCookies = function(headers_json) {
  if (!headers_json["cookie"])
    return {};

  return headers_json["cookie"]
    .split(';')
    .map(v => v.split('='))
    .reduce((acc, v) => {
      acc[v[0].trim()] = v[1].trim();
      return acc;
    }, {});
}

// Open a new window with a given |origin|, loaded with DIP:credentialless. The
// new document will execute any scripts sent toward the token it returns.
const newCredentiallessWindow = (origin) => {
  const main_document_token = token();
  const url = origin + executor_path + dip_credentialless +
    `&uuid=${main_document_token}`;
  const context = window.open(url);
  add_completion_callback(() => w.close());
  return main_document_token;
};

// Create a new iframe, loaded with DIP:credentialless.
// The new document will execute any scripts sent toward the token it returns.
const newCredentiallessIframe = (parent_token, child_origin) => {
  const sub_document_token = token();
  const iframe_url = child_origin + executor_path + dip_credentialless +
    `&uuid=${sub_document_token}`;
  send(parent_token, `
    let iframe = document.createElement("iframe");
    iframe.src = "${iframe_url}";
    document.body.appendChild(iframe);
  `)
  return sub_document_token;
};

// The following functions create remote execution contexts with the matching
// origins and headers. The first return value is the uuid that can be used
// to instantiate a RemoteContext object. The second return value is the URL of
// the context that was created.
async function createIframeContext(t, origin, header) {
  const uuid = token();
  const frame_url = origin + remote_executor_path + header + '&uuid=' + uuid;
  const frame = await with_iframe(frame_url);
  t.add_cleanup(() => frame.remove());
  return [uuid, frame_url];
}

async function createDedicatedWorkerContext(t, origin, header) {
  const iframe_uuid = token();
  const frame_url = origin + remote_executor_path + header + '&uuid=' + iframe_uuid;
  const frame = await with_iframe(frame_url);
  t.add_cleanup(() => frame.remove());

  const uuid = token();
  const worker_url = origin + remote_executor_worker_path + '&uuid=' + uuid;
  const ctx = new RemoteContext(iframe_uuid);
  await ctx.execute_script(
    (url) => {
      const worker = new Worker(url);
    }, [worker_url]);
  return [uuid, worker_url];
}

async function createSharedWorkerContext(t, origin, header) {
  const uuid = token();
  const worker_url = origin + remote_executor_worker_path + header + '&uuid=' + uuid;
  const worker = new SharedWorker(worker_url);
  worker.addEventListener('error', t.unreached_func('Worker.onerror'));
  return [uuid, worker_url];
}

async function createIframeWithSWContext(t, origin, header) {
  // Register a service worker with no headers.
  const uuid = token();
  const frame_url = origin + remote_executor_path + header + '&uuid=' + uuid;
  const service_worker_url = origin + executor_service_worker_path;
  const reg = await service_worker_unregister_and_register(
    t, service_worker_url, frame_url);
  const worker = reg.installing || reg.waiting || reg.active;
  worker.addEventListener('error', t.unreached_func('Worker.onerror'));

  const frame = await with_iframe(frame_url);
  t.add_cleanup(() => {
    reg.unregister();
    frame.remove();
  });
  return [uuid, frame_url];
}

// A common interface for building the 4 type of execution contexts. Outputs the
// token needed to create the RemoteContext.
async function getTokenFromEnvironment(t,  environment, headers) {
  switch(environment) {
    case "document":
      const iframe_context = await createIframeContext(t, window.origin, headers);
      return iframe_context[0];
    case "dedicated_worker":
      const dedicated_worker_context = await createDedicatedWorkerContext(t, window.origin, headers);
      return dedicated_worker_context[0];
    case "shared_worker":
      const shared_worker_context = await createSharedWorkerContext(t, window.origin, headers);
      return shared_worker_context[0];
    case "service_worker":
      const sw_context = await createIframeWithSWContext(t, window.origin, headers);
      return sw_context[0];
  }
}

// A common interface for building the 4 type of execution contexts:
// It outputs: [
//   - The token to communicate with the environment.
//   - A promise resolved when the environment encounters an error.
// ]
const environments = {
  document: headers => {
    const tok = token();
    const url = window.origin + executor_path + headers + `&uuid=${tok}`;
    const context = window.open(url);
    add_completion_callback(() => context.close());
    return [tok, new Promise(resolve => {})];
  },

  dedicated_worker: headers => {
    const tok = token();
    const url = window.origin + executor_worker_path + headers + `&uuid=${tok}`;
    const context = new Worker(url);
    return [tok, new Promise(resolve => context.onerror = resolve)];
  },

  shared_worker: headers => {
    const tok = token();
    const url = window.origin + executor_worker_path + headers + `&uuid=${tok}`;
    const context = new SharedWorker(url);
    return [tok, new Promise(resolve => context.onerror = resolve)];
  },

  service_worker: headers => {
    const tok = token();
    const url = window.origin + executor_worker_path + headers + `&uuid=${tok}`;
    const scope = url; // Generate a one-time scope for service worker.
    const error = new Promise(resolve => {
      navigator.serviceWorker.register(url, {scope: scope})
        .then(registration => {
          add_completion_callback(() => registration.unregister());
        }, /* catch */ resolve);
    });
    return [tok, error];
  },
};