<!DOCTYPE html>
<meta name=timeout content=long>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/common/get-host-info.sub.js"></script>
<script src="/common/utils.js"></script>
<script src="resources/test-helpers.sub.js"></script>
<body>
<script>
const worker = 'resources/fetch-event-test-worker.js';

const method = 'POST';
const duplex = 'half';

function createBody(t) {
  const rs = new ReadableStream({start(c) {
    c.enqueue('i a');
    c.enqueue('m the request');
    step_timeout(t.step_func(() => {
      c.enqueue(' body');
      c.close();
    }, 10));
  }});
  return rs.pipeThrough(new TextEncoderStream());
}

promise_test(async t => {
  const scope = 'resources/';
  const registration =
    await service_worker_unregister_and_register(t, worker, scope);
  await wait_for_state(t, registration.installing, 'activated');

  // This will happen after all other tests
  promise_test(t => {
    return registration.unregister();
  }, 'restore global state');
}, 'global setup');

// Test that the service worker can read FetchEvent#body when it is made from
// a ReadableStream. It responds with request body it read.
promise_test(async t => {
  const body = createBody(t);
  // Set page_url to "?ignore" so the service worker falls back to network
  // for the main resource request, and add a suffix to avoid colliding
  // with other tests.
  const page_url = `resources/simple.html?ignore&id=${token()}`;
  const frame = await with_iframe(page_url);
  t.add_cleanup(() => { frame.remove(); });
  const response = await frame.contentWindow.fetch('simple.html?request-body', {
    method, body, duplex});
  assert_equals(response.status, 200, 'status');
  const text = await response.text();
  assert_equals(text, 'i am the request body', 'body');
}, 'The streaming request body is readable in the service worker.');

// Network fallback
promise_test(async t => {
  const body = createBody(t);
  // Set page_url to "?ignore" so the service worker falls back to network
  // for the main resource request, and add a suffix to avoid colliding
  // with other tests.
  const page_url = `resources/simple.html?ignore&id=${token()}`;
  const frame = await with_iframe(page_url);
  t.add_cleanup(() => { frame.remove(); });
  // Add "?ignore" so that the service worker falls back to
  // echo-content.h2.py.
  const echo_url = '/fetch/api/resources/echo-content.h2.py?ignore';
  const response =
    await frame.contentWindow.fetch(echo_url, { method, body, duplex});
  assert_equals(response.status, 200, 'status');
  const text = await response.text();
  assert_equals(text, 'i am the request body', 'body');
}, 'Network fallback for streaming upload.');

// When the streaming body is used in the service worker, network fallback
// fails.
promise_test(async t => {
  const body = createBody(t);
  // Set page_url to "?ignore" so the service worker falls back to network
  // for the main resource request, and add a suffix to avoid colliding
  // with other tests.
  const page_url = `resources/simple.html?ignore&id=${token()}`;
  const frame = await with_iframe(page_url);
  t.add_cleanup(() => { frame.remove(); });
  const echo_url = '/fetch/api/resources/echo-content.h2.py?use-and-ignore';
  const w = frame.contentWindow;
  await promise_rejects_js(t, w.TypeError, w.fetch(echo_url, {
    method, body, duplex}));
}, 'When the streaming request body is used, network fallback fails.');

// When the streaming body is used by clone() in the service worker, network
// fallback succeeds.
promise_test(async t => {
  const body = createBody(t);
  // Set page_url to "?ignore" so the service worker falls back to network
  // for the main resource request, and add a suffix to avoid colliding
  // with other tests.
  const page_url = `resources/simple.html?ignore&id=${token()}`;
  const frame = await with_iframe(page_url);
  t.add_cleanup(() => { frame.remove(); });
  // Add "?clone-and-ignore" so that the service worker falls back to
  // echo-content.h2.py.
  const echo_url = '/fetch/api/resources/echo-content.h2.py?clone-and-ignore';
  const response = await frame.contentWindow.fetch(echo_url, {
    method, body, duplex});
  assert_equals(response.status, 200, 'status');
  const text = await response.text();
  assert_equals(text, 'i am the request body', 'body');
}, 'Running clone() in the service worker does not prevent network fallback.');

</script>
</body>
