<!DOCTYPE html>
<title>ServiceWorker FetchEvent issued from workers in an iframe sandboxed via CSP HTTP response header.</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="resources/test-helpers.sub.js"></script>
<body>
<script>
let lastCallbackId = 0;
let callbacks = {};
function doTest(frame, type) {
  return new Promise(function(resolve) {
    var id = ++lastCallbackId;
    callbacks[id] = resolve;
    frame.contentWindow.postMessage({id: id, type: type}, '*');
  });
}

// Asks the service worker for data about requests and clients seen. The
// worker posts a message back with |data| where:
// |data.requests|: the requests the worker received FetchEvents for
// |data.clients|: the URLs of all the worker's clients
// The worker clears its data after responding.
function getResultsFromWorker(worker) {
  return new Promise(resolve => {
    let channel = new MessageChannel();
    channel.port1.onmessage = msg => {
      resolve(msg.data);
    };
    worker.postMessage({port: channel.port2}, [channel.port2]);
  });
}

window.onmessage = function (e) {
  message = e.data;
  let id = message['id'];
  let callback = callbacks[id];
  delete callbacks[id];
  callback(message['result']);
};

const SCOPE = 'resources/sandboxed-iframe-fetch-event-iframe.py';
const SCRIPT = 'resources/sandboxed-iframe-fetch-event-worker.js';
const expected_base_url = new URL(SCOPE, location.href);
// A service worker controlling |SCOPE|.
let worker;
// An iframe whose response header has
// 'Content-Security-Policy: allow-scripts'.
// This should NOT be controlled by a service worker.
let sandboxed_frame_by_header;
// An iframe whose response header has
// 'Content-Security-Policy: allow-scripts allow-same-origin'.
// This should be controlled by a service worker.
let sandboxed_same_origin_frame_by_header;

promise_test(t => {
  return service_worker_unregister_and_register(t, SCRIPT, SCOPE)
    .then(function(registration) {
      add_completion_callback(() => registration.unregister());
      worker = registration.installing;
      return wait_for_state(t, registration.installing, 'activated');
    });
}, 'Prepare a service worker.');

promise_test(t => {
  const iframe_full_url = expected_base_url + '?sandbox=allow-scripts&' +
                          'sandboxed-frame-by-header';
  return with_iframe(iframe_full_url)
    .then(f => {
      sandboxed_frame_by_header = f;
      add_completion_callback(() => f.remove());
      return getResultsFromWorker(worker);
    })
    .then(data => {
      let requests = data.requests;
      assert_equals(requests.length, 1,
                    'Service worker should provide the response');
      assert_equals(requests[0], iframe_full_url);
      assert_false(data.clients.includes(iframe_full_url),
                   'Service worker should NOT control the sandboxed page');
    });
}, 'Prepare an iframe sandboxed by CSP HTTP header with allow-scripts.');

promise_test(t => {
  const iframe_full_url =
    expected_base_url + '?sandbox=allow-scripts%20allow-same-origin&' +
    'sandboxed-iframe-same-origin-by-header';
  return with_iframe(iframe_full_url)
    .then(f => {
      sandboxed_same_origin_frame_by_header = f;
      add_completion_callback(() => f.remove());
      return getResultsFromWorker(worker);
    })
    .then(data => {
      let requests = data.requests;
      assert_equals(requests.length, 1);
      assert_equals(requests[0], iframe_full_url);
      assert_true(data.clients.includes(iframe_full_url));
    })
}, 'Prepare an iframe sandboxed by CSP HTTP header with allow-scripts and ' +
   'allow-same-origin.');

promise_test(t => {
  let frame = sandboxed_frame_by_header;
  return doTest(frame, 'fetch-from-worker')
    .then(result => {
      assert_equals(result, 'done');
      return getResultsFromWorker(worker);
    })
    .then(data => {
      assert_equals(data.requests.length, 0,
                    'The request should NOT be handled by SW.');
    });
}, 'Fetch request from a worker in iframe sandboxed by CSP HTTP header ' +
   'allow-scripts flag');

promise_test(t => {
  let frame = sandboxed_same_origin_frame_by_header;
  return doTest(frame, 'fetch-from-worker')
    .then(result => {
      assert_equals(result, 'done');
      return getResultsFromWorker(worker);
    })
    .then(data => {
      let requests = data.requests;
      assert_equals(requests.length, 1,
                    'The request should be handled by SW.');
      assert_equals(requests[0], frame.src + '&test=fetch-from-worker');
    });
}, 'Fetch request from a worker in iframe sandboxed by CSP HTTP header ' +
   'with allow-scripts and allow-same-origin flag');
</script>
</body>
