| <!DOCTYPE html> |
| <title>Test storage partitioning in fenced frames</title> |
| <meta name="timeout" content="long"> |
| <script src="/resources/testharness.js"></script> |
| <script src="/resources/testharnessreport.js"></script> |
| <script src="/common/utils.js"></script> |
| <script src="/common/dispatcher/dispatcher.js"></script> |
| <script src="resources/utils.js"></script> |
| |
| <body> |
| <script> |
| |
| // `getter(key)` : reads the value of `key`, null if not set |
| // `setter(key, value)`: sets `key` to `value` |
| async function runTest(getter, setter) { |
| const key = "key"; |
| const outer_value = "outer"; |
| const inner_value = "inner"; |
| |
| // Set the value in the top-level frame, and check that it worked. |
| await setter(key, outer_value); |
| assert_equals(await getter(key), outer_value, |
| "Stored the value in the top-level frame."); |
| |
| // Attach a fenced frame. |
| const frame = attachFencedFrameContext(); |
| |
| // Check that the outer value isn't visible. |
| const inner_before_set = await frame.execute(getter, [key]); |
| assert_equals(inner_before_set, null, |
| "The outer value isn't visible inside the fenced frame."); |
| |
| // Set the value inside the fenced frame, and check that it worked. |
| await frame.execute(setter, [key, inner_value]); |
| const inner_after_set = await frame.execute(getter, [key]); |
| assert_equals(inner_after_set, inner_value, |
| "Stored the value in the fenced frame."); |
| |
| // Check that the inner value isn't visible in the top-level frame. |
| assert_equals(await getter(key), outer_value, |
| "The inner value isn't visible outside the fenced frame."); |
| |
| // Perform an embedder-initiated navigation that will fail. |
| const original_config = frame.config; |
| frame.config = new FencedFrameConfig("resources/response-204.py"); |
| await step_timeout(() => {}, 1000); |
| |
| // Check that the failed navigation didn't change the storage partition. |
| // (The partition nonce should be reinitialized on navigation commit.) |
| const inner_after_failure = await frame.execute(getter, [key]); |
| assert_equals(inner_after_failure, inner_value, |
| "The inner value is still present after the failed navigation."); |
| |
| // Refresh the fenced frame from within. |
| await frame.execute(() => { |
| window.executor.suspend(() => { location.href = location.href; }); |
| }); |
| |
| // Check that the storage partition is the same. |
| const inner_after_inner_refresh = await frame.execute(getter, [key]); |
| assert_equals(inner_after_inner_refresh, inner_value, |
| "The inner value is the same after a fencedframe-initiated refresh."); |
| |
| // Refresh the fenced frame from the embedder. |
| await frame.execute(() => window.executor.suspend(() => {})); |
| frame.element.config = original_config; |
| |
| // Check that there is a blank slate. |
| const inner_after_embedder_refresh = await frame.execute(getter, [key]); |
| assert_equals(inner_after_embedder_refresh, null, |
| "The inner value is gone after an embedder-initiated refresh."); |
| } |
| |
| promise_test(async () => { |
| return runTest( |
| (_) => { return document.cookie || null; }, |
| (_, value) => { document.cookie = value;} |
| ); |
| }, 'document.cookie'); |
| |
| promise_test(async () => { |
| return runTest( |
| (key) => { return localStorage.getItem(key); }, |
| (key, value) => { return localStorage.setItem(key, value); } |
| ); |
| }, 'localStorage'); |
| |
| promise_test(async () => { |
| return runTest( |
| (key) => { return sessionStorage.getItem(key); }, |
| (key, value) => { return sessionStorage.setItem(key, value); } |
| ); |
| }, 'sessionStorage'); |
| |
| promise_test(async () => { |
| return runTest( |
| async (key) => { |
| const newCache = await caches.open('test-cache'); |
| const response = await newCache.match(key); |
| if (!response) { |
| return null; |
| } |
| return response.text(); |
| }, |
| async (key, value) => { |
| const newCache = await caches.open('test-cache'); |
| return newCache.put(key, new Response(value)); |
| } |
| ); |
| }, 'Cache API'); |
| |
| promise_test(async () => { |
| return runTest( |
| async (key) => { |
| const root = await navigator.storage.getDirectory(); |
| const draftHandle = await root.getFileHandle(key, { create: true }); |
| const file = await draftHandle.getFile(); |
| const text = await file.text(); |
| return text || null; |
| }, |
| async (key, value) => { |
| const root = await navigator.storage.getDirectory(); |
| const draftHandle = await root.getFileHandle(key, { create: true }); |
| const writable = await draftHandle.createWritable() |
| await writable.truncate(0); |
| await writable.write(value); |
| await writable.close(); |
| } |
| ); |
| }, 'File System Access API'); |
| |
| promise_test(async () => { |
| return runTest( |
| async (key) => { |
| const openRequest = indexedDB.open('test-db', 2); |
| const db = await new Promise((resolve) => { |
| openRequest.onsuccess = (event) => { |
| resolve(event.target.result); |
| }; |
| openRequest.onupgradeneeded = (event) => { |
| const db = event.target.result; |
| const objStore = db.createObjectStore('test-tbl', {keyPath: 'key'}); |
| objStore.transaction.oncomplete = (event) => { |
| resolve(db); |
| }; |
| }; |
| }); |
| const readRequest = db.transaction(['test-tbl']) |
| .objectStore('test-tbl') |
| .get(key); |
| return new Promise((resolve) => { |
| readRequest.onsuccess = (event) => { |
| if (!event.target.result) { |
| resolve(null); |
| } else { |
| resolve(event.target.result['value']); |
| } |
| }; |
| }); |
| }, |
| async (key, value) => { |
| const openRequest = indexedDB.open('test-db', 2); |
| const db = await new Promise((resolve) => { |
| openRequest.onsuccess = (event) => { |
| resolve(event.target.result); |
| }; |
| openRequest.onupgradeneeded = (event) => { |
| const db = event.target.result; |
| const objStore = db.createObjectStore('test-tbl', {keyPath: 'key'}); |
| objStore.transaction.oncomplete = (event) => { |
| resolve(db); |
| }; |
| }; |
| }); |
| const writeRequest = db.transaction(['test-tbl'], 'readwrite') |
| .objectStore('test-tbl') |
| .add({'key': key, 'value': value}); |
| return new Promise((resolve) => { |
| writeRequest.onsuccess = (event) => { |
| resolve(event.target.result); |
| }; |
| }); |
| } |
| ); |
| }, 'IndexedDB'); |
| |
| </script> |
| </body> |