<!doctype html>
<title>Cache Storage: verify scripts loaded from cache_storage are marked opaque</title>
<link rel="help" href="https://w3c.github.io/ServiceWorker/#cache-interface">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="resources/testharness-helpers.js"></script>
<script src="resources/test-helpers.sub.js"></script>
<script src="/common/get-host-info.sub.js"></script>
<script>
'use strict';

const SW_URL = 'resources/opaque-script-sw.js';
const BASE_SCOPE = './resources/opaque-script-frame.html';
const SAME_ORIGIN_BASE = new URL('./resources/', self.location.href).href;
const CROSS_ORIGIN_BASE = new URL('./resources/',
    get_host_info().HTTPS_REMOTE_ORIGIN + base_path()).href;

function wait_for_error() {
  return new Promise(resolve => {
    self.addEventListener('message', function messageHandler(evt) {
      if (evt.data.type !== 'ErrorEvent')
        return;
      self.removeEventListener('message', messageHandler);
      resolve(evt.data.msg);
    });
  });
}

// Load an iframe that dynamically adds a script tag that is
// same/cross origin and large/small.  It then calls a function
// defined in that loaded script that throws an unhandled error.
// The resulting message exposed in the global onerror handler
// is reported back from this function.  Opaque cross origin
// scripts should not expose the details of the uncaught exception.
async function get_error_message(t, mode, size) {
  const script_base = mode === 'same-origin' ? SAME_ORIGIN_BASE
                                             : CROSS_ORIGIN_BASE;
  const script = script_base + `opaque-script-${size}.js`;
  const scope = BASE_SCOPE + `?script=${script}`;
  const reg = await service_worker_unregister_and_register(t, SW_URL, scope);
  t.add_cleanup(_ => reg.unregister());
  assert_true(!!reg.installing);
  await wait_for_state(t, reg.installing, 'activated');
  const error_promise = wait_for_error();
  const f = await with_iframe(scope);
  t.add_cleanup(_ => f.remove());
  const error = await error_promise;
  return error;
}

promise_test(async t => {
  const error = await get_error_message(t, 'same-origin', 'small');
  assert_true(error.includes('Intentional error'));
}, 'Verify small same-origin cache_storage scripts are not opaque.');

promise_test(async t => {
  const error = await get_error_message(t, 'same-origin', 'large');
  assert_true(error.includes('Intentional error'));
}, 'Verify large same-origin cache_storage scripts are not opaque.');

promise_test(async t => {
  const error = await get_error_message(t, 'cross-origin', 'small');
  assert_false(error.includes('Intentional error'));
}, 'Verify small cross-origin cache_storage scripts are opaque.');

promise_test(async t => {
  const error = await get_error_message(t, 'cross-origin', 'large');
  assert_false(error.includes('Intentional error'));
}, 'Verify large cross-origin cache_storage scripts are opaque.');

</script>
