summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/html/cross-origin-opener-policy
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:22:09 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:22:09 +0000
commit43a97878ce14b72f0981164f87f2e35e14151312 (patch)
tree620249daf56c0258faa40cbdcf9cfba06de2a846 /testing/web-platform/tests/html/cross-origin-opener-policy
parentInitial commit. (diff)
downloadfirefox-43a97878ce14b72f0981164f87f2e35e14151312.tar.xz
firefox-43a97878ce14b72f0981164f87f2e35e14151312.zip
Adding upstream version 110.0.1.upstream/110.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'testing/web-platform/tests/html/cross-origin-opener-policy')
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/META.yml9
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/README.md11
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/blob-popup.https.html40
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/blob-popup.https.html.headers1
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/coep-blob-popup.https.html51
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/coep-blob-popup.https.html.headers2
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/coep-navigate-popup.https.html72
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/coep-navigate-popup.https.html.headers2
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/coep-redirect.https.html68
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/coep-redirect.https.html.headers2
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/coep-with-cross-origin.https.html44
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/coep-with-cross-origin.https.html.headers2
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/coep-with-same-origin.https.html44
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/coep-with-same-origin.https.html.headers2
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/coep-with-same-site.https.html44
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/coep-with-same-site.https.html.headers2
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/coop-coep-sandbox.https.html59
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/coop-coep-sandbox.https.html.headers2
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/coop-csp-sandbox-navigate.https.html40
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/coop-csp-sandbox.https.html24
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/coop-navigate-same-origin-csp-sandbox.html63
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/coop-navigated-history-popup.https.html18
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/coop-navigated-popup.https.html37
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/coop-navigated-popup.https.html.headers1
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/coop-popup-opener-navigates.https.html84
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/coop-popup-opener-navigates.https.html.headers1
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/coop-same-origin-allow-popups-document-write.html62
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/coop-sandbox-cuts-opener.https.html66
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/coop-sandbox-redirects-cuts-opener.https.html68
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/coop-sandbox.https.html59
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/coop-sandbox.https.html.headers1
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/header-parsing-failures.https.html90
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/header-parsing-non-ascii.https.html17
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/header-parsing-non-ascii.https.html.headers1
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/header-parsing-repeated.https.html16
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/header-parsing-repeated.https.html.headers2
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/header-parsing-successes.https.html44
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/historical/coep-navigate-popup-unsafe-inherit.https.html40
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/historical/popup-same-origin-unsafe-allow-outgoing-with-cross-origin.https.html58
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/historical/popup-same-origin-unsafe-allow-outgoing-with-cross-origin.https.html.headers1
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/historical/popup-same-origin-unsafe-allow-outgoing-with-same-origin.https.html58
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/historical/popup-same-origin-unsafe-allow-outgoing-with-same-origin.https.html.headers1
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/historical/popup-same-origin-unsafe-allow-outgoing-with-same-site.https.html58
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/historical/popup-same-origin-unsafe-allow-outgoing-with-same-site.https.html.headers1
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/historical/popup-same-site-unsafe-allow-outgoing-with-cross-origin.https.html58
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/historical/popup-same-site-unsafe-allow-outgoing-with-cross-origin.https.html.headers1
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/historical/popup-same-site-unsafe-allow-outgoing-with-same-origin.https.html58
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/historical/popup-same-site-unsafe-allow-outgoing-with-same-origin.https.html.headers1
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/historical/popup-same-site-unsafe-allow-outgoing-with-same-site.https.html58
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/historical/popup-same-site-unsafe-allow-outgoing-with-same-site.https.html.headers1
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/historical/popup-same-site-with-cross-origin.https.html58
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/historical/popup-same-site-with-cross-origin.https.html.headers1
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/historical/popup-same-site-with-same-origin.https.html58
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/historical/popup-same-site-with-same-origin.https.html.headers1
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/historical/popup-same-site-with-same-site.https.html58
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/historical/popup-same-site-with-same-site.https.html.headers1
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/iframe-popup-same-origin-allow-popups-to-same-origin-allow-popups.https.html88
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/iframe-popup-same-origin-allow-popups-to-same-origin-allow-popups.https.html.headers1
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/iframe-popup-same-origin-allow-popups-to-same-origin.https.html86
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/iframe-popup-same-origin-allow-popups-to-same-origin.https.html.headers1
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/iframe-popup-same-origin-allow-popups-to-unsafe-none.https.html85
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/iframe-popup-same-origin-allow-popups-to-unsafe-none.https.html.headers1
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/iframe-popup-same-origin-to-same-origin.https.html88
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/iframe-popup-same-origin-to-same-origin.https.html.headers1
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/iframe-popup-same-origin-to-unsafe-none.https.html87
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/iframe-popup-same-origin-to-unsafe-none.https.html.headers1
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/iframe-popup-unsafe-none-to-same-origin.https.html87
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/iframe-popup-unsafe-none-to-same-origin.https.html.headers1
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/iframe-popup-unsafe-none-to-unsafe-none.https.html85
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/iframe-popup-unsafe-none-to-unsafe-none.https.html.headers1
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/javascript-url.https.html199
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/navigate-to-aboutblank.https.html193
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/navigate-top-to-aboutblank.https.html171
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/no-https.html21
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/no-https.html.headers1
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/popup-coop-by-sw.https.html136
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/popup-meta-http-equiv.https.html24
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/popup-redirect-cache.https.html90
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/popup-redirect-cache.https.html.headers1
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/popup-redirect-same-origin-allow-popups.https.html96
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/popup-same-origin-allow-popups-with-cross-origin.https.html58
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/popup-same-origin-allow-popups-with-cross-origin.https.html.headers1
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/popup-same-origin-allow-popups-with-same-origin.https.html58
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/popup-same-origin-allow-popups-with-same-origin.https.html.headers1
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/popup-same-origin-allow-popups-with-same-site.https.html58
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/popup-same-origin-allow-popups-with-same-site.https.html.headers1
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/popup-same-origin-non-initial-about-blank.https.html17
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/popup-same-origin-non-initial-about-blank.https.html.headers1
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/popup-same-origin-with-cross-origin.https.html58
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/popup-same-origin-with-cross-origin.https.html.headers1
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/popup-same-origin-with-same-origin.https.html58
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/popup-same-origin-with-same-origin.https.html.headers1
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/popup-same-origin-with-same-site.https.html58
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/popup-same-origin-with-same-site.https.html.headers1
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/popup-unsafe-none-with-cross-origin.https.html58
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/popup-unsafe-none-with-cross-origin.https.html.headers1
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/popup-unsafe-none-with-same-origin.https.html58
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/popup-unsafe-none-with-same-origin.https.html.headers1
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/popup-unsafe-none-with-same-site.https.html58
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/popup-unsafe-none-with-same-site.https.html.headers1
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/popup-unspecified-with-cross-origin.https.html58
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/popup-unspecified-with-same-origin.https.html58
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/popup-unspecified-with-same-site.https.html58
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/popup-with-structured-header.https.html33
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/popup-with-structured-header.https.html.headers1
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/reporting/META.yml6
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/access-from-coop-page-to-openee_coop-ro.https.html82
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/access-from-coop-page-to-openee_coop-ro_cross-origin.https.html85
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/access-from-coop-page-to-opener_coop-ro.https.html63
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/access-from-coop-page-to-opener_coop-ro_cross-origin.https.html63
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/access-from-coop-page-to-other_coop-ro.https.html92
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/access-from-coop-page-to-other_coop-ro_cross-origin.https.html93
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/access-to-coop-page-from-openee_coop-ro.https.html77
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/access-to-coop-page-from-openee_coop-ro_cross-origin.https.html79
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/access-to-coop-page-from-opener_coop-ro.https.html67
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/access-to-coop-page-from-opener_coop-ro_cross-origin.https.html68
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/access-to-coop-page-from-other_coop-ro.https.html82
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/access-to-coop-page-from-other_coop-ro_cross-origin.https.html83
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/property-blur.https.html13
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/property-close.https.html13
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/property-closed.https.html13
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/property-focus.https.html13
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/property-frames.https.html13
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/property-indexed-getter.https.html66
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/property-indexed-getter.https.html.headers1
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/property-length.https.html13
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/property-location-get.https.html13
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/property-location-set.https.html13
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/property-named-getter.https.html71
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/property-named-getter.https.html.headers1
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/property-opener-get.https.html13
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/property-opener-set.https.html13
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/property-postmessage-1.https.html13
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/property-postmessage-2.https.html13
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/property-self.https.html13
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/property-top.https.html13
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/property-window.https.html13
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/report-to-both_coop-ro.https.html124
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/reporting-observer.html275
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/reporting/document-reporting/report-only-four-reports.https.html86
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/reporting/document-reporting/report-only-four-reports.https.html.sub.headers6
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/reporting/document-reporting/report-to-both_coop-ro.https.html124
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/reporting/document-reporting/reporting-redirect-with-same-origin-allow-popups.https.html111
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/reporting/document-reporting/reporting-redirect-with-unsafe-none.https.html130
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/report-only-four-reports.https.html86
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/report-only-four-reports.https.html.sub.headers6
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/report-only-from-unsafe-none.https.html71
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/report-only-from-unsafe-none.https.html.headers1
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/report-only-same-origin-report-to.https.html96
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/report-only-same-origin-report-to.https.html.sub.headers3
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/report-only-same-origin-with-coep-report-only.https.html32
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/report-only-same-origin-with-coep-report-only.https.html.headers3
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/report-only-same-origin-with-coep.https.html32
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/report-only-same-origin-with-coep.https.html.headers3
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/report-only-same-origin.https.html73
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/report-only-same-origin.https.html.headers2
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-coop-navigated-opener.https.html67
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-coop-navigated-popup.https.html85
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-coop-navigated-popup.https.html.sub.headers2
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-popup-same-origin-allow-popups-report-to.https.html126
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-popup-same-origin-allow-popups-report-to.https.html.sub.headers3
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-popup-same-origin-coep-report-to.https.html173
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-popup-same-origin-coep-report-to.https.html.sub.headers4
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-popup-same-origin-report-to.https.html216
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-popup-same-origin-report-to.https.html.sub.headers3
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-popup-same-origin.https.html110
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-popup-same-origin.https.html.headers1
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-popup-unsafe-none-report-to.https.html126
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-popup-unsafe-none-report-to.https.html.sub.headers2
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-redirect-with-same-origin-allow-popups.https.html111
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/reporting/resources/reporting-common.js405
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/reporting/resources/test-access-property.js57
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/reporting/resources/try-access.js20
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/resource-popup.https.html91
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/resources/call-functionCalledByOpenee.html5
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/resources/common.js86
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/resources/coop-coep.py84
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/resources/coop-same-origin-repeated.asis24
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/resources/csp-sandbox.py29
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/resources/fully-loaded.js10
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/resources/iframe-test.js234
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/resources/popup-test.js99
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/resources/postback.html45
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/resources/postback.html.headers2
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/resources/redirect.py5
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/resources/resource-cleanup.html11
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/resources/resource-popup.html21
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/resources/universal-worker.js2
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/README.md9
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/coop-rp-in-navigation-chain.https.html65
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/coop-rp-in-navigation-chain.https.html.headers1
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/iframe-popup-to-so.https.html90
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/iframe-popup-to-so.https.html.headers1
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/iframe-popup-to-soap.https.html91
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/iframe-popup-to-soap.https.html.headers1
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/iframe-popup-to-un.https.html90
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/iframe-popup-to-un.https.html.headers1
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/iframe-popup.https.html90
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/iframe-popup.https.html.headers1
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/named_targeting.https.html40
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/named_targeting.https.html.headers1
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/popup-so.https.html37
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/popup-so.https.html.headers1
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/popup-soap.https.html37
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/popup-soap.https.html.headers1
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/popup-u.https.html37
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/popup-un.https.html37
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/popup-un.https.html.headers1
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/popup-with-cross-origin.https.html44
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/popup-with-cross-origin.https.html.headers1
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/popup-with-same-origin.https.html44
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/popup-with-same-origin.https.html.headers1
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/popup-with-same-site.https.html44
-rw-r--r--testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/popup-with-same-site.https.html.headers1
214 files changed, 9588 insertions, 0 deletions
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/META.yml b/testing/web-platform/tests/html/cross-origin-opener-policy/META.yml
new file mode 100644
index 0000000000..b9d578d22f
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/META.yml
@@ -0,0 +1,9 @@
+spec: https://html.spec.whatwg.org/multipage/origin.html#cross-origin-opener-policies
+suggested_reviewers:
+ - mikewest
+ - jugglinmike
+ - arturjanc
+ - lweichselbaum
+ - hemeryar
+ - ParisMeuleman
+ - valenting
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/README.md b/testing/web-platform/tests/html/cross-origin-opener-policy/README.md
new file mode 100644
index 0000000000..3f080c82d2
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/README.md
@@ -0,0 +1,11 @@
+This directory as well as `../cross-origin-embedder-policy/` contains tests for `Cross-Origin-Opener-Policy` and `Cross-Origin-Embedder-Policy`. Some light background reading:
+
+* [COOP and COEP explained](https://docs.google.com/document/d/1zDlfvfTJ_9e8Jdc8ehuV4zMEu9ySMCiTGMS9y0GU92k/edit)
+* [COOP processing model](https://gist.github.com/annevk/6f2dd8c79c77123f39797f6bdac43f3e) (also defines interaction with COEP)
+* [COEP processing model](https://mikewest.github.io/corpp/)
+* [Open COOP issues](https://github.com/whatwg/html/labels/topic%3A%20cross-origin-opener-policy)
+* [Open COEP issues](https://github.com/whatwg/html/labels/topic%3A%20cross-origin-embedder-policy)
+
+Notes:
+
+* Top-level navigation to a `data:` URL does not work in Chrome and Firefox and is therefore not tested. (This should probably be standardized.)
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/blob-popup.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/blob-popup.https.html
new file mode 100644
index 0000000000..eda150eb34
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/blob-popup.https.html
@@ -0,0 +1,40 @@
+<!doctype html>
+<title>Cross-Origin-Opener-Policy and a blob URL popup</title>
+<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>
+async_test(t => {
+ window.test = t; // Make the test available globally so the blob URL can use it
+ window.furtherPopup = null;
+
+ const bc = new BroadcastChannel(token());
+ bc.onmessage = t.step_func_done(({ data }) => {
+ assert_equals(data.name.length, 0);
+ assert_false(data.opener);
+ assert_true(furtherPopup.closed);
+ });
+
+ const blobContents = `<script>
+const w = window.open("${get_host_info().HTTPS_REMOTE_ORIGIN}/html/cross-origin-opener-policy/resources/coop-coep.py?coop=x&coep=x&channel=${bc.name}", "${bc.name}");
+window.opener.furtherPopup = w;
+<\/script>`;
+ const blob = new Blob([blobContents], { type: "text/html" });
+ const blobURL = URL.createObjectURL(blob);
+ const popup = window.open(blobURL);
+ t.add_cleanup(() => {
+ // Close the popups once the test is complete.
+ // The browsing context of the second popup is closed hence use the
+ // broadcast channel to trigger the closure.
+ bc.postMessage("close");
+ popup.close();
+ });
+ popup.onload = t.step_func(() => {
+ assert_equals(popup.opener, window);
+ assert_equals(popup.location.href, blobURL);
+ assert_equals(popup.document.URL, blobURL);
+ assert_equals(popup.origin, window.origin);
+ });
+});
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/blob-popup.https.html.headers b/testing/web-platform/tests/html/cross-origin-opener-policy/blob-popup.https.html.headers
new file mode 100644
index 0000000000..46ad58d83b
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/blob-popup.https.html.headers
@@ -0,0 +1 @@
+Cross-Origin-Opener-Policy: same-origin
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/coep-blob-popup.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/coep-blob-popup.https.html
new file mode 100644
index 0000000000..08f70181fc
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/coep-blob-popup.https.html
@@ -0,0 +1,51 @@
+<!doctype html>
+<title>Cross-Origin-Opener-Policy and Cross-Origin-Embedder-Policy: blob URL popup</title>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src=/common/get-host-info.sub.js></script>
+<script src=../cross-origin-embedder-policy/resources/script-factory.js></script>
+<script>
+["window.open()", "<a>", "<a rel=noopener>"].forEach(type => {
+ promise_test(t => {
+ const origins = get_host_info();
+ const id = `tut mir leid ${type}`;
+ const blob = new Blob([`<script>${createScript(origins.ORIGIN, origins.HTTPS_REMOTE_ORIGIN, "channel", id)}<\/script>`], {type: "text/html"});
+ const blobURL = URL.createObjectURL(blob);
+ const bc = new BroadcastChannel(id);
+
+ if (type === "window.open()") {
+ const popup = window.open(blobURL);
+ t.add_cleanup(() => popup.close());
+ popup.onload = t.step_func(() => {
+ assert_equals(popup.opener, window);
+ assert_equals(popup.location.href, blobURL);
+ assert_equals(popup.document.URL, blobURL);
+ assert_equals(popup.origin, window.origin);
+ });
+ } else {
+ const a = document.createElement("a");
+ a.target = type;
+ if (type === "<a rel=noopener>") {
+ a.rel = "noopener";
+ }
+ a.href = blobURL;
+ a.click();
+ }
+
+ return new Promise(resolve => {
+ bc.onmessage = t.step_func(({ data }) => {
+ assert_equals(data.id, id);
+ assert_equals(data.origin, window.origin);
+ assert_true(data.sameOriginNoCORPSuccess, "Same-origin without CORP did not succeed");
+ assert_true(data.crossOriginNoCORPFailure, "Cross-origin without CORP did not fail");
+ if (type === "<a rel=noopener>") {
+ assert_false(data.opener, 'opener');
+ } else {
+ assert_true(data.opener, 'opener');
+ }
+ resolve();
+ });
+ });
+ }, `COOP+COEP blob URL popup: ${type}`);
+});
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/coep-blob-popup.https.html.headers b/testing/web-platform/tests/html/cross-origin-opener-policy/coep-blob-popup.https.html.headers
new file mode 100644
index 0000000000..63b60e490f
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/coep-blob-popup.https.html.headers
@@ -0,0 +1,2 @@
+Cross-Origin-Opener-Policy: same-origin
+Cross-Origin-Embedder-Policy: require-corp
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/coep-navigate-popup.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/coep-navigate-popup.https.html
new file mode 100644
index 0000000000..714a4b6c42
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/coep-navigate-popup.https.html
@@ -0,0 +1,72 @@
+<!doctype html>
+<title>Cross-Origin-Opener-Policy and Cross-Origin-Embedder-Policy: a navigating popup</title>
+<meta name=timeout content=long>
+<meta name=variant content=?0-1>
+<meta name=variant content=?2-3>
+<meta name=variant content=?4-last>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src="/common/subset-tests.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="resources/common.js"></script>
+<script>
+[
+ {
+ "title": "coop/coep",
+ "coop": "same-origin",
+ "coep": "require-corp",
+ "opener": true
+ },
+ {
+ "title": "no coop/coep",
+ "coop": "",
+ "coep": "require-corp",
+ "opener": false
+ },
+ {
+ "title": "coop/no coep",
+ "coop": "same-origin",
+ "coep": "",
+ "opener": false
+ },
+ {
+ "title": "no coop/no coep",
+ "coop": "",
+ "coep": "",
+ "opener": false
+ },
+ {
+ "title": "coop unsafe-none/coep",
+ "coop": "unsafe-none",
+ "coep": "require-corp",
+ "opener": false
+ },
+ {
+ "title": "coop unsafe-none/no coep",
+ "coop": "unsafe-none",
+ "coep": "",
+ "opener": false
+ }
+].forEach((variant, i) => {
+ // Only run specified variants
+ if (!shouldRunSubTest(i)) {
+ return;
+ }
+
+ ["same-origin", "same-site"].forEach(site => {
+ const title = `Popup navigating to ${site} with ${variant.title}`;
+ const channel = title.replace(/ /g,"-");
+ const navigateHost = site === "same-origin" ? SAME_ORIGIN : SAME_SITE;
+ const navigateURL = `${navigateHost.origin}/html/cross-origin-opener-policy/resources/coop-coep.py?coop=${variant.coop}&coep=${variant.coep}&channel=${channel}`;
+ const opener = site === "same-origin" ? variant.opener : false;
+
+ async_test(t => {
+ // For each test we open a COOP: same-origin/COEP: require-corp document in a popup and then
+ // navigate that to either a same-origin (site=="same-origin") or same-site (site=="same-site")
+ // document whose COOP and COEP are set as per the top-most array. We then verify that this
+ // document has the correct opener for its specific setup.
+ url_test(t, `${SAME_ORIGIN.origin}/html/cross-origin-opener-policy/resources/coop-coep.py?coop=same-origin&coep=require-corp&navigate=${encodeURIComponent(navigateURL)}`, channel, opener);
+ }, title);
+ });
+});
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/coep-navigate-popup.https.html.headers b/testing/web-platform/tests/html/cross-origin-opener-policy/coep-navigate-popup.https.html.headers
new file mode 100644
index 0000000000..63b60e490f
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/coep-navigate-popup.https.html.headers
@@ -0,0 +1,2 @@
+Cross-Origin-Opener-Policy: same-origin
+Cross-Origin-Embedder-Policy: require-corp
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/coep-redirect.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/coep-redirect.https.html
new file mode 100644
index 0000000000..83f8f8a33d
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/coep-redirect.https.html
@@ -0,0 +1,68 @@
+<!doctype html>
+<title>Cross-Origin-Opener-Policy and Cross-Origin-Embedder-Policy: redirects</title>
+<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="resources/common.js"></script>
+<script>
+const coopCOEPPath = new URL("resources/coop-coep.py", window.location).pathname;
+
+[
+ {
+ "title": "coop/coep to coop/coep",
+ "redirectCOOP": "same-origin",
+ "redirectCOEP": "require-corp",
+ "coop": "same-origin",
+ "coep": "require-corp",
+ "opener": true
+ },
+ {
+ "title": "coop/coep to no coop/coep",
+ "redirectCOOP": "same-origin",
+ "redirectCOEP": "require-corp",
+ "coop": "",
+ "coep": "require-corp",
+ "opener": false
+ },
+ {
+ "title": "no coop/no coep to coop/coep",
+ "redirectCOOP": "",
+ "redirectCOEP": "",
+ "coop": "same-origin",
+ "coep": "require-corp",
+ "opener": false
+ },
+ {
+ "title": "coop/no coep to coop/coep",
+ "redirectCOOP": "same-origin",
+ "redirectCOEP": "",
+ "coop": "same-origin",
+ "coep": "require-corp",
+ "opener": false
+ },
+ {
+ "title": "coop unsafe-none/coep to coop/coep",
+ "redirectCOOP": "unsafe-none",
+ "redirectCOEP": "require-corp",
+ "coop": "same-origin",
+ "coep": "require-corp",
+ "opener": false
+ },
+ {
+ "title": "coop unsafe-none/coep to coop unsafe-inherit/coep",
+ "redirectCOOP": "unsafe-none",
+ "redirectCOEP": "require-corp",
+ "coop": "unsafe-none",
+ "coep": "require-corp",
+ "opener": false
+ }
+].forEach(variant => {
+ const title = `Redirect from ${variant.title}`;
+ async_test(t => {
+ const channel = title.replace(/ /g,"-");
+ const redirectLocation = `${SAME_ORIGIN.origin}${coopCOEPPath}?coop=${variant.coop}&coep=${variant.coep}&channel=${channel}`;
+ url_test(t, `${SAME_ORIGIN.origin}${coopCOEPPath}?coop=${variant.redirectCOOP}&coep=${variant.redirectCOEP}&redirect=${encodeURIComponent(redirectLocation)}`, channel, variant.opener);
+ }, title);
+});
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/coep-redirect.https.html.headers b/testing/web-platform/tests/html/cross-origin-opener-policy/coep-redirect.https.html.headers
new file mode 100644
index 0000000000..63b60e490f
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/coep-redirect.https.html.headers
@@ -0,0 +1,2 @@
+Cross-Origin-Opener-Policy: same-origin
+Cross-Origin-Embedder-Policy: require-corp
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/coep-with-cross-origin.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/coep-with-cross-origin.https.html
new file mode 100644
index 0000000000..3f6256bcd2
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/coep-with-cross-origin.https.html
@@ -0,0 +1,44 @@
+<!doctype html>
+<title>Cross-Origin-Opener-Policy and Cross-Origin-Embedder-Policy</title>
+<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/dispatcher/dispatcher.js"></script>
+<script src="/common/utils.js"></script>
+<script src="resources/common.js"></script>
+<script src="resources/popup-test.js"></script>
+<script>
+[
+ {
+ "title": "popup with coop/coep",
+ "coop": "same-origin",
+ "coep": "require-corp",
+ "opener": "severed"
+ },
+ {
+ "title": "popup with coop unsafe-none/coep",
+ "coop": "unsafe-none",
+ "coep": "require-corp",
+ "opener": "severed"
+ },
+ {
+ "title": "popup with coop unsafe-none without coep",
+ "coop": "unsafe-none",
+ "coep": "",
+ "opener": "severed"
+ },
+ {
+ "title": "popup without coep",
+ "coop": "same-origin",
+ "coep": "",
+ "opener": "severed"
+ }
+].forEach(variant => {
+ popup_test(`Cross-origin ${variant.title}`, CROSS_ORIGIN, { coop: variant.coop, coep: variant.coep }, variant.opener);
+});
+
+test(() => {
+ assert_true(window.crossOriginIsolated);
+}, "Bonus: window.crossOriginIsolated");
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/coep-with-cross-origin.https.html.headers b/testing/web-platform/tests/html/cross-origin-opener-policy/coep-with-cross-origin.https.html.headers
new file mode 100644
index 0000000000..63b60e490f
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/coep-with-cross-origin.https.html.headers
@@ -0,0 +1,2 @@
+Cross-Origin-Opener-Policy: same-origin
+Cross-Origin-Embedder-Policy: require-corp
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/coep-with-same-origin.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/coep-with-same-origin.https.html
new file mode 100644
index 0000000000..66e7aaf88e
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/coep-with-same-origin.https.html
@@ -0,0 +1,44 @@
+<!doctype html>
+<title>Cross-Origin-Opener-Policy and Cross-Origin-Embedder-Policy</title>
+<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/dispatcher/dispatcher.js"></script>
+<script src="/common/utils.js"></script>
+<script src="resources/common.js"></script>
+<script src="resources/popup-test.js"></script>
+<script>
+[
+ {
+ "title": "popup with coop/coep",
+ "coop": "same-origin",
+ "coep": "require-corp",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with coop unsafe-none/coep",
+ "coop": "unsafe-none",
+ "coep": "require-corp",
+ "opener": "severed"
+ },
+ {
+ "title": "popup with coop unsafe-none without coep",
+ "coop": "unsafe-none",
+ "coep": "",
+ "opener": "severed"
+ },
+ {
+ "title": "popup without coep",
+ "coop": "same-origin",
+ "coep": "",
+ "opener": "severed"
+ }
+].forEach(variant => {
+ popup_test(`Same-origin ${variant.title}`, SAME_ORIGIN, { coop: variant.coop, coep: variant.coep }, variant.opener);
+});
+
+test(() => {
+ assert_true(window.crossOriginIsolated);
+}, "Bonus: window.crossOriginIsolated");
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/coep-with-same-origin.https.html.headers b/testing/web-platform/tests/html/cross-origin-opener-policy/coep-with-same-origin.https.html.headers
new file mode 100644
index 0000000000..63b60e490f
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/coep-with-same-origin.https.html.headers
@@ -0,0 +1,2 @@
+Cross-Origin-Opener-Policy: same-origin
+Cross-Origin-Embedder-Policy: require-corp
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/coep-with-same-site.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/coep-with-same-site.https.html
new file mode 100644
index 0000000000..abce659790
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/coep-with-same-site.https.html
@@ -0,0 +1,44 @@
+<!doctype html>
+<title>Cross-Origin-Opener-Policy and Cross-Origin-Embedder-Policy</title>
+<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/dispatcher/dispatcher.js"></script>
+<script src="/common/utils.js"></script>
+<script src="resources/common.js"></script>
+<script src="resources/popup-test.js"></script>
+<script>
+[
+ {
+ "title": "popup with coop/coep",
+ "coop": "same-origin",
+ "coep": "require-corp",
+ "opener": "severed"
+ },
+ {
+ "title": "popup with coop unsafe-none/coep",
+ "coop": "unsafe-none",
+ "coep": "require-corp",
+ "opener": "severed"
+ },
+ {
+ "title": "popup with coop unsafe-none without coep",
+ "coop": "unsafe-none",
+ "coep": "",
+ "opener": "severed"
+ },
+ {
+ "title": "popup without coep",
+ "coop": "same-origin",
+ "coep": "",
+ "opener": "severed"
+ }
+].forEach(variant => {
+ popup_test(`Same-site ${variant.title}`, SAME_SITE, { coop: variant.coop, coep: variant.coep }, variant.opener);
+});
+
+test(() => {
+ assert_true(window.crossOriginIsolated);
+}, "Bonus: window.crossOriginIsolated");
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/coep-with-same-site.https.html.headers b/testing/web-platform/tests/html/cross-origin-opener-policy/coep-with-same-site.https.html.headers
new file mode 100644
index 0000000000..63b60e490f
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/coep-with-same-site.https.html.headers
@@ -0,0 +1,2 @@
+Cross-Origin-Opener-Policy: same-origin
+Cross-Origin-Embedder-Policy: require-corp
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/coop-coep-sandbox.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/coop-coep-sandbox.https.html
new file mode 100644
index 0000000000..4b94435119
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/coop-coep-sandbox.https.html
@@ -0,0 +1,59 @@
+<!doctype html>
+<title>Sandboxed Cross-Origin-Opener-Policy popup should result in a network error</title>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src="/common/utils.js"></script> <!-- Use token() to allow running tests in parallel -->
+<div id=log>
+<script>
+[
+ "allow-popups allow-scripts allow-same-origin",
+ "allow-popups allow-scripts",
+].forEach(sandboxValue => {
+ async_test(t => {
+ const frame = document.createElement("iframe");
+ const channel = new BroadcastChannel(token());
+ channel.onmessage = t.unreached_func("A COOP popup was created from a sandboxed frame");
+ t.add_cleanup(() => frame.remove());
+ frame.sandbox = sandboxValue;
+ frame.srcdoc = `<script>
+ const popup = window.open("resources/coop-coep.py?coop=same-origin&coep=&channel=${channel.name}");
+ <\/script>`;
+ document.body.append(frame);
+ addEventListener('load', t.step_func(() => {
+ // This uses a timeout to give some time for incorrect implementations to broadcast. A
+ // theoretical testdriver.js API for browsing contexts could be used to speed this up.
+ t.step_timeout(() => {
+ t.done()
+ }, 1500);
+ }));
+ }, `<iframe sandbox="${sandboxValue}"> ${document.title}`);
+});
+
+// Verify that the popup does not have sandboxing flags set
+async_test(t => {
+ const frame = document.createElement("iframe");
+ const channel = new BroadcastChannel(token());
+ channel.onmessage = t.step_func_done();
+ t.add_cleanup(() => frame.remove());
+ frame.sandbox = "allow-popups allow-scripts allow-popups-to-escape-sandbox";
+ frame.srcdoc = `<script>
+window.open("resources/coop-coep.py?coop=same-origin&coep=require-corp&channel=${channel.name}");
+<\/script>`;
+ document.body.append(frame);
+}, `<iframe sandbox="allow-popups allow-scripts allow-popups-to-escape-sandbox"> ${document.title}`);
+
+async_test(t => {
+ const frame = document.createElement("iframe");
+ const channel = new BroadcastChannel(token());
+ frame.sandbox = "allow-scripts allow-same-origin";
+ frame.name = `iframe-${channel.name}`;
+ frame.src = `resources/coop-coep.py?coop=same-origin&coep=require-corp&channel=${channel.name}`;
+ channel.onmessage = t.step_func( event => {
+ const payload = event.data;
+ assert_equals(payload.name, frame.name, "name");
+ t.done();
+ });
+ t.add_cleanup(() => frame.remove());
+ document.body.append(frame);
+}, `Iframe with sandbox and COOP must load.`);
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/coop-coep-sandbox.https.html.headers b/testing/web-platform/tests/html/cross-origin-opener-policy/coop-coep-sandbox.https.html.headers
new file mode 100644
index 0000000000..4fff9d9fba
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/coop-coep-sandbox.https.html.headers
@@ -0,0 +1,2 @@
+Cross-Origin-Opener-Policy: same-origin
+Cross-Origin-Embedder-Policy: require-corp \ No newline at end of file
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/coop-csp-sandbox-navigate.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/coop-csp-sandbox-navigate.https.html
new file mode 100644
index 0000000000..be2d83214a
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/coop-csp-sandbox-navigate.https.html
@@ -0,0 +1,40 @@
+<!doctype html>
+<title>CSP sandbox popup navigate to Cross-Origin-Opener-Policy document should work</title>
+<meta name="timeout" content="long">
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src="/common/utils.js"></script> <!-- Use token() to allow running tests in parallel -->
+<div id=log>
+<script>
+[
+ "allow-popups allow-scripts allow-same-origin",
+ "allow-popups allow-scripts",
+].forEach(sandboxValue => {
+ async_test(t => {
+ const channel = new BroadcastChannel(token());
+ let popup;
+ channel.onmessage = t.step_func_done(e => {
+ assert_equals(e.data.name, '', 'e.data.name');
+ assert_false(e.data.opener, 'e.data.opener');
+ // `popup` is still the WindowProxy that holds the CSP sandbox document, not the
+ // after-navigation COOP document. The CSP sandbox only applies to the before navigation
+ // document/window.
+ assert_true(popup.closed, 'popup.closed');
+ // Same-origin check (with the CSP sandbox document) should not throw when 'allow-same-origin'
+ if (sandboxValue.includes('allow-same-origin')) {
+ assert_true(!!popup.document, 'same-origin check');
+ } else {
+ assert_throws_dom("SecurityError", () => { popup.document; }, 'same-origin check');
+ }
+ });
+ const navigateTo = `/html/cross-origin-opener-policy/resources/coop-coep.py?coop=same-origin&coep=&channel=${channel.name}`;
+ popup = window.open(`resources/csp-sandbox.py?coop=&coep=&sandbox=${sandboxValue}&channel=&navigate=${encodeURIComponent(navigateTo)}`, sandboxValue.replace(/ /g, '_'));
+ t.add_cleanup(() => { popup.close(); });
+ addEventListener('load', t.step_func(() => {
+ t.step_timeout(() => {
+ assert_unreached('Navigation from CSP sandbox to COOP document failed')
+ }, 10000);
+ }));
+ }, `CSP: sandbox ${sandboxValue}; ${document.title}`);
+});
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/coop-csp-sandbox.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/coop-csp-sandbox.https.html
new file mode 100644
index 0000000000..259d484df2
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/coop-csp-sandbox.https.html
@@ -0,0 +1,24 @@
+<!doctype html>
+<title>CSP sandboxed Cross-Origin-Opener-Policy popup should result in a network error</title>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src="/common/utils.js"></script> <!-- Use token() to allow running tests in parallel -->
+<div id=log>
+<script>
+[
+ "allow-popups allow-scripts allow-same-origin",
+ "allow-popups allow-scripts",
+].forEach(sandboxValue => {
+ async_test(t => {
+ const channel = new BroadcastChannel(token());
+ channel.onmessage = t.unreached_func("A COOP popup was created from a CSP-sandboxed popup");
+ const popup = window.open(`resources/csp-sandbox.py?coop=same-origin&coep=&sandbox=${sandboxValue}&channel=${channel.name}`);
+ t.add_cleanup(() => { popup.close(); });
+ addEventListener('load', t.step_func(() => {
+ t.step_timeout(() => {
+ t.done()
+ }, 1500);
+ }));
+ }, `CSP: sandbox ${sandboxValue}; ${document.title}`);
+});
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/coop-navigate-same-origin-csp-sandbox.html b/testing/web-platform/tests/html/cross-origin-opener-policy/coop-navigate-same-origin-csp-sandbox.html
new file mode 100644
index 0000000000..83113de376
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/coop-navigate-same-origin-csp-sandbox.html
@@ -0,0 +1,63 @@
+<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="/common/dispatcher/dispatcher.js"></script>
+<script src="./resources/common.js"></script>
+<script>
+
+const executor_path = '/common/dispatcher/executor.html?pipe=';
+
+const https_origin = get_host_info().HTTPS_ORIGIN;
+const coop_same_origin =
+ '|header(Cross-Origin-Opener-Policy,same-origin)';
+const csp_sandbox =
+ '|header(Content-Security-Policy, sandbox allow-scripts)';
+
+promise_test(async test => {
+ const driver_token = token();
+
+ // 1. Start from a COOP:same-origin document.
+ const opener_token = token();
+ const opener_url = https_origin + executor_path + coop_same_origin +
+ `&uuid=${opener_token}`;
+ const w = window.open(opener_url);
+ add_completion_callback(() => w.close());
+
+ // 2. It opens a popups, and then navigates the popup toward a same-origin
+ // COOP:same-origin document with CSP:sandbox
+ const openee_token = token();
+ const openee_url = https_origin + executor_path + coop_same_origin +
+ csp_sandbox + `&uuid=${openee_token}`;
+ send(opener_token, `
+ openee = window.open("${openee_url}");
+ `);
+ add_completion_callback(() => send(openee_token, "close()"));
+
+ // Because of CSP:sandbox, the popup is not considered same-origin with
+ // its openee. Check the openee/opener relationship is now closed.
+ send(openee_token, `
+ if (opener)
+ send("${driver_token}", "Error: have opener");
+ else
+ send("${driver_token}", "Success: no opener");
+ `);
+ assert_equals(await receive(driver_token), "Success: no opener");
+
+ // Technically, the opener's "openee" WindowProxy should appear as closed at
+ // this time. The popup loaded a new document, and at least two fetch requests
+ // were made. This is more than enough. However, in theory, there is nothing
+ // to guarantee we can observe "openee.close". Wait a bit to ensure this will
+ // never flake.
+ await new Promise(r => test.step_timeout(r, 1000));
+
+ send(opener_token, `
+ if (openee.closed)
+ send("${driver_token}", "Success: openee closed");
+ else
+ send("${driver_token}", "Error: can still access openee");
+ `);
+ assert_equals(await receive(driver_token), "Success: openee closed");
+});
+
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/coop-navigated-history-popup.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/coop-navigated-history-popup.https.html
new file mode 100644
index 0000000000..a061be992c
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/coop-navigated-history-popup.https.html
@@ -0,0 +1,18 @@
+<!doctype html>
+<title>Cross-Origin-Opener-Policy: a navigating popup that then goes back in history</title>
+<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="resources/common.js"></script>
+<script>
+const title = `Popup navigating to other origin with COOP: same-origin and back in history`;
+const channel = title.replace(/ /g,"-");
+const opener = false;
+const openerDOMAccess = false;
+const navigateURL = `${CROSS_ORIGIN.origin}/html/cross-origin-opener-policy/resources/coop-coep.py?coop=same-origin&coep=&navHistory=-1`;
+
+async_test(t => {
+ url_test(t, `${SAME_ORIGIN.origin}/html/cross-origin-opener-policy/resources/coop-coep.py?coop=&coep=&navigate=${encodeURIComponent(navigateURL)}&avoidBackAndForth=1&channel=${channel}`, channel, opener, openerDOMAccess);
+}, title);
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/coop-navigated-popup.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/coop-navigated-popup.https.html
new file mode 100644
index 0000000000..ef610a488f
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/coop-navigated-popup.https.html
@@ -0,0 +1,37 @@
+<!doctype html>
+<title>Cross-Origin-Opener-Policy: a navigated popup</title>
+<!-- In particular this is different from coep-navigate-popup.https.html as this document initiates
+ the navigation (and uses same-origin-allow-popups and no COEP as without that it cannot be
+ observed). COOP should work identically, but implementations might have used the wrong
+ authority. -->
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src="/common/utils.js"></script> <!-- Use token() to allow running tests in parallel -->
+<script>
+async_test(t => {
+ const noCOOP = "/common/blank.html";
+ const popupName = token();
+ const popup = window.open(noCOOP, popupName);
+ const channel = new BroadcastChannel(token());
+ // Close the popup once the test is complete.
+ // The browsing context is closed after the navigation hence use the broadcast channel
+ // to trigger the closure.
+ t.add_cleanup(() => {
+ channel.postMessage("close");
+ });
+ popup.onload = t.step_func(() => {
+ assert_equals(popup.name, popupName);
+ assert_equals(new URL(popup.document.URL).pathname, noCOOP);
+ channel.onmessage = t.step_func_done(event => {
+ const payload = event.data;
+ // The name should be empty, but we're checking the length rather than a
+ // string comparison to "" to keep the random token out of error messages.
+ assert_equals(payload.name.length, 0);
+ assert_false(payload.opener);
+ assert_true(popup.closed);
+ });
+ const coop = `resources/coop-coep.py?coop=same-origin&coep=&channel=${channel.name}`;
+ popup.location = coop;
+ });
+}, "Open a popup to a document without COOP, then navigate it to a document with");
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/coop-navigated-popup.https.html.headers b/testing/web-platform/tests/html/cross-origin-opener-policy/coop-navigated-popup.https.html.headers
new file mode 100644
index 0000000000..d83ed86fb9
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/coop-navigated-popup.https.html.headers
@@ -0,0 +1 @@
+Cross-Origin-Opener-Policy: same-origin-allow-popups
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/coop-popup-opener-navigates.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/coop-popup-opener-navigates.https.html
new file mode 100644
index 0000000000..a6c63654a9
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/coop-popup-opener-navigates.https.html
@@ -0,0 +1,84 @@
+<!doctype html>
+<title>
+ Cross-Origin-Opener-Policy: opener is lost because the opener navigates.
+</title>
+<!--
+ COOP tests usually assume that the opener is lost because it navigated to a
+ page that triggered a browsing context group swap. It can also happen when
+ the opener navigates instead. This test verifies the behavior.
+-->
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src="/common/dispatcher/dispatcher.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="/common/utils.js"></script>
+<script src="resources/common.js"></script>
+<script>
+
+const executor_path = "/common/dispatcher/executor.html?pipe=";
+const coop_same_origin_header =
+ '|header(Cross-Origin-Opener-Policy,same-origin)';
+const coop_unsafe_none_header =
+ '|header(Cross-Origin-Opener-Policy,unsafe-none)';
+
+function getExecutorPath(uuid, origin, coop_header) {
+ return origin.origin + executor_path + coop_header + `&uuid=${uuid}`;
+}
+
+// Note: Because we can not navigate the main page to verify the behavior,
+// we instead create another layer of popup, and navigate the intermediate
+// one. We can verify the opener behavior from this page, and the openee
+// behavior from the second popup.
+promise_test(async t => {
+ // Set up dispatcher communications.
+ const first_popup_token = token();
+ const post_navigate_first_popup_token = token();
+ const second_popup_token = token();
+ const reply_token = token();
+
+ const first_popup_url = getExecutorPath(
+ first_popup_token,
+ SAME_ORIGIN,
+ coop_same_origin_header);
+
+ const post_navigate_first_popup_url = getExecutorPath(
+ post_navigate_first_popup_token,
+ SAME_ORIGIN,
+ coop_unsafe_none_header);
+
+ const second_popup_url = getExecutorPath(
+ second_popup_token,
+ SAME_ORIGIN,
+ coop_same_origin_header);
+
+ // We open the first popup and then ping it, it will respond after loading.
+ const first_popup = window.open(first_popup_url);
+ send(first_popup_token, `send('${reply_token}', 'Popup loaded');`);
+ assert_equals(await receive(reply_token), "Popup loaded");
+
+ // We open the second popup and the ping it, it will respond after loading.
+ send(first_popup_token,
+ `opener.second_popup_url = window.open('${second_popup_url}');`);
+ send(second_popup_token, `send('${reply_token}', 'Popup loaded');`);
+ assert_equals(await receive(reply_token), "Popup loaded");
+
+ // Both popups are now loaded. We navigate the middle one to a page that
+ // does not have COOP, this should trigger a browsing context group swap.
+ send(first_popup_token, `location.href = '${post_navigate_first_popup_url}'`);
+ send(post_navigate_first_popup_token,
+ `send('${reply_token}', 'Popup navigated');`);
+ assert_equals(await receive(reply_token), "Popup navigated");
+
+ // Give some time for things to settle across processes etc. before
+ // proceeding with verifications.
+ await new Promise((resolve, reject) => { t.step_timeout(resolve, 1500); });
+
+ // The reference held by the main page to the first popup should be closed.
+ assert_equals(first_popup.closed, true);
+
+ // The second popup, opened by the first one should have its opener unset.
+ send(second_popup_token, `send('${reply_token}', opener);`);
+ assert_equals(await receive(reply_token), "");
+
+}, "Verify that having the opener navigate instead of the openee also triggers COOP swaps.");
+ </script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/coop-popup-opener-navigates.https.html.headers b/testing/web-platform/tests/html/cross-origin-opener-policy/coop-popup-opener-navigates.https.html.headers
new file mode 100644
index 0000000000..46ad58d83b
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/coop-popup-opener-navigates.https.html.headers
@@ -0,0 +1 @@
+Cross-Origin-Opener-Policy: same-origin
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/coop-same-origin-allow-popups-document-write.html b/testing/web-platform/tests/html/cross-origin-opener-policy/coop-same-origin-allow-popups-document-write.html
new file mode 100644
index 0000000000..82dd4541b6
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/coop-same-origin-allow-popups-document-write.html
@@ -0,0 +1,62 @@
+<!doctype html>
+<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="/common/dispatcher/dispatcher.js"></script>
+<script>
+
+/*
+ Regression test for: https://crbug.com/1216244
+ From a window using Cross-Origin-Opener-Policy:same-origin-allow-popup, open
+ a new blank window and navigate it cross-origin using document.write and a
+ meta refresh. The openee/opener relationship must hold.
+*/
+
+const executor_path = '/common/dispatcher/executor.html?pipe=';
+const coep_soap =
+ "|header(Cross-Origin-Opener-Policy,same-origin-allow-popups)";
+const same_origin = get_host_info().HTTPS_ORIGIN;
+const cross_origin = get_host_info().HTTPS_REMOTE_ORIGIN;
+
+promise_test(async t => {
+ // This window:
+ const this_window_token = token();
+
+ // The opener, using COEP:same-origin-allow-popups:
+ const opener_token = token();
+ const opener_url = same_origin + executor_path + coep_soap +
+ `&uuid=${opener_token}`;
+ const opener = window.open(opener_url);
+
+ // Open a blank window, then use document.write and a meta refresh to navigate
+ // cross-origin.
+ const openee_token = token();
+ const openee_url = cross_origin + executor_path + `&uuid=${openee_token}`;
+ send(opener_token, `
+ openee = window.open();
+ openee.document.write(\`
+ <meta http-equiv="refresh" content="0; url=${openee_url}">
+ \`);
+ openee.document.close();
+ `);
+
+ // Check the openee is loaded without access to the opener.
+ send(openee_token, `
+ send("${this_window_token}", opener == null)
+ `);
+ assert_equals(await receive(this_window_token), "true", "opener == null");
+
+ // To get the state of the openee reflected into the opener's process, waiting
+ // for the openee' document to load and the various fetch() with the
+ // dispatcher should be largely enough. However these aren't causal guarantee.
+ // So wait a bit to be sure:
+ await new Promise(r => t.step_timeout(r, 1000));
+
+ // Check the opener see the openee as 'closed' after the navigation.
+ send(opener_token, `
+ send("${this_window_token}", openee.closed)
+ `);
+ assert_equals(await receive(this_window_token), "true", "openee.closed");
+});
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/coop-sandbox-cuts-opener.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/coop-sandbox-cuts-opener.https.html
new file mode 100644
index 0000000000..47e6d0d6fe
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/coop-sandbox-cuts-opener.https.html
@@ -0,0 +1,66 @@
+<!doctype html>
+<title>
+ Sandboxed Cross-Origin-Opener-Policy popup should cut the opener if necessary
+</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/dispatcher/dispatcher.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="/common/utils.js"></script>
+<script src="resources/common.js"></script>
+<body>
+<script>
+const executor_path = "/common/dispatcher/executor.html?pipe=";
+const coop_same_origin_header =
+ '|header(Cross-Origin-Opener-Policy,same-origin)';
+const coop_unsafe_none_header =
+ '|header(Cross-Origin-Opener-Policy,unsafe-none)';
+
+function getExecutorPath(uuid, origin, coop_header) {
+ return origin.origin + executor_path + coop_header + `&uuid=${uuid}`;
+}
+
+[
+ "allow-popups allow-scripts allow-same-origin",
+ "allow-popups allow-scripts",
+].forEach(sandboxValue => {
+ async_test(t => {
+ // Set up dispatcher communications.
+ const iframe_token = token();
+ const popup_token = token();
+ const main_frame_token_for_popup = token();
+ const main_frame_token_for_iframe = token();
+
+ // Create a sandboxed iframe.
+ const iframe = document.createElement("iframe");
+ iframe.sandbox = sandboxValue;
+ iframe.src = getExecutorPath(iframe_token, SAME_ORIGIN,
+ coop_unsafe_none_header);
+ document.body.append(iframe);
+ t.add_cleanup(() => iframe.remove());
+
+ // Open a COOP popup from the sandboxed iframe.
+ const popup_url = getExecutorPath(popup_token,
+ SAME_ORIGIN,
+ coop_same_origin_header);
+ send(iframe_token, `window.popup = window.open('${popup_url}')`);
+
+ // This should fail. We ping the popup, if we get an answer it loaded.
+ send(popup_token, `
+ send('${main_frame_token_for_popup}', 'Popup loaded');
+ `);
+ receive(main_frame_token_for_popup)
+ .then(t.unreached_func("A COOP popup was created from a sandboxed frame"));
+
+ // We delay probing the popup.closed property to give it time to settle.
+ t.step_timeout(() => {
+ send(iframe_token,
+ `send('${main_frame_token_for_iframe}', window.popup.closed);`);
+ }, 1500);
+ receive(main_frame_token_for_iframe)
+ .then(t.step_func_done(data => assert_equals(data, "true")));
+
+ }, `<iframe sandbox="${sandboxValue}"> ${document.title}`);
+});
+</script>
+</body>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/coop-sandbox-redirects-cuts-opener.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/coop-sandbox-redirects-cuts-opener.https.html
new file mode 100644
index 0000000000..01f60b425d
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/coop-sandbox-redirects-cuts-opener.https.html
@@ -0,0 +1,68 @@
+<!doctype html>
+<title>
+ Sandboxed Cross-Origin-Opener-Policy popup should cut the opener if necessary
+ including during redirects.
+</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/dispatcher/dispatcher.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="/common/utils.js"></script>
+<script src="resources/common.js"></script>
+<body>
+<script>
+const executor_path = "/common/dispatcher/executor.html?pipe=";
+const coop_same_origin_header =
+ '|header(Cross-Origin-Opener-Policy,same-origin)';
+const coop_unsafe_none_header =
+ '|header(Cross-Origin-Opener-Policy,unsafe-none)';
+
+function getExecutorPath(uuid, origin) {
+ return origin.origin + executor_path + `&uuid=${uuid}`;
+}
+
+[
+ "allow-popups allow-scripts allow-same-origin",
+ "allow-popups allow-scripts",
+].forEach(sandboxValue => {
+ async_test(t => {
+ // Set up dispatcher communications.
+ const iframe_token = token();
+ const popup_token = token();
+ const main_frame_token_for_popup = token();
+ const main_frame_token_for_iframe = token();
+
+ // Create a sandboxed iframe.
+ const iframe = document.createElement("iframe");
+ iframe.sandbox = sandboxValue;
+ iframe.src = getExecutorPath(iframe_token, SAME_ORIGIN);
+ document.body.append(iframe);
+ t.add_cleanup(() => iframe.remove());
+
+ // Open a COOP popup from the sandboxed iframe.
+ // Instead of navigating directly we go through a redirect.
+ const popup_url = getExecutorPath(popup_token, SAME_ORIGIN);
+ const redirect_url = SAME_ORIGIN.origin + "/common/redirect.py?pipe=" +
+ coop_same_origin_header + "&location=" +
+ encodeURIComponent(popup_url);
+ send(iframe_token, `window.popup = window.open('${redirect_url}')`);
+
+ // This should fail. We ping the popup, if we get an answer it loaded.
+ send(popup_token, `
+ send('${main_frame_token_for_popup}', 'Popup loaded');
+ `);
+ receive(main_frame_token_for_popup)
+ .then(t.unreached_func("A COOP popup was created from a sandboxed frame"));
+
+ // We delay probing the popup.closed property to give it time to settle.
+ t.step_timeout(() => {
+ send(iframe_token,
+ `send('${main_frame_token_for_iframe}', window.popup.closed);`);
+ }, 1500);
+ receive(main_frame_token_for_iframe)
+ .then(t.step_func_done(data => assert_equals(data, "true")));
+
+ }, `<iframe sandbox="${sandboxValue}"> ${document.title}`);
+});
+</script>
+</body>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/coop-sandbox.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/coop-sandbox.https.html
new file mode 100644
index 0000000000..6f250c1b09
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/coop-sandbox.https.html
@@ -0,0 +1,59 @@
+<!doctype html>
+<title>Sandboxed Cross-Origin-Opener-Policy popup should result in a network error</title>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src="/common/utils.js"></script> <!-- Use token() to allow running tests in parallel -->
+<div id=log>
+<script>
+[
+ "allow-popups allow-scripts allow-same-origin",
+ "allow-popups allow-scripts",
+].forEach(sandboxValue => {
+ async_test(t => {
+ const frame = document.createElement("iframe");
+ const channel = new BroadcastChannel(token());
+ channel.onmessage = t.unreached_func("A COOP popup was created from a sandboxed frame");
+ t.add_cleanup(() => frame.remove());
+ frame.sandbox = sandboxValue;
+ frame.srcdoc = `<script>
+ const popup = window.open("resources/coop-coep.py?coop=same-origin&coep=&channel=${channel.name}");
+ <\/script>`;
+ document.body.append(frame);
+ addEventListener('load', t.step_func(() => {
+ // This uses a timeout to give some time for incorrect implementations to broadcast. A
+ // theoretical testdriver.js API for browsing contexts could be used to speed this up.
+ t.step_timeout(() => {
+ t.done()
+ }, 1500);
+ }));
+ }, `<iframe sandbox="${sandboxValue}"> ${document.title}`);
+});
+
+// Verify that the popup does not have sandboxing flags set
+async_test(t => {
+ const frame = document.createElement("iframe");
+ const channel = new BroadcastChannel(token());
+ channel.onmessage = t.step_func_done();
+ t.add_cleanup(() => frame.remove());
+ frame.sandbox = "allow-popups allow-scripts allow-popups-to-escape-sandbox";
+ frame.srcdoc = `<script>
+window.open("resources/coop-coep.py?coop=same-origin&coep=&channel=${channel.name}");
+<\/script>`;
+ document.body.append(frame);
+}, `<iframe sandbox="allow-popups allow-scripts allow-popups-to-escape-sandbox"> ${document.title}`);
+
+async_test(t => {
+ const frame = document.createElement("iframe");
+ const channel = new BroadcastChannel(token());
+ frame.sandbox = "allow-scripts allow-same-origin";
+ frame.name = `iframe-${channel.name}`;
+ frame.src = `resources/coop-coep.py?coop=same-origin&coep=&channel=${channel.name}`;
+ channel.onmessage = t.step_func( event => {
+ const payload = event.data;
+ assert_equals(payload.name, frame.name, "name");
+ t.done();
+ });
+ t.add_cleanup(() => frame.remove());
+ document.body.append(frame);
+}, `Iframe with sandbox and COOP must load.`);
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/coop-sandbox.https.html.headers b/testing/web-platform/tests/html/cross-origin-opener-policy/coop-sandbox.https.html.headers
new file mode 100644
index 0000000000..46ad58d83b
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/coop-sandbox.https.html.headers
@@ -0,0 +1 @@
+Cross-Origin-Opener-Policy: same-origin
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/header-parsing-failures.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/header-parsing-failures.https.html
new file mode 100644
index 0000000000..55b126ff37
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/header-parsing-failures.https.html
@@ -0,0 +1,90 @@
+<!doctype html>
+<meta charset=utf-8>
+<meta name=timeout content=long>
+<meta name="variant" content="?1-4">
+<meta name="variant" content="?5-8">
+<meta name="variant" content="?9-12">
+<meta name="variant" content="?12-last">
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src="/common/dispatcher/dispatcher.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="/common/subset-tests.js"></script>
+<script src="/common/utils.js"></script>
+<script src="resources/common.js"></script>
+<script src="resources/popup-test.js"></script>
+<script>
+
+[
+ // None of the following should be recognized as "same-origin" (hence the
+ // preserved opener).
+ {
+ "title": "coop with semi-column",
+ "coop": "same-origin;",
+ },
+ {
+ "title": "coop with vertical tab",
+ "coop": "\u000bsame-origin\u000b",
+ },
+ {
+ "title": "coop with form feed",
+ "coop": "\u000csame-origin\u000c",
+ },
+ {
+ "title": "coop with carriage return",
+ "coop": "\u000dsame-origin\u000d",
+ },
+ {
+ "title": "coop with capital letter",
+ "coop": "Same-origin",
+ },
+ {
+ "title": "coop with bad structured header 1",
+ "coop": "same-origin;\tfoo=bar",
+ },
+ {
+ "title": "coop with bad structured header 2",
+ "coop": "same-origin ;foo=bar",
+ },
+ {
+ "title": "coop with bad structured header 3",
+ "coop": "same-origin; foo=bar;",
+ },
+ {
+ "title": "coop as a structured header 'string' item",
+ "coop": "\"same-origin\"",
+ },
+ {
+ "title": "coop as a structured header 'byte sequence' item",
+ "coop": ":c2FtZS1vcmlnaW4=:",
+ },
+ {
+ "title": "coop as a structured header 'boolean' item",
+ "coop": "?1",
+ },
+ {
+ "title": "coop as a structured header 'integer or decimal' item",
+ "coop": "1",
+ },
+ {
+ "title": "coop as an unrecognized structured header type",
+ "coop": "$same-origin",
+ },
+ {
+ "title": "coop with duplicate value",
+ "coop": "same-origin same-origin",
+ },
+ {
+ // Note: comma must be escaped here to not mess with the WPT pipe function.
+ "title": "coop with duplicate value, separated by a comma",
+ "coop": "same-origin\\,same-origin",
+ },
+ {
+ "title": "coop with preceding asterisk character",
+ "coop": "*same-origin ",
+ }
+].forEach(variant => {
+ subsetTest(popup_test, `Parsing ${variant.title}`, SAME_ORIGIN, { coop: variant.coop }, "preserved");
+});
+
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/header-parsing-non-ascii.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/header-parsing-non-ascii.https.html
new file mode 100644
index 0000000000..b5f20f88f4
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/header-parsing-non-ascii.https.html
@@ -0,0 +1,17 @@
+<!doctype html>
+<meta charset=utf-8>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src="/common/dispatcher/dispatcher.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="/common/utils.js"></script>
+<script src="resources/common.js"></script>
+<script src="resources/popup-test.js"></script>
+<script>
+ popup_test(
+ `Simple document with non-ascii COOP header opening a same-origin popup`,
+ SAME_ORIGIN,
+ "unsafe-none",
+ "preserved");
+</script>
+
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/header-parsing-non-ascii.https.html.headers b/testing/web-platform/tests/html/cross-origin-opener-policy/header-parsing-non-ascii.https.html.headers
new file mode 100644
index 0000000000..54e44a7113
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/header-parsing-non-ascii.https.html.headers
@@ -0,0 +1 @@
+Cross-Origin-Opener-Policy: same%FForigin
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/header-parsing-repeated.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/header-parsing-repeated.https.html
new file mode 100644
index 0000000000..a1430cbf57
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/header-parsing-repeated.https.html
@@ -0,0 +1,16 @@
+<!doctype html>
+<meta charset=utf-8>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src="/common/dispatcher/dispatcher.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="/common/utils.js"></script>
+<script src="resources/common.js"></script>
+<script src="resources/popup-test.js"></script>
+<script>
+ popup_test(
+ `Simple document with duplicated COOP header opening a same-origin popup`,
+ SAME_ORIGIN,
+ "unsafe-none",
+ "preserved");
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/header-parsing-repeated.https.html.headers b/testing/web-platform/tests/html/cross-origin-opener-policy/header-parsing-repeated.https.html.headers
new file mode 100644
index 0000000000..85c58be8a1
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/header-parsing-repeated.https.html.headers
@@ -0,0 +1,2 @@
+Cross-Origin-Opener-Policy: same-origin
+Cross-Origin-Opener-Policy: same-origin
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/header-parsing-successes.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/header-parsing-successes.https.html
new file mode 100644
index 0000000000..8e055669ad
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/header-parsing-successes.https.html
@@ -0,0 +1,44 @@
+<!doctype html>
+<meta charset=utf-8>
+<meta name=timeout content=long>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src="/common/dispatcher/dispatcher.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="/common/utils.js"></script>
+<script src="resources/common.js"></script>
+<script src="resources/popup-test.js"></script>
+<script>
+
+[
+ // All of the following should be recognized as "same-origin" (hence the
+ // severed opener link).
+ {
+ "title": "coop with leading space",
+ "coop": " same-origin",
+ },
+ {
+ "title": "coop with trailing space",
+ "coop": "same-origin ",
+ },
+ {
+ "title": "coop with leading tab",
+ "coop": "\tsame-origin",
+ },
+ {
+ "title": "coop with trailing tab",
+ "coop": "same-origin\t",
+ },
+ {
+ "title": "coop with duplicate value, separated by semi-column",
+ "coop": "same-origin;same-origin",
+ },
+ {
+ "title": "coop with valid structured header",
+ "coop": "same-origin; foo=bar",
+ }
+].forEach(variant => {
+ popup_test(`Parsing ${variant.title}`, SAME_ORIGIN, { coop: variant.coop }, "severed");
+});
+
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/historical/coep-navigate-popup-unsafe-inherit.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/historical/coep-navigate-popup-unsafe-inherit.https.html
new file mode 100644
index 0000000000..8368dc4c81
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/historical/coep-navigate-popup-unsafe-inherit.https.html
@@ -0,0 +1,40 @@
+<!doctype html>
+<title>Historical: Cross-Origin-Opener-Policy and Cross-Origin-Embedder-Policy: a navigating popup</title>
+<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="../resources/common.js"></script>
+<script src="/common/subset-tests.js"></script>
+<script>
+[
+ {
+ "title": "coop unsafe-inherit/coep",
+ "coop": "unsafe-inherit", // historical value, equivalent to "unsafe-none"
+ "coep": "require-corp",
+ "opener": false
+ },
+ {
+ "title": "coop unsafe-inherit/no coep",
+ "coop": "unsafe-inherit", // historical value, equivalent to "unsafe-none"
+ "coep": "",
+ "opener": false
+ }
+].forEach((variant) => {
+ ["same-origin", "same-site"].forEach((site) => {
+ const title = `Popup navigating to ${site} with ${variant.title}`;
+ const channel = title.replace(/ /g,"-");
+ const navigateHost = site === "same-origin" ? SAME_ORIGIN : SAME_SITE;
+ const navigateURL = `${navigateHost.origin}/html/cross-origin-opener-policy/resources/coop-coep.py?coop=${variant.coop}&coep=${variant.coep}&channel=${channel}`;
+ const opener = site === "same-origin" ? variant.opener : false;
+
+ async_test(t => {
+ // For each test we open a COOP: same-origin/COEP: require-corp document in a popup and then
+ // navigate that to either a document with same origin (site=="same-origin") or
+ // not-same-origin (site=="same-site") whose COOP and COEP are set as per the top-most array.
+ // We then verify that this document has the correct opener for its specific setup.
+ url_test(t, `${SAME_ORIGIN.origin}/html/cross-origin-opener-policy/resources/coop-coep.py?coop=same-origin&coep=require-corp&navigate=${encodeURIComponent(navigateURL)}`, channel, opener);
+ }, title);
+ });
+});
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/historical/popup-same-origin-unsafe-allow-outgoing-with-cross-origin.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/historical/popup-same-origin-unsafe-allow-outgoing-with-cross-origin.https.html
new file mode 100644
index 0000000000..21e0875f41
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/historical/popup-same-origin-unsafe-allow-outgoing-with-cross-origin.https.html
@@ -0,0 +1,58 @@
+<!doctype html>
+<meta charset=utf-8>
+<meta name=timeout content=long>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src="/common/dispatcher/dispatcher.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="/common/utils.js"></script>
+<script src="../resources/common.js"></script>
+<script src="../resources/popup-test.js"></script>
+<script>
+
+[
+ {
+ "title": "popup with empty coop",
+ "coop": "",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with coop unsafe-none",
+ "coop": "unsafe-none",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with jibberish coop",
+ "coop": "jibberish",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with obsolete coop",
+ "coop": "same-site",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with obsolete coop 2",
+ "coop": "same-site unsafe-allow-outgoing",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with obsolete coop 3",
+ "coop": "same-origin unsafe-allow-outgoing",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with coop same-origin",
+ "coop": "same-origin",
+ "opener": "severed"
+ },
+ {
+ "title": "popup with coop same-origin-allow-popups",
+ "coop": "same-origin-allow-popups",
+ "opener": "severed"
+ }
+].forEach(variant => {
+ popup_test(`Cross-origin ${variant.title}`, CROSS_ORIGIN, { coop: variant.coop }, variant.opener);
+});
+
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/historical/popup-same-origin-unsafe-allow-outgoing-with-cross-origin.https.html.headers b/testing/web-platform/tests/html/cross-origin-opener-policy/historical/popup-same-origin-unsafe-allow-outgoing-with-cross-origin.https.html.headers
new file mode 100644
index 0000000000..a19f4400ce
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/historical/popup-same-origin-unsafe-allow-outgoing-with-cross-origin.https.html.headers
@@ -0,0 +1 @@
+Cross-Origin-Opener-Policy: same-origin unsafe-allow-outgoing
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/historical/popup-same-origin-unsafe-allow-outgoing-with-same-origin.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/historical/popup-same-origin-unsafe-allow-outgoing-with-same-origin.https.html
new file mode 100644
index 0000000000..89b0b4934e
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/historical/popup-same-origin-unsafe-allow-outgoing-with-same-origin.https.html
@@ -0,0 +1,58 @@
+<!doctype html>
+<meta charset=utf-8>
+<meta name=timeout content=long>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src="/common/dispatcher/dispatcher.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="/common/utils.js"></script>
+<script src="../resources/common.js"></script>
+<script src="../resources/popup-test.js"></script>
+<script>
+
+[
+ {
+ "title": "popup with empty coop",
+ "coop": "",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with coop unsafe-none",
+ "coop": "unsafe-none",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with jibberish coop",
+ "coop": "jibberish",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with obsolete coop",
+ "coop": "same-site",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with obsolete coop 2",
+ "coop": "same-site unsafe-allow-outgoing",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with obsolete coop 3",
+ "coop": "same-origin unsafe-allow-outgoing",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with coop same-origin",
+ "coop": "same-origin",
+ "opener": "severed"
+ },
+ {
+ "title": "popup with coop same-origin-allow-popups",
+ "coop": "same-origin-allow-popups",
+ "opener": "severed"
+ }
+].forEach(variant => {
+ popup_test(`Same-origin ${variant.title}`, SAME_ORIGIN, { coop: variant.coop }, variant.opener);
+});
+
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/historical/popup-same-origin-unsafe-allow-outgoing-with-same-origin.https.html.headers b/testing/web-platform/tests/html/cross-origin-opener-policy/historical/popup-same-origin-unsafe-allow-outgoing-with-same-origin.https.html.headers
new file mode 100644
index 0000000000..a19f4400ce
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/historical/popup-same-origin-unsafe-allow-outgoing-with-same-origin.https.html.headers
@@ -0,0 +1 @@
+Cross-Origin-Opener-Policy: same-origin unsafe-allow-outgoing
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/historical/popup-same-origin-unsafe-allow-outgoing-with-same-site.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/historical/popup-same-origin-unsafe-allow-outgoing-with-same-site.https.html
new file mode 100644
index 0000000000..fb3330365f
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/historical/popup-same-origin-unsafe-allow-outgoing-with-same-site.https.html
@@ -0,0 +1,58 @@
+<!doctype html>
+<meta charset=utf-8>
+<meta name=timeout content=long>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src="/common/dispatcher/dispatcher.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="/common/utils.js"></script>
+<script src="../resources/common.js"></script>
+<script src="../resources/popup-test.js"></script>
+<script>
+
+[
+ {
+ "title": "popup with empty coop",
+ "coop": "",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with coop unsafe-none",
+ "coop": "unsafe-none",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with jibberish coop",
+ "coop": "jibberish",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with obsolete coop",
+ "coop": "same-site",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with obsolete coop 2",
+ "coop": "same-site unsafe-allow-outgoing",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with obsolete coop 3",
+ "coop": "same-origin unsafe-allow-outgoing",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with coop same-origin",
+ "coop": "same-origin",
+ "opener": "severed"
+ },
+ {
+ "title": "popup with coop same-origin-allow-popups",
+ "coop": "same-origin-allow-popups",
+ "opener": "severed"
+ }
+].forEach(variant => {
+ popup_test(`Same-site ${variant.title}`, SAME_SITE, { coop: variant.coop }, variant.opener);
+});
+
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/historical/popup-same-origin-unsafe-allow-outgoing-with-same-site.https.html.headers b/testing/web-platform/tests/html/cross-origin-opener-policy/historical/popup-same-origin-unsafe-allow-outgoing-with-same-site.https.html.headers
new file mode 100644
index 0000000000..a19f4400ce
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/historical/popup-same-origin-unsafe-allow-outgoing-with-same-site.https.html.headers
@@ -0,0 +1 @@
+Cross-Origin-Opener-Policy: same-origin unsafe-allow-outgoing
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/historical/popup-same-site-unsafe-allow-outgoing-with-cross-origin.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/historical/popup-same-site-unsafe-allow-outgoing-with-cross-origin.https.html
new file mode 100644
index 0000000000..21e0875f41
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/historical/popup-same-site-unsafe-allow-outgoing-with-cross-origin.https.html
@@ -0,0 +1,58 @@
+<!doctype html>
+<meta charset=utf-8>
+<meta name=timeout content=long>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src="/common/dispatcher/dispatcher.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="/common/utils.js"></script>
+<script src="../resources/common.js"></script>
+<script src="../resources/popup-test.js"></script>
+<script>
+
+[
+ {
+ "title": "popup with empty coop",
+ "coop": "",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with coop unsafe-none",
+ "coop": "unsafe-none",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with jibberish coop",
+ "coop": "jibberish",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with obsolete coop",
+ "coop": "same-site",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with obsolete coop 2",
+ "coop": "same-site unsafe-allow-outgoing",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with obsolete coop 3",
+ "coop": "same-origin unsafe-allow-outgoing",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with coop same-origin",
+ "coop": "same-origin",
+ "opener": "severed"
+ },
+ {
+ "title": "popup with coop same-origin-allow-popups",
+ "coop": "same-origin-allow-popups",
+ "opener": "severed"
+ }
+].forEach(variant => {
+ popup_test(`Cross-origin ${variant.title}`, CROSS_ORIGIN, { coop: variant.coop }, variant.opener);
+});
+
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/historical/popup-same-site-unsafe-allow-outgoing-with-cross-origin.https.html.headers b/testing/web-platform/tests/html/cross-origin-opener-policy/historical/popup-same-site-unsafe-allow-outgoing-with-cross-origin.https.html.headers
new file mode 100644
index 0000000000..ab7b289481
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/historical/popup-same-site-unsafe-allow-outgoing-with-cross-origin.https.html.headers
@@ -0,0 +1 @@
+Cross-Origin-Opener-Policy: same-site unsafe-allow-outgoing
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/historical/popup-same-site-unsafe-allow-outgoing-with-same-origin.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/historical/popup-same-site-unsafe-allow-outgoing-with-same-origin.https.html
new file mode 100644
index 0000000000..89b0b4934e
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/historical/popup-same-site-unsafe-allow-outgoing-with-same-origin.https.html
@@ -0,0 +1,58 @@
+<!doctype html>
+<meta charset=utf-8>
+<meta name=timeout content=long>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src="/common/dispatcher/dispatcher.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="/common/utils.js"></script>
+<script src="../resources/common.js"></script>
+<script src="../resources/popup-test.js"></script>
+<script>
+
+[
+ {
+ "title": "popup with empty coop",
+ "coop": "",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with coop unsafe-none",
+ "coop": "unsafe-none",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with jibberish coop",
+ "coop": "jibberish",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with obsolete coop",
+ "coop": "same-site",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with obsolete coop 2",
+ "coop": "same-site unsafe-allow-outgoing",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with obsolete coop 3",
+ "coop": "same-origin unsafe-allow-outgoing",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with coop same-origin",
+ "coop": "same-origin",
+ "opener": "severed"
+ },
+ {
+ "title": "popup with coop same-origin-allow-popups",
+ "coop": "same-origin-allow-popups",
+ "opener": "severed"
+ }
+].forEach(variant => {
+ popup_test(`Same-origin ${variant.title}`, SAME_ORIGIN, { coop: variant.coop }, variant.opener);
+});
+
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/historical/popup-same-site-unsafe-allow-outgoing-with-same-origin.https.html.headers b/testing/web-platform/tests/html/cross-origin-opener-policy/historical/popup-same-site-unsafe-allow-outgoing-with-same-origin.https.html.headers
new file mode 100644
index 0000000000..ab7b289481
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/historical/popup-same-site-unsafe-allow-outgoing-with-same-origin.https.html.headers
@@ -0,0 +1 @@
+Cross-Origin-Opener-Policy: same-site unsafe-allow-outgoing
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/historical/popup-same-site-unsafe-allow-outgoing-with-same-site.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/historical/popup-same-site-unsafe-allow-outgoing-with-same-site.https.html
new file mode 100644
index 0000000000..fb3330365f
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/historical/popup-same-site-unsafe-allow-outgoing-with-same-site.https.html
@@ -0,0 +1,58 @@
+<!doctype html>
+<meta charset=utf-8>
+<meta name=timeout content=long>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src="/common/dispatcher/dispatcher.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="/common/utils.js"></script>
+<script src="../resources/common.js"></script>
+<script src="../resources/popup-test.js"></script>
+<script>
+
+[
+ {
+ "title": "popup with empty coop",
+ "coop": "",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with coop unsafe-none",
+ "coop": "unsafe-none",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with jibberish coop",
+ "coop": "jibberish",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with obsolete coop",
+ "coop": "same-site",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with obsolete coop 2",
+ "coop": "same-site unsafe-allow-outgoing",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with obsolete coop 3",
+ "coop": "same-origin unsafe-allow-outgoing",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with coop same-origin",
+ "coop": "same-origin",
+ "opener": "severed"
+ },
+ {
+ "title": "popup with coop same-origin-allow-popups",
+ "coop": "same-origin-allow-popups",
+ "opener": "severed"
+ }
+].forEach(variant => {
+ popup_test(`Same-site ${variant.title}`, SAME_SITE, { coop: variant.coop }, variant.opener);
+});
+
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/historical/popup-same-site-unsafe-allow-outgoing-with-same-site.https.html.headers b/testing/web-platform/tests/html/cross-origin-opener-policy/historical/popup-same-site-unsafe-allow-outgoing-with-same-site.https.html.headers
new file mode 100644
index 0000000000..ab7b289481
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/historical/popup-same-site-unsafe-allow-outgoing-with-same-site.https.html.headers
@@ -0,0 +1 @@
+Cross-Origin-Opener-Policy: same-site unsafe-allow-outgoing
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/historical/popup-same-site-with-cross-origin.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/historical/popup-same-site-with-cross-origin.https.html
new file mode 100644
index 0000000000..21e0875f41
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/historical/popup-same-site-with-cross-origin.https.html
@@ -0,0 +1,58 @@
+<!doctype html>
+<meta charset=utf-8>
+<meta name=timeout content=long>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src="/common/dispatcher/dispatcher.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="/common/utils.js"></script>
+<script src="../resources/common.js"></script>
+<script src="../resources/popup-test.js"></script>
+<script>
+
+[
+ {
+ "title": "popup with empty coop",
+ "coop": "",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with coop unsafe-none",
+ "coop": "unsafe-none",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with jibberish coop",
+ "coop": "jibberish",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with obsolete coop",
+ "coop": "same-site",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with obsolete coop 2",
+ "coop": "same-site unsafe-allow-outgoing",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with obsolete coop 3",
+ "coop": "same-origin unsafe-allow-outgoing",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with coop same-origin",
+ "coop": "same-origin",
+ "opener": "severed"
+ },
+ {
+ "title": "popup with coop same-origin-allow-popups",
+ "coop": "same-origin-allow-popups",
+ "opener": "severed"
+ }
+].forEach(variant => {
+ popup_test(`Cross-origin ${variant.title}`, CROSS_ORIGIN, { coop: variant.coop }, variant.opener);
+});
+
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/historical/popup-same-site-with-cross-origin.https.html.headers b/testing/web-platform/tests/html/cross-origin-opener-policy/historical/popup-same-site-with-cross-origin.https.html.headers
new file mode 100644
index 0000000000..34bd099a30
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/historical/popup-same-site-with-cross-origin.https.html.headers
@@ -0,0 +1 @@
+Cross-Origin-Opener-Policy: same-site
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/historical/popup-same-site-with-same-origin.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/historical/popup-same-site-with-same-origin.https.html
new file mode 100644
index 0000000000..89b0b4934e
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/historical/popup-same-site-with-same-origin.https.html
@@ -0,0 +1,58 @@
+<!doctype html>
+<meta charset=utf-8>
+<meta name=timeout content=long>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src="/common/dispatcher/dispatcher.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="/common/utils.js"></script>
+<script src="../resources/common.js"></script>
+<script src="../resources/popup-test.js"></script>
+<script>
+
+[
+ {
+ "title": "popup with empty coop",
+ "coop": "",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with coop unsafe-none",
+ "coop": "unsafe-none",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with jibberish coop",
+ "coop": "jibberish",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with obsolete coop",
+ "coop": "same-site",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with obsolete coop 2",
+ "coop": "same-site unsafe-allow-outgoing",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with obsolete coop 3",
+ "coop": "same-origin unsafe-allow-outgoing",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with coop same-origin",
+ "coop": "same-origin",
+ "opener": "severed"
+ },
+ {
+ "title": "popup with coop same-origin-allow-popups",
+ "coop": "same-origin-allow-popups",
+ "opener": "severed"
+ }
+].forEach(variant => {
+ popup_test(`Same-origin ${variant.title}`, SAME_ORIGIN, { coop: variant.coop }, variant.opener);
+});
+
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/historical/popup-same-site-with-same-origin.https.html.headers b/testing/web-platform/tests/html/cross-origin-opener-policy/historical/popup-same-site-with-same-origin.https.html.headers
new file mode 100644
index 0000000000..34bd099a30
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/historical/popup-same-site-with-same-origin.https.html.headers
@@ -0,0 +1 @@
+Cross-Origin-Opener-Policy: same-site
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/historical/popup-same-site-with-same-site.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/historical/popup-same-site-with-same-site.https.html
new file mode 100644
index 0000000000..fb3330365f
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/historical/popup-same-site-with-same-site.https.html
@@ -0,0 +1,58 @@
+<!doctype html>
+<meta charset=utf-8>
+<meta name=timeout content=long>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src="/common/dispatcher/dispatcher.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="/common/utils.js"></script>
+<script src="../resources/common.js"></script>
+<script src="../resources/popup-test.js"></script>
+<script>
+
+[
+ {
+ "title": "popup with empty coop",
+ "coop": "",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with coop unsafe-none",
+ "coop": "unsafe-none",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with jibberish coop",
+ "coop": "jibberish",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with obsolete coop",
+ "coop": "same-site",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with obsolete coop 2",
+ "coop": "same-site unsafe-allow-outgoing",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with obsolete coop 3",
+ "coop": "same-origin unsafe-allow-outgoing",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with coop same-origin",
+ "coop": "same-origin",
+ "opener": "severed"
+ },
+ {
+ "title": "popup with coop same-origin-allow-popups",
+ "coop": "same-origin-allow-popups",
+ "opener": "severed"
+ }
+].forEach(variant => {
+ popup_test(`Same-site ${variant.title}`, SAME_SITE, { coop: variant.coop }, variant.opener);
+});
+
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/historical/popup-same-site-with-same-site.https.html.headers b/testing/web-platform/tests/html/cross-origin-opener-policy/historical/popup-same-site-with-same-site.https.html.headers
new file mode 100644
index 0000000000..34bd099a30
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/historical/popup-same-site-with-same-site.https.html.headers
@@ -0,0 +1 @@
+Cross-Origin-Opener-Policy: same-site
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/iframe-popup-same-origin-allow-popups-to-same-origin-allow-popups.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/iframe-popup-same-origin-allow-popups-to-same-origin-allow-popups.https.html
new file mode 100644
index 0000000000..099424790a
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/iframe-popup-same-origin-allow-popups-to-same-origin-allow-popups.https.html
@@ -0,0 +1,88 @@
+<!doctype html>
+<meta charset=utf-8>
+<meta name=timeout content=long>
+<meta name="variant" content="?1-2">
+<meta name="variant" content="?3-4">
+<meta name="variant" content="?5-6">
+<meta name="variant" content="?7-8">
+<meta name="variant" content="?9-last">
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src=/common/dispatcher/dispatcher.js></script>
+<script src=/common/get-host-info.sub.js></script>
+<script src=/common/subset-tests.js></script>
+<script src=/common/utils.js></script>
+<script src="resources/common.js"></script>
+<script src="resources/iframe-test.js"></script>
+
+<body>
+<script>
+// This document has COOP: same-origin-allow-popups. The popup has COOP:
+// same-origin-allow-popups. Therefore there should only be an opener and name
+// if the frameOrigin and popupOrigin are same-origin with this document.
+[
+ {
+ "title": "same origin iframe, same origin popup",
+ "iframeOrigin": SAME_ORIGIN,
+ "popupOrigin": SAME_ORIGIN,
+ "opener": "preserved"
+ },
+ {
+ "title": "same site iframe, same origin popup",
+ "iframeOrigin": SAME_SITE,
+ "popupOrigin": SAME_ORIGIN,
+ "opener": "severed"
+ },
+ {
+ "title": "cross origin iframe, same origin popup",
+ "iframeOrigin": CROSS_ORIGIN,
+ "popupOrigin": SAME_ORIGIN,
+ "opener": "severed"
+ },
+ {
+ "title": "same origin iframe, same site popup",
+ "iframeOrigin": SAME_ORIGIN,
+ "popupOrigin": SAME_SITE,
+ "opener": "severed"
+ },
+ {
+ "title": "same site iframe, same site popup",
+ "iframeOrigin": SAME_SITE,
+ "popupOrigin": SAME_SITE,
+ "opener": "severed"
+ },
+ {
+ "title": "cross origin iframe, same site popup",
+ "iframeOrigin": CROSS_ORIGIN,
+ "popupOrigin": SAME_SITE,
+ "opener": "severed"
+ },
+ {
+ "title": "same origin iframe, cross origin popup",
+ "iframeOrigin": SAME_ORIGIN,
+ "popupOrigin": CROSS_ORIGIN,
+ "opener": "severed"
+ },
+ {
+ "title": "same site iframe, cross origin popup",
+ "iframeOrigin": SAME_SITE,
+ "popupOrigin": CROSS_ORIGIN,
+ "opener": "severed"
+ },
+ {
+ "title": "cross origin iframe, cross origin popup",
+ "iframeOrigin": CROSS_ORIGIN,
+ "popupOrigin": CROSS_ORIGIN,
+ "opener": "severed"
+ }
+].forEach(variant => {
+ subsetTest(
+ iframe_test,
+ `COOP: same-origin-allow-popups to popup COOP: same-origin-allow-popups via an iframe, with ${variant.title}`,
+ variant.iframeOrigin,
+ variant.popupOrigin,
+ { coop: 'same-origin-allow-popups' },
+ variant.opener);
+});
+</script>
+</body>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/iframe-popup-same-origin-allow-popups-to-same-origin-allow-popups.https.html.headers b/testing/web-platform/tests/html/cross-origin-opener-policy/iframe-popup-same-origin-allow-popups-to-same-origin-allow-popups.https.html.headers
new file mode 100644
index 0000000000..d83ed86fb9
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/iframe-popup-same-origin-allow-popups-to-same-origin-allow-popups.https.html.headers
@@ -0,0 +1 @@
+Cross-Origin-Opener-Policy: same-origin-allow-popups
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/iframe-popup-same-origin-allow-popups-to-same-origin.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/iframe-popup-same-origin-allow-popups-to-same-origin.https.html
new file mode 100644
index 0000000000..34699c8d08
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/iframe-popup-same-origin-allow-popups-to-same-origin.https.html
@@ -0,0 +1,86 @@
+<!doctype html>
+<meta charset=utf-8>
+<meta name=timeout content=long>
+<meta name="variant" content="?1-2">
+<meta name="variant" content="?3-4">
+<meta name="variant" content="?5-6">
+<meta name="variant" content="?7-8">
+<meta name="variant" content="?9-last">
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src=/common/dispatcher/dispatcher.js></script>
+<script src=/common/get-host-info.sub.js></script>
+<script src=/common/subset-tests.js></script>
+<script src=/common/utils.js></script>
+<script src="resources/common.js"></script>
+<script src="resources/iframe-test.js"></script>
+
+<body>
+<script>
+[
+ {
+ "title": "same origin iframe, same origin popup",
+ "iframeOrigin": SAME_ORIGIN,
+ "popupOrigin": SAME_ORIGIN,
+ "opener": "severed"
+ },
+ {
+ "title": "same site iframe, same origin popup",
+ "iframeOrigin": SAME_SITE,
+ "popupOrigin": SAME_ORIGIN,
+ "opener": "severed"
+ },
+ {
+ "title": "cross origin iframe, same origin popup",
+ "iframeOrigin": CROSS_ORIGIN,
+ "popupOrigin": SAME_ORIGIN,
+ "opener": "severed"
+ },
+ {
+ "title": "same origin iframe, same site popup",
+ "iframeOrigin": SAME_ORIGIN,
+ "popupOrigin": SAME_SITE,
+ "opener": "severed"
+ },
+ {
+ "title": "same site iframe, same site popup",
+ "iframeOrigin": SAME_SITE,
+ "popupOrigin": SAME_SITE,
+ "opener": "severed"
+ },
+ {
+ "title": "cross origin iframe, same site popup",
+ "iframeOrigin": CROSS_ORIGIN,
+ "popupOrigin": SAME_SITE,
+ "opener": "severed"
+ },
+ {
+ "title": "same origin iframe, cross origin popup",
+ "iframeOrigin": SAME_ORIGIN,
+ "popupOrigin": CROSS_ORIGIN,
+ "opener": "severed"
+ },
+ {
+ "title": "same site iframe, cross origin popup",
+ "iframeOrigin": SAME_SITE,
+ "popupOrigin": CROSS_ORIGIN,
+ "opener": "severed"
+ },
+ {
+ "title": "cross origin iframe, cross origin popup",
+ "iframeOrigin": CROSS_ORIGIN,
+ "popupOrigin": CROSS_ORIGIN,
+ "opener": "severed"
+ }
+].forEach(variant => {
+ subsetTest(
+ iframe_test,
+ `COOP: same-origin-allow-popups to popup COOP: same-origin via an iframe, with ${variant.title}`,
+ variant.iframeOrigin,
+ variant.popupOrigin,
+ { coop: 'same-origin' },
+ variant.opener);
+});
+</script>
+</body>
+
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/iframe-popup-same-origin-allow-popups-to-same-origin.https.html.headers b/testing/web-platform/tests/html/cross-origin-opener-policy/iframe-popup-same-origin-allow-popups-to-same-origin.https.html.headers
new file mode 100644
index 0000000000..d83ed86fb9
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/iframe-popup-same-origin-allow-popups-to-same-origin.https.html.headers
@@ -0,0 +1 @@
+Cross-Origin-Opener-Policy: same-origin-allow-popups
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/iframe-popup-same-origin-allow-popups-to-unsafe-none.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/iframe-popup-same-origin-allow-popups-to-unsafe-none.https.html
new file mode 100644
index 0000000000..29fb5cfa2d
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/iframe-popup-same-origin-allow-popups-to-unsafe-none.https.html
@@ -0,0 +1,85 @@
+<!doctype html>
+<meta charset=utf-8>
+<meta name=timeout content=long>
+<meta name="variant" content="?1-2">
+<meta name="variant" content="?3-4">
+<meta name="variant" content="?5-6">
+<meta name="variant" content="?7-8">
+<meta name="variant" content="?9-last">
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src=/common/dispatcher/dispatcher.js></script>
+<script src=/common/get-host-info.sub.js></script>
+<script src=/common/subset-tests.js></script>
+<script src=/common/utils.js></script>
+<script src="resources/common.js"></script>
+<script src="resources/iframe-test.js"></script>
+
+<body>
+<script>
+[
+ {
+ "title": "same origin iframe, same origin popup",
+ "iframeOrigin": SAME_ORIGIN,
+ "popupOrigin": SAME_ORIGIN,
+ "opener": "preserved"
+ },
+ {
+ "title": "same site iframe, same origin popup",
+ "iframeOrigin": SAME_SITE,
+ "popupOrigin": SAME_ORIGIN,
+ "opener": "preserved"
+ },
+ {
+ "title": "cross origin iframe, same origin popup",
+ "iframeOrigin": CROSS_ORIGIN,
+ "popupOrigin": SAME_ORIGIN,
+ "opener": "preserved"
+ },
+ {
+ "title": "same origin iframe, same site popup",
+ "iframeOrigin": SAME_ORIGIN,
+ "popupOrigin": SAME_SITE,
+ "opener": "preserved"
+ },
+ {
+ "title": "same site iframe, same site popup",
+ "iframeOrigin": SAME_SITE,
+ "popupOrigin": SAME_SITE,
+ "opener": "preserved"
+ },
+ {
+ "title": "cross origin iframe, same site popup",
+ "iframeOrigin": CROSS_ORIGIN,
+ "popupOrigin": SAME_SITE,
+ "opener": "preserved"
+ },
+ {
+ "title": "same origin iframe, cross origin popup",
+ "iframeOrigin": SAME_ORIGIN,
+ "popupOrigin": CROSS_ORIGIN,
+ "opener": "preserved"
+ },
+ {
+ "title": "same site iframe, cross origin popup",
+ "iframeOrigin": SAME_SITE,
+ "popupOrigin": CROSS_ORIGIN,
+ "opener": "preserved"
+ },
+ {
+ "title": "cross origin iframe, cross origin popup",
+ "iframeOrigin": CROSS_ORIGIN,
+ "popupOrigin": CROSS_ORIGIN,
+ "opener": "preserved"
+ }
+].forEach(variant => {
+ subsetTest(
+ iframe_test,
+ `COOP: same-origin-allow-popups to popup COOP: unsafe-none via an iframe, with ${variant.title}`,
+ variant.iframeOrigin,
+ variant.popupOrigin,
+ { coop: 'unsafe-none' },
+ variant.opener);
+});
+</script>
+</body>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/iframe-popup-same-origin-allow-popups-to-unsafe-none.https.html.headers b/testing/web-platform/tests/html/cross-origin-opener-policy/iframe-popup-same-origin-allow-popups-to-unsafe-none.https.html.headers
new file mode 100644
index 0000000000..d83ed86fb9
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/iframe-popup-same-origin-allow-popups-to-unsafe-none.https.html.headers
@@ -0,0 +1 @@
+Cross-Origin-Opener-Policy: same-origin-allow-popups
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/iframe-popup-same-origin-to-same-origin.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/iframe-popup-same-origin-to-same-origin.https.html
new file mode 100644
index 0000000000..7d31256584
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/iframe-popup-same-origin-to-same-origin.https.html
@@ -0,0 +1,88 @@
+<!doctype html>
+<meta charset=utf-8>
+<meta name=timeout content=long>
+<meta name="variant" content="?1-2">
+<meta name="variant" content="?3-4">
+<meta name="variant" content="?5-6">
+<meta name="variant" content="?7-8">
+<meta name="variant" content="?9-last">
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src=/common/dispatcher/dispatcher.js></script>
+<script src=/common/get-host-info.sub.js></script>
+<script src=/common/subset-tests.js></script>
+<script src=/common/utils.js></script>
+<script src="resources/common.js"></script>
+<script src="resources/iframe-test.js"></script>
+
+<body>
+<script>
+
+// This document has COOP "same-origin". The popup has COOP "same-origin". Therefore there should
+// only be an opener and name if the frameOrigin and popupOrigin are same-origin with this document.
+[
+ {
+ "title": "same origin iframe, same origin popup",
+ "iframeOrigin": SAME_ORIGIN,
+ "popupOrigin": SAME_ORIGIN,
+ "opener": "preserved"
+ },
+ {
+ "title": "same site iframe, same origin popup",
+ "iframeOrigin": SAME_SITE,
+ "popupOrigin": SAME_ORIGIN,
+ "opener": "noopener"
+ },
+ {
+ "title": "cross origin iframe, same origin popup",
+ "iframeOrigin": CROSS_ORIGIN,
+ "popupOrigin": SAME_ORIGIN,
+ "opener": "noopener"
+ },
+ {
+ "title": "same origin iframe, same site popup",
+ "iframeOrigin": SAME_ORIGIN,
+ "popupOrigin": SAME_SITE,
+ "opener": "severed"
+ },
+ {
+ "title": "same site iframe, same site popup",
+ "iframeOrigin": SAME_SITE,
+ "popupOrigin": SAME_SITE,
+ "opener": "noopener"
+ },
+ {
+ "title": "cross origin iframe, same site popup",
+ "iframeOrigin": CROSS_ORIGIN,
+ "popupOrigin": SAME_SITE,
+ "opener": "noopener"
+ },
+ {
+ "title": "same origin iframe, cross origin popup",
+ "iframeOrigin": SAME_ORIGIN,
+ "popupOrigin": CROSS_ORIGIN,
+ "opener": "severed"
+ },
+ {
+ "title": "same site iframe, cross origin popup",
+ "iframeOrigin": SAME_SITE,
+ "popupOrigin": CROSS_ORIGIN,
+ "opener": "noopener"
+ },
+ {
+ "title": "cross origin iframe, cross origin popup",
+ "iframeOrigin": CROSS_ORIGIN,
+ "popupOrigin": CROSS_ORIGIN,
+ "opener": "noopener"
+ }
+].forEach(variant => {
+ subsetTest(
+ iframe_test,
+ `COOP: same-origin to popup COOP: same-origin via an iframe, with ${variant.title}`,
+ variant.iframeOrigin,
+ variant.popupOrigin,
+ { coop: 'same-origin' },
+ variant.opener);
+});
+</script>
+</body>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/iframe-popup-same-origin-to-same-origin.https.html.headers b/testing/web-platform/tests/html/cross-origin-opener-policy/iframe-popup-same-origin-to-same-origin.https.html.headers
new file mode 100644
index 0000000000..46ad58d83b
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/iframe-popup-same-origin-to-same-origin.https.html.headers
@@ -0,0 +1 @@
+Cross-Origin-Opener-Policy: same-origin
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/iframe-popup-same-origin-to-unsafe-none.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/iframe-popup-same-origin-to-unsafe-none.https.html
new file mode 100644
index 0000000000..847f75665b
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/iframe-popup-same-origin-to-unsafe-none.https.html
@@ -0,0 +1,87 @@
+<!doctype html>
+<meta charset=utf-8>
+<meta name=timeout content=long>
+<meta name="variant" content="?1-2">
+<meta name="variant" content="?3-4">
+<meta name="variant" content="?5-6">
+<meta name="variant" content="?7-8">
+<meta name="variant" content="?9-last">
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src=/common/dispatcher/dispatcher.js></script>
+<script src=/common/get-host-info.sub.js></script>
+<script src=/common/subset-tests.js></script>
+<script src=/common/utils.js></script>
+<script src="resources/common.js"></script>
+<script src="resources/iframe-test.js"></script>
+
+<body>
+<script>
+// This document has COOP: same-origin. The popup has no COOP. Therefore there
+// should be no opener or name.
+[
+ {
+ "title": "same origin iframe, same origin popup",
+ "iframeOrigin": SAME_ORIGIN,
+ "popupOrigin": SAME_ORIGIN,
+ "opener": "severed"
+ },
+ {
+ "title": "same site iframe, same origin popup",
+ "iframeOrigin": SAME_SITE,
+ "popupOrigin": SAME_ORIGIN,
+ "opener": "noopener"
+ },
+ {
+ "title": "cross origin iframe, same origin popup",
+ "iframeOrigin": CROSS_ORIGIN,
+ "popupOrigin": SAME_ORIGIN,
+ "opener": "noopener"
+ },
+ {
+ "title": "same origin iframe, same site popup",
+ "iframeOrigin": SAME_ORIGIN,
+ "popupOrigin": SAME_SITE,
+ "opener": "severed"
+ },
+ {
+ "title": "same site iframe, same site popup",
+ "iframeOrigin": SAME_SITE,
+ "popupOrigin": SAME_SITE,
+ "opener": "noopener"
+ },
+ {
+ "title": "cross origin iframe, same site popup",
+ "iframeOrigin": CROSS_ORIGIN,
+ "popupOrigin": SAME_SITE,
+ "opener": "noopener"
+ },
+ {
+ "title": "same origin iframe, cross origin popup",
+ "iframeOrigin": SAME_ORIGIN,
+ "popupOrigin": CROSS_ORIGIN,
+ "opener": "severed"
+ },
+ {
+ "title": "same site iframe, cross origin popup",
+ "iframeOrigin": SAME_SITE,
+ "popupOrigin": CROSS_ORIGIN,
+ "opener": "noopener"
+ },
+ {
+ "title": "cross origin iframe, cross origin popup",
+ "iframeOrigin": CROSS_ORIGIN,
+ "popupOrigin": CROSS_ORIGIN,
+ "opener": "noopener"
+ }
+].forEach(variant => {
+ subsetTest(
+ iframe_test,
+ `COOP: same-origin to popup COOP: unsafe-none via an iframe, with ${variant.title}`,
+ variant.iframeOrigin,
+ variant.popupOrigin,
+ { coop: 'unsafe-none' },
+ variant.opener);
+});
+</script>
+</body>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/iframe-popup-same-origin-to-unsafe-none.https.html.headers b/testing/web-platform/tests/html/cross-origin-opener-policy/iframe-popup-same-origin-to-unsafe-none.https.html.headers
new file mode 100644
index 0000000000..46ad58d83b
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/iframe-popup-same-origin-to-unsafe-none.https.html.headers
@@ -0,0 +1 @@
+Cross-Origin-Opener-Policy: same-origin
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/iframe-popup-unsafe-none-to-same-origin.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/iframe-popup-unsafe-none-to-same-origin.https.html
new file mode 100644
index 0000000000..8158b9f4d5
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/iframe-popup-unsafe-none-to-same-origin.https.html
@@ -0,0 +1,87 @@
+<!doctype html>
+<meta charset=utf-8>
+<meta name=timeout content=long>
+<meta name="variant" content="?1-2">
+<meta name="variant" content="?3-4">
+<meta name="variant" content="?5-6">
+<meta name="variant" content="?7-8">
+<meta name="variant" content="?9-last">
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src=/common/dispatcher/dispatcher.js></script>
+<script src=/common/get-host-info.sub.js></script>
+<script src=/common/subset-tests.js></script>
+<script src=/common/utils.js></script>
+<script src="resources/common.js"></script>
+<script src="resources/iframe-test.js"></script>
+
+<body>
+<script>
+// This document has COOP: unsafe-none. The popup has COOP: same-origin.
+// Therefore there should be no opener or name.
+[
+ {
+ "title": "same origin iframe, same origin popup",
+ "iframeOrigin": SAME_ORIGIN,
+ "popupOrigin": SAME_ORIGIN,
+ "opener": "severed"
+ },
+ {
+ "title": "same site iframe, same origin popup",
+ "iframeOrigin": SAME_SITE,
+ "popupOrigin": SAME_ORIGIN,
+ "opener": "severed"
+ },
+ {
+ "title": "cross origin iframe, same origin popup",
+ "iframeOrigin": CROSS_ORIGIN,
+ "popupOrigin": SAME_ORIGIN,
+ "opener": "severed"
+ },
+ {
+ "title": "same origin iframe, same site popup",
+ "iframeOrigin": SAME_ORIGIN,
+ "popupOrigin": SAME_SITE,
+ "opener": "severed"
+ },
+ {
+ "title": "same site iframe, same site popup",
+ "iframeOrigin": SAME_SITE,
+ "popupOrigin": SAME_SITE,
+ "opener": "severed"
+ },
+ {
+ "title": "cross origin iframe, same site popup",
+ "iframeOrigin": CROSS_ORIGIN,
+ "popupOrigin": SAME_SITE,
+ "opener": "severed"
+ },
+ {
+ "title": "same origin iframe, cross origin popup",
+ "iframeOrigin": SAME_ORIGIN,
+ "popupOrigin": CROSS_ORIGIN,
+ "opener": "severed"
+ },
+ {
+ "title": "same site iframe, cross origin popup",
+ "iframeOrigin": SAME_SITE,
+ "popupOrigin": CROSS_ORIGIN,
+ "opener": "severed"
+ },
+ {
+ "title": "cross origin iframe, cross origin popup",
+ "iframeOrigin": CROSS_ORIGIN,
+ "popupOrigin": CROSS_ORIGIN,
+ "opener": "severed"
+ }
+].forEach(variant => {
+ subsetTest(
+ iframe_test,
+ `COOP: unsafe-none to popup COOP: same-origin via an iframe, with ${variant.title}`,
+ variant.iframeOrigin,
+ variant.popupOrigin,
+ { coop: 'same-origin' },
+ variant.opener);
+});
+</script>
+</body>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/iframe-popup-unsafe-none-to-same-origin.https.html.headers b/testing/web-platform/tests/html/cross-origin-opener-policy/iframe-popup-unsafe-none-to-same-origin.https.html.headers
new file mode 100644
index 0000000000..073ce7adfb
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/iframe-popup-unsafe-none-to-same-origin.https.html.headers
@@ -0,0 +1 @@
+Cross-Origin-Opener-Policy: unsafe-none
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/iframe-popup-unsafe-none-to-unsafe-none.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/iframe-popup-unsafe-none-to-unsafe-none.https.html
new file mode 100644
index 0000000000..74ceeb290d
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/iframe-popup-unsafe-none-to-unsafe-none.https.html
@@ -0,0 +1,85 @@
+<!doctype html>
+<meta charset=utf-8>
+<meta name=timeout content=long>
+<meta name="variant" content="?1-2">
+<meta name="variant" content="?3-4">
+<meta name="variant" content="?5-6">
+<meta name="variant" content="?7-8">
+<meta name="variant" content="?9-last">
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src=/common/dispatcher/dispatcher.js></script>
+<script src=/common/get-host-info.sub.js></script>
+<script src=/common/subset-tests.js></script>
+<script src=/common/utils.js></script>
+<script src="resources/common.js"></script>
+<script src="resources/iframe-test.js"></script>
+
+<body>
+<script>
+[
+ {
+ "title": "same origin iframe, same origin popup",
+ "iframeOrigin": SAME_ORIGIN,
+ "popupOrigin": SAME_ORIGIN,
+ "opener": "preserved"
+ },
+ {
+ "title": "same site iframe, same origin popup",
+ "iframeOrigin": SAME_SITE,
+ "popupOrigin": SAME_ORIGIN,
+ "opener": "preserved"
+ },
+ {
+ "title": "cross origin iframe, same origin popup",
+ "iframeOrigin": CROSS_ORIGIN,
+ "popupOrigin": SAME_ORIGIN,
+ "opener": "preserved"
+ },
+ {
+ "title": "same origin iframe, same site popup",
+ "iframeOrigin": SAME_ORIGIN,
+ "popupOrigin": SAME_SITE,
+ "opener": "preserved"
+ },
+ {
+ "title": "same site iframe, same site popup",
+ "iframeOrigin": SAME_SITE,
+ "popupOrigin": SAME_SITE,
+ "opener": "preserved"
+ },
+ {
+ "title": "cross origin iframe, same site popup",
+ "iframeOrigin": CROSS_ORIGIN,
+ "popupOrigin": SAME_SITE,
+ "opener": "preserved"
+ },
+ {
+ "title": "same origin iframe, cross origin popup",
+ "iframeOrigin": SAME_ORIGIN,
+ "popupOrigin": CROSS_ORIGIN,
+ "opener": "preserved"
+ },
+ {
+ "title": "same site iframe, cross origin popup",
+ "iframeOrigin": SAME_SITE,
+ "popupOrigin": CROSS_ORIGIN,
+ "opener": "preserved"
+ },
+ {
+ "title": "cross origin iframe, cross origin popup",
+ "iframeOrigin": CROSS_ORIGIN,
+ "popupOrigin": CROSS_ORIGIN,
+ "opener": "preserved"
+ }
+].forEach(variant => {
+ subsetTest(
+ iframe_test,
+ `COOP: unsafe-none to popup COOP: unsafe-none via an iframe, with ${variant.title}`,
+ variant.iframeOrigin,
+ variant.popupOrigin,
+ { coop: 'unsafe-none' },
+ variant.opener);
+});
+</script>
+</body>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/iframe-popup-unsafe-none-to-unsafe-none.https.html.headers b/testing/web-platform/tests/html/cross-origin-opener-policy/iframe-popup-unsafe-none-to-unsafe-none.https.html.headers
new file mode 100644
index 0000000000..073ce7adfb
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/iframe-popup-unsafe-none-to-unsafe-none.https.html.headers
@@ -0,0 +1 @@
+Cross-Origin-Opener-Policy: unsafe-none
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/javascript-url.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/javascript-url.https.html
new file mode 100644
index 0000000000..8ebb3ccd4a
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/javascript-url.https.html
@@ -0,0 +1,199 @@
+<!DOCTYPE html>
+<title>Cross-Origin-Opener-Policy and a "javascript:" URL popup</title>
+<meta charset="utf-8">
+<meta name="timeout" content="long">
+<meta name="variant" content="?1-2">
+<meta name="variant" content="?3-4">
+<meta name="variant" content="?5-6">
+<meta name="variant" content="?7-8">
+<meta name="variant" content="?9-10">
+<meta name="variant" content="?11-12">
+<meta name="variant" content="?13-14">
+<meta name="variant" content="?15-16">
+<meta name="variant" content="?17-last">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/dispatcher/dispatcher.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="/common/subset-tests.js"></script>
+<script src="/common/utils.js"></script>
+<script src="resources/common.js"></script>
+
+<p>According to HTML's navigate algorithm, requests to <code>javascript:</code>
+URLs should inherit the cross-origin opener policy of the active document. To
+observe this, each subtest uses the following procedure.</p>
+
+<ol>
+ <li>create popup with a given COOP (the <code>parentCOOP</code>)</li>
+ <li>navigate the popup to a <code>javascript:</code> URL (the new document is
+ expected to inherit the <code>parentCOOP</code>)</li>
+ <li>from the popup, create a second popup window with a given COOP (the
+ <code>childCOOP</code>)</li>
+</ol>
+
+<p>Both popup windows inspect state and report back to the test.</p>
+
+<pre>
+ .---- test ----.
+ | open(https:) |
+ | parentCOOP | .----- subject -------.
+ | '---------> | --------. |
+ | | | v |
+ | | | assign(javascript:) |
+ | | | (COOP under test) |
+ | | | | |
+ | | | open(https:) |
+ | | | childCOOP | .- child -.
+ | | | '--------------> | |
+ | | '---------------------' '---------'
+ | | | |
+ | validate | <--status---+---------------------'
+ '--------------'
+</pre>
+
+<script>
+'use strict';
+
+function getExecutorPath(uuid, origin, coopHeader) {
+ const executorPath = '/common/dispatcher/executor.html?';
+ const coopHeaderPipe =
+ `|header(Cross-Origin-Opener-Policy,${encodeURIComponent(coopHeader)})`;
+ return origin + executorPath + `uuid=${uuid}` + '&pipe=' + coopHeaderPipe;
+}
+
+function assert_isolated(results) {
+ assert_equals(results.childName, '', 'child name');
+ assert_false(results.childOpener, 'child opener');
+ // The test subject's reference to the "child" window must report "closed"
+ // when COOP enforces isolation because the document initially created during
+ // the window open steps must be discarded when a new document object is
+ // created at the end of the navigation.
+ assert_true(results.childClosed, 'child closed');
+}
+
+function assert_not_isolated(results, expectedName) {
+ assert_equals(results.childName, expectedName, 'child name');
+ assert_true(results.childOpener, 'child opener');
+ assert_false(results.childClosed, 'child closed');
+}
+
+async function javascript_url_test(parentCOOP, childCOOP, origin, resultsVerification) {
+ promise_test(async t => {
+ const parentToken = token();
+ const childToken = token();
+ const responseToken = token();
+
+ const parentURL = getExecutorPath(
+ parentToken,
+ SAME_ORIGIN.origin,
+ parentCOOP);
+ const childURL = getExecutorPath(
+ childToken,
+ origin.origin,
+ childCOOP);
+
+ // Open a first popup, referred to as the parent popup, and wait for it to
+ // load.
+ window.open(parentURL);
+ send(parentToken, `send('${responseToken}', 'Done loading');`);
+ assert_equals(await receive(responseToken), 'Done loading');
+
+ // Make sure the parent popup is removed once the test has run, keeping a
+ // clean state.
+ add_completion_callback(() => {
+ send(parentToken, 'close');
+ });
+
+ // Navigate the popup to the javascript URL. It should inherit the current
+ // document's COOP. Because we're navigating to a page that is not an
+ // executor, we lose access to easy messaging, making things a bit more
+ // complicated. We use a predetermined scenario of communication that
+ // enables us to retrieve whether the child popup appears closed from the
+ // parent popup.
+ //
+ // Notes:
+ // - Splitting the script tag prevents HTML parsing to kick in.
+ // - The innermost double quotes need a triple backslash, because it goes
+ // through two rounds of consuming escape characters (\\\" -> \" -> ").
+ // - The javascript URL does not accept \n characters so we need to use
+ // a new template literal for each line.
+ send(parentToken,
+ `location.assign("javascript:'` +
+ // Include dispatcher.js to have access to send() and receive().
+ `<script src=\\\"/common/dispatcher/dispatcher.js\\\"></scr` + `ipt>` +
+ `<script> (async () => {` +
+
+ // Open the child popup and keep a handle to it.
+ `const w = open(\\\"${childURL}\\\", \\\"${childToken}\\\");` +
+
+ // We wait for the main frame to query the w.closed property.
+ `await receive(\\\"${parentToken}\\\");` +
+ `send(\\\"${responseToken}\\\", w.closed);` +
+
+ // Finally we wait for the cleanup indicating that this popup can be
+ // closed.
+ `await receive(\\\"${parentToken}\\\");` +
+ `close();` +
+ `})()</scr` + `ipt>'");`
+ );
+
+ // Make sure the javascript navigation ran, and the child popup was created.
+ send(childToken, `send('${responseToken}', 'Done loading');`);
+ assert_equals(await receive(responseToken), 'Done loading');
+
+ // Make sure the child popup is removed once the test has run, keeping a
+ // clean state.
+ add_completion_callback(() => {
+ send(childToken, `close()`);
+ });
+
+ // Give some time for things to settle across processes etc. before
+ // proceeding with verifications.
+ await new Promise(resolve => { t.step_timeout(resolve, 500); });
+
+ // Gather information about the child popup and verify that they match what
+ // we expect.
+ const results = {};
+ send(parentToken, 'query');
+ results.childClosed = await receive(responseToken) === 'true';
+
+ send(childToken, `send('${responseToken}', opener != null);`);
+ results.childOpener = await receive(responseToken) === 'true';
+
+ send(childToken, `send('${responseToken}', name);`);
+ results.childName = await receive(responseToken);
+
+ resultsVerification(results, childToken);
+ }, `navigation: ${origin.name}; ` + `parentCOOP: ${parentCOOP}; ` +
+ `childCOOP: ${childCOOP}`);
+}
+
+const tests = [
+ ['unsafe-none', 'unsafe-none', SAME_ORIGIN, assert_not_isolated],
+ ['unsafe-none', 'unsafe-none', SAME_SITE, assert_not_isolated],
+ ['unsafe-none', 'same-origin-allow-popups', SAME_ORIGIN, assert_isolated],
+ ['unsafe-none', 'same-origin-allow-popups', SAME_SITE, assert_isolated],
+ ['unsafe-none', 'same-origin', SAME_ORIGIN, assert_isolated],
+ ['unsafe-none', 'same-origin', SAME_SITE, assert_isolated],
+ ['same-origin-allow-popups', 'unsafe-none', SAME_ORIGIN, assert_not_isolated],
+ ['same-origin-allow-popups', 'unsafe-none', SAME_SITE, assert_not_isolated],
+ ['same-origin-allow-popups', 'same-origin-allow-popups', SAME_ORIGIN, assert_not_isolated],
+ ['same-origin-allow-popups', 'same-origin-allow-popups', SAME_SITE, assert_isolated],
+ ['same-origin-allow-popups', 'same-origin', SAME_ORIGIN, assert_isolated],
+ ['same-origin-allow-popups', 'same-origin', SAME_SITE, assert_isolated],
+ ['same-origin', 'unsafe-none', SAME_ORIGIN, assert_isolated],
+ ['same-origin', 'unsafe-none', SAME_SITE, assert_isolated],
+ ['same-origin', 'same-origin-allow-popups', SAME_ORIGIN, assert_isolated],
+ ['same-origin', 'same-origin-allow-popups', SAME_SITE, assert_isolated],
+ ['same-origin', 'same-origin', SAME_ORIGIN, assert_not_isolated],
+ ['same-origin', 'same-origin', SAME_SITE, assert_isolated],
+].forEach(([parentCOOP, childCOOP, origin, expectation]) => {
+ subsetTest(
+ javascript_url_test,
+ parentCOOP,
+ childCOOP,
+ origin,
+ expectation);
+});
+
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/navigate-to-aboutblank.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/navigate-to-aboutblank.https.html
new file mode 100644
index 0000000000..b2145cfa56
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/navigate-to-aboutblank.https.html
@@ -0,0 +1,193 @@
+<title>
+ This tests the inheritance of COOP for navigations to about:blank.
+</title>
+<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="/common/dispatcher/dispatcher.js"></script>
+
+<p>Non-initial empty documents (about:blank) should inherit their
+ cross-origin-opener-policy from the navigation's initiator top level document,
+ if the initiator and its top level document are same-origin, or default
+ (unsafe-none) otherwise.
+</p>
+
+<ol>
+ <li>Create the opener popup with a given COOP <code>openerCOOP</code>.</li>
+ <li>Add iframe to the opener popup that is either same-origin or
+ cross-origin.
+ </li>
+ <li>Opener's iframe opens a new window, to a network document with <code>openeeCOOP</code>.</li>
+ <li>Opener's iframe navigates the openee popup to about:blank.</li>
+</ol>
+
+<script>
+const executor_path = "/common/dispatcher/executor.html?pipe=";
+const same_origin = get_host_info().HTTPS_ORIGIN;
+const cross_origin = get_host_info().HTTPS_REMOTE_ORIGIN;
+const coop_same_origin_header =
+ '|header(Cross-Origin-Opener-Policy,same-origin)';
+const coep_require_corp_header =
+ '|header(Cross-Origin-Embedder-Policy,require-corp)';
+const coop_same_origin_plus_coep_header =
+ coop_same_origin_header + coep_require_corp_header;
+const coop_same_origin_allow_popups_header =
+ '|header(Cross-Origin-Opener-Policy,same-origin-allow-popups)';
+const coop_unsafe_none_header =
+ '|header(Cross-Origin-Opener-Policy,unsafe-none)';
+
+function navigateToAboutBlankTest(
+ opener_COOP_header,
+ iframe_origin,
+ openee_COOP_header,
+ openee_origin,
+ iframe_header,
+ expect_openee_closed
+){
+ return promise_test(async t => {
+ const this_window_token = token();
+ const opener_token = token();
+ const openee_token = token();
+ const iframe_token = token();
+
+ const opener_url = same_origin + executor_path + opener_COOP_header +
+ `&uuid=${opener_token}`;
+ const openee_url = openee_origin + executor_path + openee_COOP_header +
+ `&uuid=${openee_token}`;
+ const iframe_url = iframe_origin + executor_path + iframe_header + `&uuid=${iframe_token}`;
+
+ t.add_cleanup(() => {
+ send(openee_token, "window.close()");
+ send(opener_token, "window.close()");
+ });
+
+ // 1. Create the opener window.
+ let opener_window_proxy = window.open(opener_url, opener_token);
+
+ // 2. Create the iframe.
+ send(opener_token, `
+ iframe = document.createElement('iframe');
+ iframe.src = "${iframe_url}";
+ document.body.appendChild(iframe);
+ `);
+
+ // 3. The iframe opens its openee window.
+ send(iframe_token, `
+ window.openee = window.open(
+ '${openee_url.replace(/,/g, '\\,')}',
+ "${openee_token}"
+ );
+ `);
+
+ // 4. Ensure the popup is fully loaded.
+ send(openee_token, `send("${this_window_token}", "Ack");`);
+ assert_equals(await receive(this_window_token), "Ack");
+
+ // 5. The iframe navigates openee to about:blank.
+ send(iframe_token, `
+ window.openee_blank = window.open('about:blank', "${openee_token}");
+ (async function() {
+ const timeout = 2000;
+ const retry_delay = 100;
+ for(let i = 0; i * retry_delay < timeout; ++i) {
+ // A try-catch block is used, because of same-origin policy,
+ // preventing access to the document before committing about:blank.
+ try {
+ if (window.openee_blank.closed ||
+ window.openee_blank.document.location.href == "about:blank") {
+ send("${this_window_token}", "about:blank loaded");
+ return;
+ }
+ } catch(e) {}
+ await new Promise(resolve => setTimeout(resolve, retry_delay));
+ }
+ send("${this_window_token}", "about:blank not loaded");
+ })()
+ `);
+ assert_equals(await receive(this_window_token), "about:blank loaded");
+
+ // 6. Retrieve and check the results.
+ send(iframe_token, `
+ send("${this_window_token}", window.openee.closed);
+ `);
+ assert_equals(await receive(this_window_token), `${expect_openee_closed}`);
+ }, `Navigate to about:blank from iframe with opener.top \
+COOP: ${opener_COOP_header}, iframe origin: ${iframe_origin}, \
+openee COOP: ${openee_COOP_header}, openee origin: ${openee_origin}.`);
+};
+
+// iframe same-origin with its top-level embedder:
+// initial empty document and about:blank navigations initiated from the
+// same-origin iframe will inherit the COOP from the iframe's top-level embedder.
+
+// Since all navigations of openee are within same-origin pages with the
+// same COOP value, there are no browsing context group switches.
+navigateToAboutBlankTest(
+ coop_same_origin_header,
+ same_origin,
+ coop_same_origin_header,
+ same_origin,
+ "",
+ false
+);
+
+// Since all navigations of openee are within same-origin pages with the
+// same COOP value, there are no browsing context group switches.
+// Test with both COOP and COEP.
+navigateToAboutBlankTest(
+ coop_same_origin_plus_coep_header,
+ same_origin,
+ coop_same_origin_plus_coep_header,
+ same_origin,
+ coep_require_corp_header,
+ false
+);
+
+// Since all navigations of openee are within same-origin pages with the
+// same COOP value, there are no browsing context group switches.
+navigateToAboutBlankTest(
+ coop_same_origin_allow_popups_header,
+ same_origin,
+ coop_same_origin_allow_popups_header,
+ same_origin,
+ "",
+ false
+);
+
+// The first openee navigation, from initial empty document to
+// cross-origin will not switch the browsing context group, thanks to the
+// same-origin-allow-popups behavior.
+// The second openee navigation, to about:blank, will inherit from the
+// iniatiator's, the iframe, top. Navigating from a COOP: unsafe-none page to
+// a COOP: same-origin-allow-popups page causes a browsing context group
+// switch.
+navigateToAboutBlankTest(
+ coop_same_origin_allow_popups_header,
+ same_origin,
+ coop_unsafe_none_header,
+ cross_origin,
+ "",
+ true
+);
+
+// iframe cross-origin with its top-level embedder:
+// initial empty document and about:blank navigations initiated from the
+// cross-origin iframe will default COOP to unsafe-none.
+
+// The navigation from the initial empty document and the cross_origin url
+// does not cause a browsing context group switch
+// (both have COOP: unsafe-none).
+// The navigation from the cross-origin url to about:blank does not cause a
+// browsing context group swich, about:blank defaulted its COOP value to
+// unsafe-none.
+navigateToAboutBlankTest(
+ coop_same_origin_allow_popups_header,
+ cross_origin,
+ coop_unsafe_none_header,
+ cross_origin,
+ "",
+ false
+);
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/navigate-top-to-aboutblank.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/navigate-top-to-aboutblank.https.html
new file mode 100644
index 0000000000..fe605baf45
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/navigate-top-to-aboutblank.https.html
@@ -0,0 +1,171 @@
+<title>
+ This tests the inheritance of COOP for navigations of the top document to about:blank.
+</title>
+<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="/common/dispatcher/dispatcher.js"></script>
+<script src="/html/cross-origin-opener-policy/resources/common.js"></script>
+
+
+<p>Non-initial empty documents (about:blank) should inherit their
+ cross-origin-opener-policy from the navigation's initiator top level document,
+ if the initiator and its top level document are same-origin, or default (to
+ unsafe-none) otherwise.
+</p>
+
+<ol>
+ <li>Create the opener popup with a given COOP <code>openerCOOP</code>.</li>
+ <li>Add iframe to the opener popup that is either same-origin or
+ cross-origin.
+ </li>
+ <li>Opener opens a new window, to a network document with the same origin and
+ COOP value as opener.</li>
+ <li>Opener's iframe navigates its parent frame (opener) to about:blank.</li>
+ <li>Verify the openee still has access to its opener.</li>
+</ol>
+
+<script>
+const executor_path = "/common/dispatcher/executor.html?pipe=";
+const same_origin = get_host_info().HTTPS_ORIGIN;
+const cross_origin = get_host_info().HTTPS_REMOTE_ORIGIN;
+const coop_same_origin_header =
+ '|header(Cross-Origin-Opener-Policy,same-origin)';
+const coop_same_origin_allow_popups_header =
+ '|header(Cross-Origin-Opener-Policy,same-origin-allow-popups)';
+const coop_unsafe_none_header =
+ '|header(Cross-Origin-Opener-Policy,unsafe-none)';
+
+function navigateToAboutBlankTest(
+ COOP_header,
+ iframe_origin,
+ expect_opener_closed
+){
+ return promise_test(async t => {
+ const this_window_token = token();
+ const opener_token = token();
+ const openee_token = token();
+ const iframe_token = token();
+
+ const opener_url = same_origin + executor_path + COOP_header +
+ `&uuid=${opener_token}`;
+ const openee_url = same_origin + executor_path + COOP_header +
+ `&uuid=${openee_token}`;
+ const iframe_url = iframe_origin + executor_path + `&uuid=${iframe_token}`;
+
+ t.add_cleanup(() => {
+ send(opener_token, "window.close()");
+ send(openee_token, "window.close()");
+ });
+
+ // 1. Create the opener window.
+ let opener_window_proxy = window.open(opener_url, opener_token);
+
+ // 2. Create the iframe.
+ send(opener_token, `
+ iframe = document.createElement('iframe');
+ iframe.src = "${iframe_url}";
+ document.body.appendChild(iframe);
+ `);
+
+ // 3. The opener opens openee window.
+ send(opener_token, `
+ window.openee = window.open(
+ '${openee_url.replace(/,/g, '\\,')}'
+ );
+ `);
+
+ // 4. Ensure the popup is fully loaded.
+ send(openee_token, `send("${this_window_token}", "Ack");`);
+ assert_equals(await receive(this_window_token), "Ack");
+
+ // 5. The iframe navigates its top-level document to about:blank. It needs
+ // to receive a user action as it may be cross-origin and it navigates top
+ // to a cross-origin document.
+ // https://github.com/WICG/interventions/issues/16
+ send(iframe_token, addScriptAndTriggerOnload(
+ "/resources/testdriver.js",
+ `${addScriptAndTriggerOnload("/resources/testdriver-vendor.js",
+ `
+ test_driver.bless('navigate top to about:blank', () => {
+ open("about:blank", "_top");
+ });
+ `)}
+ `));
+
+ // 6. Ensure opener is fully loaded and then retrieve the results.
+ send(openee_token, `
+ (async function() {
+ const timeout = 2000;
+ const retry_delay = 100;
+ for(let i = 0; i * retry_delay < timeout; ++i) {
+ // A try-catch block is used, because of same-origin policy,
+ // which may prevent the access to the opener if its origin changed,
+ // after a navigation to about:blank from the cross origin iframe.
+ try {
+ if (
+ window.opener === null ||
+ window.opener.closed ||
+ window.opener.document.location.href == "about:blank") {
+ send("${this_window_token}", "about:blank loaded");
+ return;
+ }
+ } catch(e) {
+ // The exception is thrown when about:blank is loaded and is
+ // cross-origin with openee.
+ send("${this_window_token}", "about:blank loaded");
+ return;
+ }
+ await new Promise(resolve => setTimeout(resolve, retry_delay));
+ }
+ send("${this_window_token}", "about:blank NOT loaded");
+ })()
+ `);
+ assert_equals(await receive(this_window_token), "about:blank loaded");
+
+ // 7. Retrieve and check the results.
+ send(openee_token, `
+ send(
+ "${this_window_token}",
+ window.opener === null || window.opener.closed);
+ `);
+
+ assert_equals(await receive(this_window_token), `${expect_opener_closed}`);
+ }, `Navigate top to about:blank from iframe with \
+opener COOP: ${COOP_header}, iframe origin: ${iframe_origin}`);
+};
+
+// iframe same-origin with its top-level embedder:
+// initial empty document and about:blank navigations initiated from the
+// same-origin iframe will inherit COOP from the iframe's top-level embedder.
+
+// Opener's navigation to about:blank stays in the same browsing context group.
+navigateToAboutBlankTest(
+ coop_same_origin_header,
+ same_origin,
+ false
+);
+
+// iframe cross-origin with its top-level embedder:
+// initial empty document and about:blank navigations initiated from the
+// cross-origin iframe will default COOP to unsafe-none.
+
+// Opener's navigation to about:blank doesn't inherit COOP, leading to a
+// browsing context group switch.
+navigateToAboutBlankTest(
+ coop_same_origin_header,
+ cross_origin,
+ true
+);
+
+// Same origin allow popups allows the navigation of top to the cross-origin
+// about:blank (origin inherited from the iframe) page, which does not have COOP
+// (initiator is a cross origin iframe).
+navigateToAboutBlankTest(
+ coop_same_origin_allow_popups_header,
+ cross_origin,
+ false
+);
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/no-https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/no-https.html
new file mode 100644
index 0000000000..db15d5c676
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/no-https.html
@@ -0,0 +1,21 @@
+<!doctype html>
+<meta name=timeout content=long>
+<title>Cross-Origin-Opener-Policy requires secure contexts</title>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script>
+async_test(t => {
+ const popup = window.open("resources/call-functionCalledByOpenee.html");
+ t.add_cleanup(() => {
+ popup.close();
+ });
+ window.functionCalledByOpenee = t.step_func_done(() => {
+ assert_false(popup.closed);
+ });
+ assert_equals(window, popup.opener);
+}, "Cross-Origin-Opener-Policy only works over secure contexts");
+
+test(() => {
+ assert_false(window.crossOriginIsolated);
+}, "Bonus: window.crossOriginIsolated");
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/no-https.html.headers b/testing/web-platform/tests/html/cross-origin-opener-policy/no-https.html.headers
new file mode 100644
index 0000000000..46ad58d83b
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/no-https.html.headers
@@ -0,0 +1 @@
+Cross-Origin-Opener-Policy: same-origin
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/popup-coop-by-sw.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/popup-coop-by-sw.https.html
new file mode 100644
index 0000000000..69c2db1ad9
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/popup-coop-by-sw.https.html
@@ -0,0 +1,136 @@
+<meta name="timeout" content="long">
+<meta name="variant" content="?1-4">
+<meta name="variant" content="?5-last">
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src="/common/subset-tests.js"></script>
+<script src="/service-workers/service-worker/resources/test-helpers.sub.js"></script>
+<script src="/common/utils.js"></script>
+<script src="/common/dispatcher/dispatcher.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script>
+
+const executor_path = '/common/dispatcher/executor.html?pipe=';
+const executor_service_worker_path = '/common/dispatcher/executor-service-worker.js?pipe=';
+
+const coop_header = `|header(Cross-Origin-Opener-Policy,same-origin)`;
+const coep_header = `|header(Cross-Origin-Embedder-Policy,require-corp)`;
+
+const https_origin = get_host_info().HTTPS_ORIGIN;
+
+const swap_browsing_context_group = true;
+const keep_browsing_context_group = false;
+
+const opener_basic = "";
+const opener_coi = coop_header + coep_header;
+
+const sw_basic = "";
+const sw_coi = coop_header + coep_header;
+
+const openee_basic = {
+ 'content-type': 'text/html',
+};
+const openee_coi = {
+ 'content-type': 'text/html',
+ 'cross-origin-embedder-policy': 'require-corp',
+ 'cross-origin-opener-policy': 'same-origin',
+};
+
+// A document opens a popup. The popup's document is served from a synthetic
+// response by a ServiceWorker. Check how cross-origin isolation works in this
+// case.
+const popupCoopBySwTest = (
+ description,
+ // Test parameters:
+ opener_headers,
+ openee_headers,
+ sw_headers,
+ // Test expectations:
+ expected_browing_context_group
+) => {
+ subsetTest(promise_test, async test => {
+ const driver_token = token();
+
+ // 1. Create the opener.
+ const opener_token = token();
+ const opener_url = https_origin + executor_path + opener_headers +
+ `&uuid=${opener_token}`;
+ const opener_window = window.open(opener_url);
+ test.add_cleanup(() => opener_window.close());
+
+ // 2. Define the openee's URL as being served by the service worker.
+ const openee_url = https_origin + "/common/dispatcher/proxied?" + token();
+
+ // 3. Register, install and activate a ServiceWorker serving the openee_url.
+ const sw_token = token();
+ const sw_url = https_origin + executor_service_worker_path + sw_headers +
+ `&uuid=${sw_token}`;
+ const sw_scope = openee_url; // One-time scope, because of the token.
+
+ const sw_registration =
+ await service_worker_unregister_and_register(test, sw_url, sw_scope);
+ test.add_cleanup(() => sw_registration.unregister());
+ await wait_for_state(test, sw_registration.installing, 'activated');
+
+ send(sw_token, `
+ fetchHandler = event => {
+ if (!event.request.url.includes("proxied"))
+ return;
+
+ const response = new Response(\`
+ <script src="/common/dispatcher/dispatcher.js"></scr\`+\`ipt>
+ <script>
+ send("${driver_token}", opener ? "opener is set"
+ : "opener is null");
+ </scr\` + \`ipt>
+ \`, {
+ status: 200,
+ headers: ${JSON.stringify(openee_headers)},
+ });
+ event.respondWith(response);
+ }
+
+ await clients.claim();
+
+ send("${driver_token}", serviceWorker.state);
+ `)
+ assert_equals(await receive(driver_token), "activated");
+
+ // 4. The opener opens a popup. Its document is a synthetic response served
+ // from the Service Worker.
+ send(opener_token, `
+ window.open("${openee_url}");
+ `);
+
+ assert_equals(await receive(driver_token),
+ (expected_browing_context_group == swap_browsing_context_group)
+ ? "opener is null"
+ : "opener is set");
+ }, description);
+};
+
+popupCoopBySwTest("opener:basic, openee:basic, sw:basic",
+ opener_basic, openee_basic, sw_basic,
+ keep_browsing_context_group);
+popupCoopBySwTest("opener:basic, openee:basic, sw:coi",
+ opener_basic, openee_basic, sw_coi,
+ keep_browsing_context_group);
+popupCoopBySwTest("opener:basic, openee:coi, sw:basic",
+ opener_basic, openee_coi, sw_basic,
+ swap_browsing_context_group);
+popupCoopBySwTest("opener:basic, openee:coi, sw:coi",
+ opener_basic, openee_coi, sw_coi,
+ swap_browsing_context_group);
+popupCoopBySwTest("opener:coi, openee:basic, sw:basic",
+ opener_coi, openee_basic, sw_basic,
+ swap_browsing_context_group);
+popupCoopBySwTest("opener:coi, openee:basic, sw:coi",
+ opener_coi, openee_basic, sw_coi,
+ swap_browsing_context_group);
+popupCoopBySwTest("opener:coi, openee:coi, sw:basic",
+ opener_coi, openee_coi, sw_basic,
+ keep_browsing_context_group);
+popupCoopBySwTest("opener:coi, openee:coi, sw:coi",
+ opener_coi, openee_coi, sw_coi,
+ keep_browsing_context_group);
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/popup-meta-http-equiv.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/popup-meta-http-equiv.https.html
new file mode 100644
index 0000000000..157f7aef46
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/popup-meta-http-equiv.https.html
@@ -0,0 +1,24 @@
+<!doctype html>
+<meta http-equiv="Cross-Origin-Opener-Policy" content="same-origin"><!-- should not be supported -->
+<meta charset=utf-8>
+<meta name=timeout content=long>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src="/common/dispatcher/dispatcher.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="/common/utils.js"></script>
+<script src="resources/common.js"></script>
+<script src="resources/popup-test.js"></script>
+<script>
+
+[
+ {
+ "title": "popup without coop",
+ "coop": "",
+ "same_origin_opener": "preserved",
+ }
+].forEach(variant => {
+ popup_test(`Same-origin ${variant.title}`, SAME_ORIGIN, variant.coop, variant.same_origin_opener);
+});
+
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/popup-redirect-cache.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/popup-redirect-cache.https.html
new file mode 100644
index 0000000000..6568ac3fdb
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/popup-redirect-cache.https.html
@@ -0,0 +1,90 @@
+<!doctype html>
+<meta charset=utf-8>
+<meta name="timeout" content="long">
+<meta name="variant" content="?0-1">
+<meta name="variant" content="?2-3">
+<meta name="variant" content="?4-5">
+<meta name="variant" content="?6-7">
+<meta name="variant" content="?8-last">
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src="/common/dispatcher/dispatcher.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="/common/subset-tests.js"></script>
+<script src="/common/utils.js"></script>
+<script src="resources/common.js"></script>
+
+<div id=log></div>
+<script>
+
+function url_test_cache(t, url, responseToken, iframeToken, hasOpener) {
+ return new Promise(async (resolve, reject) => {
+ try {
+ await dispatcher_url_test(t, url, responseToken, iframeToken, hasOpener, undefined /* OpenerDomAccess */, resolve);
+ } catch(e) {
+ reject(e);
+ }
+ }).then(() => {
+ return new Promise(async (resolve, reject) => {
+ try {
+ // Test the same url for cache.
+ // Note that at this point the popup from the first
+ // `dispatcher_url_test()` call hasn't been closed yet, but once this
+ // test has finished both will be cleaned up.
+ await dispatcher_url_test(t, url, responseToken, iframeToken, hasOpener, undefined /* OpenerDomAccess */, resolve);
+ } catch(e) {
+ reject(e);
+ }
+ });
+ });
+}
+
+// Redirect from hostA to hostB with same coop and coep.
+// Cache the hostA page if redirectCache is true.
+// Cache the hostB page if destCache is true.
+function coop_redirect_cache_test(t, hostA, hostB, coop, coep, redirectCache, destCache, hasOpener) {
+ let redirectUrl = `${hostA.origin}/html/cross-origin-opener-policy/resources/coop-coep.py`;
+ let redirectCacheString = redirectCache ? "&cache=1" : "";
+ let destCacheString = destCache ? "&cache=1" : "";
+ let responseToken = token();
+ let iframeToken = token();
+ let destUrl = `${hostB.origin}/html/cross-origin-opener-policy/resources/coop-coep.py?coop=${coop}&coep=${coep}${destCacheString}&responseToken=${responseToken}&iframeToken=${iframeToken}`;
+ let url = `${redirectUrl}?coop=${coop}&coep=${coep}${redirectCacheString}&redirect=${encodeURIComponent(destUrl)}`;
+
+ return url_test_cache(t, url, responseToken, iframeToken, hasOpener);
+}
+
+function run_redirect_cache_tests(documentCOOPValueTitle, testArray) {
+ testArray.forEach((test, i) => {
+ // Only run specified variants
+ if (!shouldRunSubTest(i)) {
+ return;
+ }
+
+ promise_test(t => {
+ return coop_redirect_cache_test(t, test[0], test[1], "same-origin", "require-corp", test[2], test[3], test[4]);
+ }, `${documentCOOPValueTitle} document opening popup redirect from ${test[0].origin} to ${test[1].origin} with redirectCache ${test[2]} and destCache ${test[3]}`);
+ });
+}
+
+const tests = [
+ // popup Origin, final Origin, isCacheRedirect, isCacheDestination, hasOpener
+ // Origin A->A->B
+ [SAME_ORIGIN, CROSS_ORIGIN, true, false, false],
+ [SAME_ORIGIN, CROSS_ORIGIN, false, true, false],
+ [SAME_ORIGIN, CROSS_ORIGIN, true, true, false],
+
+ // Origin A->B->B
+ [CROSS_ORIGIN, SAME_ORIGIN, true, false, false],
+ [CROSS_ORIGIN, SAME_ORIGIN, false, true, false],
+ [CROSS_ORIGIN, SAME_ORIGIN, true, true, false],
+
+ // Origin A->B->C
+ [SAME_SITE, CROSS_ORIGIN, true, false, false],
+ [SAME_SITE, CROSS_ORIGIN, false, true, false],
+ [SAME_SITE, CROSS_ORIGIN, true, true, false],
+];
+
+run_redirect_cache_tests("same-origin", tests);
+
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/popup-redirect-cache.https.html.headers b/testing/web-platform/tests/html/cross-origin-opener-policy/popup-redirect-cache.https.html.headers
new file mode 100644
index 0000000000..46ad58d83b
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/popup-redirect-cache.https.html.headers
@@ -0,0 +1 @@
+Cross-Origin-Opener-Policy: same-origin
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/popup-redirect-same-origin-allow-popups.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/popup-redirect-same-origin-allow-popups.https.html
new file mode 100644
index 0000000000..73119a76f8
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/popup-redirect-same-origin-allow-popups.https.html
@@ -0,0 +1,96 @@
+<title>
+ Tests the interaction of COOP same-origin-allow-popups with redirects in a
+ newly opened popup.
+</title>
+<meta charset=utf-8>
+<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="/common/dispatcher/dispatcher.js"></script>
+
+<div id=log></div>
+<script>
+
+const executor_path = "/common/dispatcher/executor.html?pipe=";
+const same_origin = {
+ host: get_host_info().HTTPS_ORIGIN,
+ name: "Same origin"
+};
+const cross_origin = {
+ host: get_host_info().HTTPS_REMOTE_ORIGIN,
+ name: "Cross origin"
+};
+const coep_header = '|header(Cross-Origin-Embedder-Policy,unsafe-none)';
+
+// Tests the interaction of COOP same-origin-allow-popups with redirects in a
+// newly created popup.
+// 1- Creates a page with origin SAME_ORIGIN and COOP same-origin-allow-popups.
+// 2- This page opens a popup.
+// 3- The popup navigates and gets a redirect response with COOP unsafe none
+// and origin either SAME_ORIGIN or CROSS_ORIGIN
+// 4- The popup follows the redirect and ends up on a final page with COOP
+// same-origin-allow-popups and origin SAME_ORIGIN
+// 5- The popup and its opener should no longer be in the same browsing context
+// group (ie the popup doesn't have an opener and the window that opened the
+// popup sees it as closed).
+function redirect_test(popup_redirect_origin) {
+ promise_test(async t => {
+ // Identifies the test window.
+ const this_window_token = token();
+
+ // Identifies the first window that will open the popup. It has COOP
+ // same-origin-allow-popups.
+ const opener_token= token();
+ const same_origin_allow_popups_header =
+ `|header(Cross-Origin-Opener-Policy,same-origin-allow-popups)`;
+ const opener_url = same_origin.host + executor_path +
+ same_origin_allow_popups_header + `&uuid=${opener_token}`;
+
+ // Identifies the popup. It will initial try to navigate to
+ // popup_redirect_origin, which has COOP unsafe-none. The navigation is
+ // then redirected to a final response of SAME_ORIGIN and COOP
+ // same-origin-allow-popups.
+ const popup_token = token();
+ const popup_final_url = same_origin.host + executor_path +
+ same_origin_allow_popups_header + `&uuid=${popup_token}`;
+ const redirect_header = 'status(302)' +
+ `|header(Location,${encodeURIComponent(
+ popup_final_url
+ .replace(/,/g, "\\,")
+ .replace(/\\\\,/g, "\\\\\\,")
+ .replace(/\(/g, "%28")
+ .replace(/\)/g, "%29"))})`;
+ const popup_initial_url = popup_redirect_origin.host + executor_path +
+ redirect_header + `&uuid=${popup_token}`;
+
+ // 1. Create the initial window.
+ let opener_window_proxy = window.open(opener_url);
+ t.add_cleanup(() => send(opener_token, "window.close()"));
+
+ // 2. The initial window opens a popup.
+ send(opener_token, `
+ popup = window.open("${popup_initial_url}");
+ `);
+ t.add_cleanup(() => send(popup_token, "window.close()"));
+
+ // 3. Check the opener status on the popup.
+ send(popup_token, `
+ send("${this_window_token}", window.opener !== null);
+ `);
+ assert_equals(await receive(this_window_token), "false", "opener");
+
+ // 4. Check the status of the popup from the initial window.
+ send(opener_token, `
+ send("${this_window_token}", popup.closed);
+ `);
+ assert_equals(await receive(this_window_token), "true", "popup.closed");
+
+ }, `${popup_redirect_origin.name} popup redirects to same-origin with same-origin-allow-popups`);
+}
+
+redirect_test(same_origin);
+redirect_test(cross_origin);
+
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/popup-same-origin-allow-popups-with-cross-origin.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/popup-same-origin-allow-popups-with-cross-origin.https.html
new file mode 100644
index 0000000000..d025faeb67
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/popup-same-origin-allow-popups-with-cross-origin.https.html
@@ -0,0 +1,58 @@
+<!doctype html>
+<meta charset=utf-8>
+<meta name=timeout content=long>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src="/common/dispatcher/dispatcher.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="/common/utils.js"></script>
+<script src="resources/common.js"></script>
+<script src="resources/popup-test.js"></script>
+<script>
+
+[
+ {
+ "title": "popup with empty coop",
+ "coop": "",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with coop unsafe-none",
+ "coop": "unsafe-none",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with jibberish coop",
+ "coop": "jibberish",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with obsolete coop",
+ "coop": "same-site",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with obsolete coop 2",
+ "coop": "same-site unsafe-allow-outgoing",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with obsolete coop 3",
+ "coop": "same-origin unsafe-allow-outgoing",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with coop same-origin",
+ "coop": "same-origin",
+ "opener": "severed"
+ },
+ {
+ "title": "popup with coop same-origin-allow-popups",
+ "coop": "same-origin-allow-popups",
+ "opener": "severed"
+ }
+].forEach(variant => {
+ popup_test(`Cross-origin ${variant.title}`, CROSS_ORIGIN, { coop : variant.coop }, variant.opener);
+});
+
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/popup-same-origin-allow-popups-with-cross-origin.https.html.headers b/testing/web-platform/tests/html/cross-origin-opener-policy/popup-same-origin-allow-popups-with-cross-origin.https.html.headers
new file mode 100644
index 0000000000..d83ed86fb9
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/popup-same-origin-allow-popups-with-cross-origin.https.html.headers
@@ -0,0 +1 @@
+Cross-Origin-Opener-Policy: same-origin-allow-popups
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/popup-same-origin-allow-popups-with-same-origin.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/popup-same-origin-allow-popups-with-same-origin.https.html
new file mode 100644
index 0000000000..438e424284
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/popup-same-origin-allow-popups-with-same-origin.https.html
@@ -0,0 +1,58 @@
+<!doctype html>
+<meta charset=utf-8>
+<meta name=timeout content=long>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src="/common/dispatcher/dispatcher.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="/common/utils.js"></script>
+<script src="resources/common.js"></script>
+<script src="resources/popup-test.js"></script>
+<script>
+
+[
+ {
+ "title": "popup with empty coop",
+ "coop": "",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with coop unsafe-none",
+ "coop": "unsafe-none",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with jibberish coop",
+ "coop": "jibberish",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with obsolete coop",
+ "coop": "same-site",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with obsolete coop 2",
+ "coop": "same-site unsafe-allow-outgoing",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with obsolete coop 3",
+ "coop": "same-origin unsafe-allow-outgoing",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with coop same-origin",
+ "coop": "same-origin",
+ "opener": "severed"
+ },
+ {
+ "title": "popup with coop same-origin-allow-popups",
+ "coop": "same-origin-allow-popups",
+ "opener": "preserved"
+ }
+].forEach(variant => {
+ popup_test(`Same-origin ${variant.title}`, SAME_ORIGIN, { coop : variant.coop }, variant.opener);
+});
+
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/popup-same-origin-allow-popups-with-same-origin.https.html.headers b/testing/web-platform/tests/html/cross-origin-opener-policy/popup-same-origin-allow-popups-with-same-origin.https.html.headers
new file mode 100644
index 0000000000..d83ed86fb9
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/popup-same-origin-allow-popups-with-same-origin.https.html.headers
@@ -0,0 +1 @@
+Cross-Origin-Opener-Policy: same-origin-allow-popups
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/popup-same-origin-allow-popups-with-same-site.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/popup-same-origin-allow-popups-with-same-site.https.html
new file mode 100644
index 0000000000..d1b6b60d7c
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/popup-same-origin-allow-popups-with-same-site.https.html
@@ -0,0 +1,58 @@
+<!doctype html>
+<meta charset=utf-8>
+<meta name=timeout content=long>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src="/common/dispatcher/dispatcher.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="/common/utils.js"></script>
+<script src="resources/common.js"></script>
+<script src="resources/popup-test.js"></script>
+<script>
+
+[
+ {
+ "title": "popup with empty coop",
+ "coop": "",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with coop unsafe-none",
+ "coop": "unsafe-none",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with jibberish coop",
+ "coop": "jibberish",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with obsolete coop",
+ "coop": "same-site",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with obsolete coop 2",
+ "coop": "same-site unsafe-allow-outgoing",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with obsolete coop 3",
+ "coop": "same-origin unsafe-allow-outgoing",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with coop same-origin",
+ "coop": "same-origin",
+ "opener": "severed"
+ },
+ {
+ "title": "popup with coop same-origin-allow-popups",
+ "coop": "same-origin-allow-popups",
+ "opener": "severed"
+ }
+].forEach(variant => {
+ popup_test(`Same-site ${variant.title}`, SAME_SITE, { coop: variant.coop }, variant.opener);
+});
+
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/popup-same-origin-allow-popups-with-same-site.https.html.headers b/testing/web-platform/tests/html/cross-origin-opener-policy/popup-same-origin-allow-popups-with-same-site.https.html.headers
new file mode 100644
index 0000000000..d83ed86fb9
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/popup-same-origin-allow-popups-with-same-site.https.html.headers
@@ -0,0 +1 @@
+Cross-Origin-Opener-Policy: same-origin-allow-popups
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/popup-same-origin-non-initial-about-blank.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/popup-same-origin-non-initial-about-blank.https.html
new file mode 100644
index 0000000000..2e58ea4553
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/popup-same-origin-non-initial-about-blank.https.html
@@ -0,0 +1,17 @@
+<!doctype html>
+<title>Cross-Origin-Opener-Policy: about:blank</title>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script>
+async_test(t => {
+ const popup = window.open("resources/coop-coep.py?coop=same-origin&coep=&navigate=about:blank");
+ t.add_cleanup(() => popup.close());
+ assert_equals(window, popup.opener);
+
+ popup.onload = t.step_func(() => {
+ assert_true(popup.location.href.endsWith("&navigate=about:blank"));
+ // Use wait_for_callback as about:blank cannot message back.
+ t.step_wait_func_done(() => popup.location.href === "about:blank");
+ });
+}, "Navigating a popup to about:blank");
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/popup-same-origin-non-initial-about-blank.https.html.headers b/testing/web-platform/tests/html/cross-origin-opener-policy/popup-same-origin-non-initial-about-blank.https.html.headers
new file mode 100644
index 0000000000..46ad58d83b
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/popup-same-origin-non-initial-about-blank.https.html.headers
@@ -0,0 +1 @@
+Cross-Origin-Opener-Policy: same-origin
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/popup-same-origin-with-cross-origin.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/popup-same-origin-with-cross-origin.https.html
new file mode 100644
index 0000000000..bd1e6848c4
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/popup-same-origin-with-cross-origin.https.html
@@ -0,0 +1,58 @@
+<!doctype html>
+<meta charset=utf-8>
+<meta name=timeout content=long>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src="/common/dispatcher/dispatcher.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="/common/utils.js"></script>
+<script src="resources/common.js"></script>
+<script src="resources/popup-test.js"></script>
+<script>
+
+[
+ {
+ "title": "popup with empty coop",
+ "coop": "",
+ "opener": "severed"
+ },
+ {
+ "title": "popup with coop unsafe-none",
+ "coop": "unsafe-none",
+ "opener": "severed"
+ },
+ {
+ "title": "popup with jibberish coop",
+ "coop": "jibberish",
+ "opener": "severed"
+ },
+ {
+ "title": "popup with obsolete coop",
+ "coop": "same-site",
+ "opener": "severed"
+ },
+ {
+ "title": "popup with obsolete coop 2",
+ "coop": "same-site unsafe-allow-outgoing",
+ "opener": "severed"
+ },
+ {
+ "title": "popup with obsolete coop 3",
+ "coop": "same-origin unsafe-allow-outgoing",
+ "opener": "severed"
+ },
+ {
+ "title": "popup with coop same-origin",
+ "coop": "same-origin",
+ "opener": "severed"
+ },
+ {
+ "title": "popup with coop same-origin-allow-popups",
+ "coop": "same-origin-allow-popups",
+ "opener": "severed"
+ }
+].forEach(variant => {
+ popup_test(`Cross-origin ${variant.title}`, CROSS_ORIGIN, { coop: variant.coop }, variant.opener);
+});
+
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/popup-same-origin-with-cross-origin.https.html.headers b/testing/web-platform/tests/html/cross-origin-opener-policy/popup-same-origin-with-cross-origin.https.html.headers
new file mode 100644
index 0000000000..46ad58d83b
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/popup-same-origin-with-cross-origin.https.html.headers
@@ -0,0 +1 @@
+Cross-Origin-Opener-Policy: same-origin
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/popup-same-origin-with-same-origin.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/popup-same-origin-with-same-origin.https.html
new file mode 100644
index 0000000000..caf4b173c2
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/popup-same-origin-with-same-origin.https.html
@@ -0,0 +1,58 @@
+<!doctype html>
+<meta charset=utf-8>
+<meta name=timeout content=long>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src="/common/dispatcher/dispatcher.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="/common/utils.js"></script>
+<script src="resources/common.js"></script>
+<script src="resources/popup-test.js"></script>
+<script>
+
+[
+ {
+ "title": "popup with empty coop",
+ "coop": "",
+ "opener": "severed"
+ },
+ {
+ "title": "popup with coop unsafe-none",
+ "coop": "unsafe-none",
+ "opener": "severed"
+ },
+ {
+ "title": "popup with jibberish coop",
+ "coop": "jibberish",
+ "opener": "severed"
+ },
+ {
+ "title": "popup with obsolete coop",
+ "coop": "same-site",
+ "opener": "severed"
+ },
+ {
+ "title": "popup with obsolete coop 2",
+ "coop": "same-site unsafe-allow-outgoing",
+ "opener": "severed"
+ },
+ {
+ "title": "popup with obsolete coop 3",
+ "coop": "same-origin unsafe-allow-outgoing",
+ "opener": "severed"
+ },
+ {
+ "title": "popup with coop same-origin",
+ "coop": "same-origin",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with coop same-origin-allow-popups",
+ "coop": "same-origin-allow-popups",
+ "opener": "severed"
+ }
+].forEach(variant => {
+ popup_test(`Same-origin ${variant.title}`, SAME_ORIGIN, { coop: variant.coop }, variant.opener);
+});
+
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/popup-same-origin-with-same-origin.https.html.headers b/testing/web-platform/tests/html/cross-origin-opener-policy/popup-same-origin-with-same-origin.https.html.headers
new file mode 100644
index 0000000000..46ad58d83b
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/popup-same-origin-with-same-origin.https.html.headers
@@ -0,0 +1 @@
+Cross-Origin-Opener-Policy: same-origin
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/popup-same-origin-with-same-site.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/popup-same-origin-with-same-site.https.html
new file mode 100644
index 0000000000..93ba9c9888
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/popup-same-origin-with-same-site.https.html
@@ -0,0 +1,58 @@
+<!doctype html>
+<meta charset=utf-8>
+<meta name=timeout content=long>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src="/common/dispatcher/dispatcher.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="/common/utils.js"></script>
+<script src="resources/common.js"></script>
+<script src="resources/popup-test.js"></script>
+<script>
+
+[
+ {
+ "title": "popup with empty coop",
+ "coop": "",
+ "opener": "severed"
+ },
+ {
+ "title": "popup with coop unsafe-none",
+ "coop": "unsafe-none",
+ "opener": "severed"
+ },
+ {
+ "title": "popup with jibberish coop",
+ "coop": "jibberish",
+ "opener": "severed"
+ },
+ {
+ "title": "popup with obsolete coop",
+ "coop": "same-site",
+ "opener": "severed"
+ },
+ {
+ "title": "popup with obsolete coop 2",
+ "coop": "same-site unsafe-allow-outgoing",
+ "opener": "severed"
+ },
+ {
+ "title": "popup with obsolete coop 3",
+ "coop": "same-origin unsafe-allow-outgoing",
+ "opener": "severed"
+ },
+ {
+ "title": "popup with coop same-origin",
+ "coop": "same-origin",
+ "opener": "severed"
+ },
+ {
+ "title": "popup with coop same-origin-allow-popups",
+ "coop": "same-origin-allow-popups",
+ "opener": "severed"
+ }
+].forEach(variant => {
+ popup_test(`Same-site ${variant.title}`, SAME_SITE, { coop: variant.coop }, variant.opener);
+});
+
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/popup-same-origin-with-same-site.https.html.headers b/testing/web-platform/tests/html/cross-origin-opener-policy/popup-same-origin-with-same-site.https.html.headers
new file mode 100644
index 0000000000..46ad58d83b
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/popup-same-origin-with-same-site.https.html.headers
@@ -0,0 +1 @@
+Cross-Origin-Opener-Policy: same-origin
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/popup-unsafe-none-with-cross-origin.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/popup-unsafe-none-with-cross-origin.https.html
new file mode 100644
index 0000000000..31ac569491
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/popup-unsafe-none-with-cross-origin.https.html
@@ -0,0 +1,58 @@
+<!doctype html>
+<meta charset=utf-8>
+<meta name=timeout content=long>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src="/common/dispatcher/dispatcher.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="/common/utils.js"></script>
+<script src="resources/common.js"></script>
+<script src="resources/popup-test.js"></script>
+<script>
+
+[
+ {
+ "title": "popup with empty coop",
+ "coop": "",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with coop unsafe-none",
+ "coop": "unsafe-none",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with jibberish coop",
+ "coop": "jibberish",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with obsolete coop",
+ "coop": "same-site",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with obsolete coop 2",
+ "coop": "same-site unsafe-allow-outgoing",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with obsolete coop 3",
+ "coop": "same-origin unsafe-allow-outgoing",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with coop same-origin",
+ "coop": "same-origin",
+ "opener": "severed"
+ },
+ {
+ "title": "popup with coop same-origin-allow-popups",
+ "coop": "same-origin-allow-popups",
+ "opener": "severed"
+ }
+].forEach(variant => {
+ popup_test(`Cross-origin ${variant.title}`, CROSS_ORIGIN, { coop: variant.coop }, variant.opener);
+});
+
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/popup-unsafe-none-with-cross-origin.https.html.headers b/testing/web-platform/tests/html/cross-origin-opener-policy/popup-unsafe-none-with-cross-origin.https.html.headers
new file mode 100644
index 0000000000..073ce7adfb
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/popup-unsafe-none-with-cross-origin.https.html.headers
@@ -0,0 +1 @@
+Cross-Origin-Opener-Policy: unsafe-none
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/popup-unsafe-none-with-same-origin.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/popup-unsafe-none-with-same-origin.https.html
new file mode 100644
index 0000000000..18f87048c3
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/popup-unsafe-none-with-same-origin.https.html
@@ -0,0 +1,58 @@
+<!doctype html>
+<meta charset=utf-8>
+<meta name=timeout content=long>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src="/common/dispatcher/dispatcher.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="/common/utils.js"></script>
+<script src="resources/common.js"></script>
+<script src="resources/popup-test.js"></script>
+<script>
+
+[
+ {
+ "title": "popup with empty coop",
+ "coop": "",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with coop unsafe-none",
+ "coop": "unsafe-none",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with jibberish coop",
+ "coop": "jibberish",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with obsolete coop",
+ "coop": "same-site",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with obsolete coop 2",
+ "coop": "same-site unsafe-allow-outgoing",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with obsolete coop 3",
+ "coop": "same-origin unsafe-allow-outgoing",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with coop same-origin",
+ "coop": "same-origin",
+ "opener": "severed"
+ },
+ {
+ "title": "popup with coop same-origin-allow-popups",
+ "coop": "same-origin-allow-popups",
+ "opener": "severed"
+ }
+].forEach(variant => {
+ popup_test(`Same-origin ${variant.title}`, SAME_ORIGIN, { coop: variant.coop }, variant.opener);
+});
+
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/popup-unsafe-none-with-same-origin.https.html.headers b/testing/web-platform/tests/html/cross-origin-opener-policy/popup-unsafe-none-with-same-origin.https.html.headers
new file mode 100644
index 0000000000..073ce7adfb
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/popup-unsafe-none-with-same-origin.https.html.headers
@@ -0,0 +1 @@
+Cross-Origin-Opener-Policy: unsafe-none
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/popup-unsafe-none-with-same-site.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/popup-unsafe-none-with-same-site.https.html
new file mode 100644
index 0000000000..d1b6b60d7c
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/popup-unsafe-none-with-same-site.https.html
@@ -0,0 +1,58 @@
+<!doctype html>
+<meta charset=utf-8>
+<meta name=timeout content=long>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src="/common/dispatcher/dispatcher.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="/common/utils.js"></script>
+<script src="resources/common.js"></script>
+<script src="resources/popup-test.js"></script>
+<script>
+
+[
+ {
+ "title": "popup with empty coop",
+ "coop": "",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with coop unsafe-none",
+ "coop": "unsafe-none",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with jibberish coop",
+ "coop": "jibberish",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with obsolete coop",
+ "coop": "same-site",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with obsolete coop 2",
+ "coop": "same-site unsafe-allow-outgoing",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with obsolete coop 3",
+ "coop": "same-origin unsafe-allow-outgoing",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with coop same-origin",
+ "coop": "same-origin",
+ "opener": "severed"
+ },
+ {
+ "title": "popup with coop same-origin-allow-popups",
+ "coop": "same-origin-allow-popups",
+ "opener": "severed"
+ }
+].forEach(variant => {
+ popup_test(`Same-site ${variant.title}`, SAME_SITE, { coop: variant.coop }, variant.opener);
+});
+
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/popup-unsafe-none-with-same-site.https.html.headers b/testing/web-platform/tests/html/cross-origin-opener-policy/popup-unsafe-none-with-same-site.https.html.headers
new file mode 100644
index 0000000000..073ce7adfb
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/popup-unsafe-none-with-same-site.https.html.headers
@@ -0,0 +1 @@
+Cross-Origin-Opener-Policy: unsafe-none
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/popup-unspecified-with-cross-origin.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/popup-unspecified-with-cross-origin.https.html
new file mode 100644
index 0000000000..31ac569491
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/popup-unspecified-with-cross-origin.https.html
@@ -0,0 +1,58 @@
+<!doctype html>
+<meta charset=utf-8>
+<meta name=timeout content=long>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src="/common/dispatcher/dispatcher.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="/common/utils.js"></script>
+<script src="resources/common.js"></script>
+<script src="resources/popup-test.js"></script>
+<script>
+
+[
+ {
+ "title": "popup with empty coop",
+ "coop": "",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with coop unsafe-none",
+ "coop": "unsafe-none",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with jibberish coop",
+ "coop": "jibberish",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with obsolete coop",
+ "coop": "same-site",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with obsolete coop 2",
+ "coop": "same-site unsafe-allow-outgoing",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with obsolete coop 3",
+ "coop": "same-origin unsafe-allow-outgoing",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with coop same-origin",
+ "coop": "same-origin",
+ "opener": "severed"
+ },
+ {
+ "title": "popup with coop same-origin-allow-popups",
+ "coop": "same-origin-allow-popups",
+ "opener": "severed"
+ }
+].forEach(variant => {
+ popup_test(`Cross-origin ${variant.title}`, CROSS_ORIGIN, { coop: variant.coop }, variant.opener);
+});
+
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/popup-unspecified-with-same-origin.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/popup-unspecified-with-same-origin.https.html
new file mode 100644
index 0000000000..18f87048c3
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/popup-unspecified-with-same-origin.https.html
@@ -0,0 +1,58 @@
+<!doctype html>
+<meta charset=utf-8>
+<meta name=timeout content=long>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src="/common/dispatcher/dispatcher.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="/common/utils.js"></script>
+<script src="resources/common.js"></script>
+<script src="resources/popup-test.js"></script>
+<script>
+
+[
+ {
+ "title": "popup with empty coop",
+ "coop": "",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with coop unsafe-none",
+ "coop": "unsafe-none",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with jibberish coop",
+ "coop": "jibberish",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with obsolete coop",
+ "coop": "same-site",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with obsolete coop 2",
+ "coop": "same-site unsafe-allow-outgoing",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with obsolete coop 3",
+ "coop": "same-origin unsafe-allow-outgoing",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with coop same-origin",
+ "coop": "same-origin",
+ "opener": "severed"
+ },
+ {
+ "title": "popup with coop same-origin-allow-popups",
+ "coop": "same-origin-allow-popups",
+ "opener": "severed"
+ }
+].forEach(variant => {
+ popup_test(`Same-origin ${variant.title}`, SAME_ORIGIN, { coop: variant.coop }, variant.opener);
+});
+
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/popup-unspecified-with-same-site.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/popup-unspecified-with-same-site.https.html
new file mode 100644
index 0000000000..d1b6b60d7c
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/popup-unspecified-with-same-site.https.html
@@ -0,0 +1,58 @@
+<!doctype html>
+<meta charset=utf-8>
+<meta name=timeout content=long>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src="/common/dispatcher/dispatcher.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="/common/utils.js"></script>
+<script src="resources/common.js"></script>
+<script src="resources/popup-test.js"></script>
+<script>
+
+[
+ {
+ "title": "popup with empty coop",
+ "coop": "",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with coop unsafe-none",
+ "coop": "unsafe-none",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with jibberish coop",
+ "coop": "jibberish",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with obsolete coop",
+ "coop": "same-site",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with obsolete coop 2",
+ "coop": "same-site unsafe-allow-outgoing",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with obsolete coop 3",
+ "coop": "same-origin unsafe-allow-outgoing",
+ "opener": "preserved"
+ },
+ {
+ "title": "popup with coop same-origin",
+ "coop": "same-origin",
+ "opener": "severed"
+ },
+ {
+ "title": "popup with coop same-origin-allow-popups",
+ "coop": "same-origin-allow-popups",
+ "opener": "severed"
+ }
+].forEach(variant => {
+ popup_test(`Same-site ${variant.title}`, SAME_SITE, { coop: variant.coop }, variant.opener);
+});
+
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/popup-with-structured-header.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/popup-with-structured-header.https.html
new file mode 100644
index 0000000000..e337e69cc0
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/popup-with-structured-header.https.html
@@ -0,0 +1,33 @@
+<!doctype html>
+<meta charset=utf-8>
+<meta name=timeout content=long>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src="/common/dispatcher/dispatcher.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="/common/utils.js"></script>
+<script src="resources/common.js"></script>
+<script src="resources/popup-test.js"></script>
+<script>
+
+[
+ {
+ "title": "popup with structured coop unsafe-none",
+ "coop": "unsafe-none; report-to=endpoint",
+ "opener": "severed",
+ },
+ {
+ "title": "popup with structured coop same-origin",
+ "coop": "same-origin; report-to=endpoint",
+ "opener": "preserved",
+ },
+ {
+ "title": "popup with structured coop same-origin-allow-popups",
+ "coop": "same-origin-allow-popups; report-to=endpoint",
+ "opener": "severed",
+ }
+].forEach(variant => {
+ popup_test(`Same-origin ${variant.title}`, SAME_ORIGIN, { coop: variant.coop }, variant.opener);
+});
+
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/popup-with-structured-header.https.html.headers b/testing/web-platform/tests/html/cross-origin-opener-policy/popup-with-structured-header.https.html.headers
new file mode 100644
index 0000000000..46ad58d83b
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/popup-with-structured-header.https.html.headers
@@ -0,0 +1 @@
+Cross-Origin-Opener-Policy: same-origin
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/META.yml b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/META.yml
new file mode 100644
index 0000000000..0db28208a6
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/META.yml
@@ -0,0 +1,6 @@
+suggested_reviewers:
+ - ArthurSonzogni
+ - ParisMeuleman
+ - camillelamy
+ - hemeryar
+ - mikewest
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/access-from-coop-page-to-openee_coop-ro.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/access-from-coop-page-to-openee_coop-ro.https.html
new file mode 100644
index 0000000000..a7e83cc0d9
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/access-from-coop-page-to-openee_coop-ro.https.html
@@ -0,0 +1,82 @@
+<title>
+ COOP reports are to the opener when the opener used COOP-RO+COEP and then it
+ tries to access a same-origin openee.
+</title>
+<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="/common/dispatcher/dispatcher.js"></script>
+<script src="/html/cross-origin-opener-policy/resources/common.js"></script>
+<script src="/html/cross-origin-opener-policy/reporting/resources/reporting-common.js"></script>
+<script src="/html/cross-origin-opener-policy/reporting/resources/try-access.js"></script>
+<script>
+
+const directory = "/html/cross-origin-opener-policy";
+const redirect_path = directory + "/resources/redirect.py?";
+const same_origin = get_host_info().HTTPS_ORIGIN;
+
+let runTest = (openee_redirect, name) => promise_test(async t => {
+ // The test window.
+ const this_window_token = token();
+
+ // The "opener" window. This has COOP and a reporter.
+ const opener_report_token= token();
+ const opener_token = token();
+ const opener_reportTo = reportToHeaders(opener_report_token);
+ const opener_url = same_origin + executor_path + opener_reportTo.header +
+ opener_reportTo.coopReportOnlySameOriginHeader + coep_header +
+ `&uuid=${opener_token}`;
+
+ // The "openee" window. This is same origin with the "opener".
+ const openee_report_token = token();
+ const openee_token = token();
+ const openee_url = same_origin + executor_path + `&uuid=${openee_token}`;
+ const openee_redirect_url = same_origin + redirect_path + openee_url
+ const openee_requested_url = openee_redirect ? openee_redirect_url
+ : openee_url;
+
+ // 1. Create the opener window.
+ let opener_window_proxy = window.open(opener_url);
+ t.add_cleanup(() => send(opener_token, "window.close()"));
+
+ // 2. The opener opens it openee.
+ send(opener_token, `
+ openee = window.open("${openee_requested_url}");
+ send("${this_window_token}", "ACK 1");
+ `);
+ assert_equals("ACK 1", await receive(this_window_token));
+ t.add_cleanup(() => send(openee_token, "window.close()"));
+
+ // 3. Ensure the openee's document to be loaded.
+ send(openee_token, `
+ send("${this_window_token}", "ACK 2");
+ `);
+ assert_equals("ACK 2", await receive(this_window_token));
+
+ // 4. The opener tries to access its openee.
+ send(opener_token, addScriptAndTriggerOnload(
+ directory + "/reporting/resources/try-access.js",
+ "tryAccess(openee);")
+ );
+ // 5. Check a report sent to the opener.
+ let report =
+ await receiveReport(opener_report_token, "access-from-coop-page-to-openee")
+ assert_equals(report.type, "coop");
+ assert_equals(report.url, opener_url.replace(/"/g, '%22'));
+ assert_equals(report.body.disposition, "reporting");
+ assert_equals(report.body.effectivePolicy, "same-origin-plus-coep");
+ assert_equals(report.body.property, "blur");
+ assert_source_location_found(report);
+ assert_equals(report.body.openerURL, undefined);
+ assert_equals(report.body.openeeURL, openee_url);
+ assert_equals(report.body.otherDocumentURL, undefined);
+ assert_equals(report.body.referrer, undefined);
+ assert_equals(report.body.initialPopupURL, openee_requested_url);
+}, name);
+
+runTest(false, "access-from-coop-page-to-openee, same-origin");
+runTest(true , "access-from-coop-page-to-openee, same-origin + redirect");
+
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/access-from-coop-page-to-openee_coop-ro_cross-origin.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/access-from-coop-page-to-openee_coop-ro_cross-origin.https.html
new file mode 100644
index 0000000000..fe72a2299f
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/access-from-coop-page-to-openee_coop-ro_cross-origin.https.html
@@ -0,0 +1,85 @@
+<title>
+ COOP reports are to the opener when the opener used COOP-RO+COEP and then it
+ tries to access a cross-origin openee.
+</title>
+<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="/common/dispatcher/dispatcher.js"></script>
+<script src="/html/cross-origin-opener-policy/resources/common.js"></script>
+<script src="/html/cross-origin-opener-policy/reporting/resources/reporting-common.js"></script>
+<script src="/html/cross-origin-opener-policy/reporting/resources/try-access.js"></script>
+<script>
+
+const directory = "/html/cross-origin-opener-policy";
+const redirect_path = directory + "/resources/redirect.py?";
+const same_origin = get_host_info().HTTPS_ORIGIN;
+const cross_origin = get_host_info().HTTPS_REMOTE_ORIGIN;
+
+let runTest = (openee_redirect, name) => promise_test(async t => {
+ // The test window.
+ const this_window_token = token();
+
+ // The "opener" window. This has COOP and a reporter.
+ const opener_report_token= token();
+ const opener_token = token();
+ const opener_reportTo = reportToHeaders(opener_report_token);
+ const opener_url = same_origin + executor_path + opener_reportTo.header +
+ opener_reportTo.coopReportOnlySameOriginHeader + coep_header +
+ `&uuid=${opener_token}`;
+
+ // The "openee" window. This is cross origin with the "opener".
+ const openee_report_token= token();
+ const openee_token = token();
+ const openee_url = cross_origin + executor_path + `&uuid=${openee_token}`;
+ const openee_redirect_url = same_origin + redirect_path + openee_url
+ const openee_requested_url = openee_redirect ? openee_redirect_url
+ : openee_url;
+
+ // 1. Create the opener window.
+ let opener_window_proxy = window.open(opener_url);
+ t.add_cleanup(() => send(opener_token, "window.close()"));
+
+ // 2. The opener opens it openee.
+ send(opener_token, `
+ openee = window.open("${openee_requested_url}");
+ send("${this_window_token}", "ACK 1");
+ `);
+ assert_equals("ACK 1", await receive(this_window_token));
+ t.add_cleanup(() => send(openee_token, "window.close()"));
+
+ // 3. Ensure the openee's document to be loaded.
+ send(openee_token, `
+ send("${this_window_token}", "ACK 2");
+ `);
+ assert_equals("ACK 2", await receive(this_window_token));
+
+ // 4. The opener tries to access its openee.
+ send(opener_token, addScriptAndTriggerOnload(
+ directory + "/reporting/resources/try-access.js",
+ "tryAccess(openee);")
+ );
+
+
+ // 5. Check a report sent to the opener.
+ let report =
+ await receiveReport(opener_report_token, "access-from-coop-page-to-openee")
+ assert_equals(report.type, "coop");
+ assert_equals(report.url, opener_url.replace(/"/g, '%22'));
+ assert_equals(report.body.disposition, "reporting");
+ assert_equals(report.body.effectivePolicy, "same-origin-plus-coep");
+ assert_equals(report.body.property, "blur");
+ assert_source_location_found(report);
+ assert_equals(report.body.openerURL, undefined);
+ assert_equals(report.body.openeeURL, "");
+ assert_equals(report.body.otherDocumentURL, undefined);
+ assert_equals(report.body.referrer, undefined);
+ assert_equals(report.body.initialPopupURL, openee_requested_url);
+}, name);
+
+runTest(false, "access-from-coop-page-to-openee, cross-origin");
+runTest(true , "access-from-coop-page-to-openee, cross-origin + redirect");
+
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/access-from-coop-page-to-opener_coop-ro.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/access-from-coop-page-to-opener_coop-ro.https.html
new file mode 100644
index 0000000000..005339a06e
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/access-from-coop-page-to-opener_coop-ro.https.html
@@ -0,0 +1,63 @@
+<title>
+ COOP reports are sent when the openee used COOP-RO+COEP and then tries to
+ access its same-origin opener.
+</title>
+<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="/common/dispatcher/dispatcher.js"></script>
+<script src="/html/cross-origin-opener-policy/resources/common.js"></script>
+<script src="/html/cross-origin-opener-policy/reporting/resources/reporting-common.js"></script>
+<script src="/html/cross-origin-opener-policy/reporting/resources/try-access.js"></script>
+<script>
+
+const directory = "/html/cross-origin-opener-policy";
+const redirect_path = directory + "/resources/redirect.py?";
+const same_origin = get_host_info().HTTPS_ORIGIN;
+
+let runTest = (openee_redirect, name) => promise_test(async t => {
+ const report_token = token();
+ const openee_token = token();
+
+ const opener_url = location.href;
+
+ const reportTo = reportToHeaders(report_token);
+ const openee_url = same_origin + executor_path +
+ reportTo.header + reportTo.coopReportOnlySameOriginHeader + coep_header +
+ `&uuid=${openee_token}`;
+ const openee_redirect_url = same_origin + redirect_path + openee_url
+ const openee_requested_url = openee_redirect ? openee_redirect_url
+ : openee_url;
+
+ const openee = window.open(openee_requested_url);
+ t.add_cleanup(() => send(openee_token, "window.close()"))
+
+ // 1. Try to access the opener. A report is sent, because of COOP-RO+COEP.
+
+ send(openee_token, addScriptAndTriggerOnload(
+ directory + "/reporting/resources/try-access.js",
+ "tryAccess(opener);")
+ );
+
+ // 2. Check a report is sent to the openee.
+ let report =
+ await receiveReport(report_token, "access-from-coop-page-to-opener")
+ assert_equals(report.type, "coop");
+ assert_equals(report.url, openee_url.replace(/"/g, '%22'));
+ assert_equals(report.body.disposition, "reporting");
+ assert_equals(report.body.effectivePolicy, "same-origin-plus-coep");
+ assert_equals(report.body.property, "blur");
+ assert_source_location_found(report);
+ assert_equals(report.body.openerURL, opener_url);
+ assert_equals(report.body.openeeURL, undefined);
+ assert_equals(report.body.otherDocumentURL, undefined);
+ assert_equals(report.body.referrer, opener_url);
+ assert_equals(report.body.initialPopupURL, undefined);
+}, name);
+
+runTest(false, "access-from-coop-page-to-opener, same-origin");
+runTest(true , "access-from-coop-page-to-opener, same-origin + redirect");
+
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/access-from-coop-page-to-opener_coop-ro_cross-origin.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/access-from-coop-page-to-opener_coop-ro_cross-origin.https.html
new file mode 100644
index 0000000000..eedfaa557f
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/access-from-coop-page-to-opener_coop-ro_cross-origin.https.html
@@ -0,0 +1,63 @@
+<title>
+ COOP reports are sent when the openee used COOP-RO+COEP and then tries to
+ access its cross-origin opener.
+</title>
+<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="/common/dispatcher/dispatcher.js"></script>
+<script src="/html/cross-origin-opener-policy/resources/common.js"></script>
+<script src="/html/cross-origin-opener-policy/reporting/resources/reporting-common.js"></script>
+<script src="/html/cross-origin-opener-policy/reporting/resources/try-access.js"></script>
+<script>
+
+const directory = "/html/cross-origin-opener-policy";
+const redirect_path = directory + "/resources/redirect.py?";
+const same_origin = get_host_info().HTTPS_ORIGIN;
+const cross_origin = get_host_info().HTTPS_REMOTE_ORIGIN;
+
+let runTest = (openee_redirect, name) => promise_test(async t => {
+ const report_token = token();
+ const openee_token = token();
+
+ const opener_origin = location.origin + '/';
+
+ const reportTo = reportToHeaders(report_token);
+ const openee_url = cross_origin + executor_path +
+ reportTo.header + reportTo.coopReportOnlySameOriginHeader + coep_header +
+ `&uuid=${openee_token}`;
+ const openee_redirect_url = same_origin + redirect_path + openee_url
+ const openee_requested_url = openee_redirect ? openee_redirect_url
+ : openee_url;
+
+ const openee = window.open(openee_requested_url);
+ t.add_cleanup(() => send(openee_token, "window.close()"))
+
+ // 1. Try to access the opener. A report is sent, because of COOP-RO+COEP.
+ send(openee_token, addScriptAndTriggerOnload(
+ directory + "/reporting/resources/try-access.js",
+ "tryAccess(opener);")
+ );
+
+ // 2. Check a report is sent to the openee.
+ let report =
+ await receiveReport(report_token, "access-from-coop-page-to-opener")
+ assert_equals(report.type, "coop");
+ assert_equals(report.url, openee_url.replace(/"/g, '%22'));
+ assert_equals(report.body.disposition, "reporting");
+ assert_equals(report.body.effectivePolicy, "same-origin-plus-coep");
+ assert_equals(report.body.property, "blur");
+ assert_source_location_found(report);
+ assert_equals(report.body.openerURL, "");
+ assert_equals(report.body.openeeURL, undefined);
+ assert_equals(report.body.otherDocumentURL, undefined);
+ assert_equals(report.body.referrer, opener_origin);
+ assert_equals(report.body.initialPopupURL, undefined);
+}, name);
+
+runTest(false, "access-from-coop-page-to-opener, cross-origin");
+runTest(true , "access-from-coop-page-to-opener, cross-origin + redirect");
+
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/access-from-coop-page-to-other_coop-ro.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/access-from-coop-page-to-other_coop-ro.https.html
new file mode 100644
index 0000000000..90df0e4e99
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/access-from-coop-page-to-other_coop-ro.https.html
@@ -0,0 +1,92 @@
+<title>
+ One window accesses a second one. They are aren't related by an opener/openee
+ relationship. The first window has set
+ Cross-Origin-Opener-Policy-Report-Only:same-origin, so it receives a
+ "access-from-coop-page-to-other" report.
+</title>
+<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="/common/dispatcher/dispatcher.js"></script>
+<script src="/html/cross-origin-opener-policy/resources/common.js"></script>
+<script src="/html/cross-origin-opener-policy/reporting/resources/reporting-common.js"></script>
+<script src="/html/cross-origin-opener-policy/reporting/resources/try-access.js"></script>
+<script>
+
+const directory = "/html/cross-origin-opener-policy";
+const same_origin = get_host_info().HTTPS_ORIGIN;
+
+let escapeComma = url => url.replace(/,/g, '\\,');
+
+promise_test(async t => {
+ const report_token= token();
+ const report_to = reportToHeaders(report_token);
+
+ // The test window.
+ const this_window_token = token();
+
+ // The "opener" window. With COOP:same-origin + reporter.
+ const opener_token = token();
+ const opener_url = same_origin + executor_path + report_to.header +
+ report_to.coopReportOnlySameOriginHeader + coep_header +
+ `&uuid=${opener_token}`;
+
+ // The "openee" window. With COOP:same-origin + reporter.
+ const openee_token = token();
+ const openee_url = same_origin + executor_path + report_to.header +
+ report_to.coopReportOnlySameOriginHeader + coep_header +
+ `&uuid=${openee_token}`;
+
+ // The "other" window.
+ const other_token = token();
+ const other_url = same_origin + executor_path + report_to.header +
+ `&uuid=${other_token}`;
+
+ t.add_cleanup(() => {
+ send(opener_token, "window.close()")
+ send(openee_token, "window.close()")
+ send(other_token, "window.close()")
+ })
+
+ // 1. Create the "opener" window.
+ let opener_window_proxy = window.open(opener_url);
+
+ // 2. Create the "openee" window.
+ send(opener_token, `
+ window.openee = window.open('${escapeComma(openee_url)}');
+ `);
+
+ // 3. Create the "other" window.
+ send(openee_token, `
+ window.other = window.open('${escapeComma(other_url)}');
+ `);
+
+ // 4. Wait for "other" to load its document.
+ send(other_token, `send('${this_window_token}', "Loaded");`);
+ assert_equals(await receive(this_window_token), "Loaded");
+
+ // 5. "opener" accesses "other" window, through "openee".
+ send(opener_token, addScriptAndTriggerOnload(
+ directory + "/reporting/resources/try-access.js",
+ "tryAccess(openee.other);")
+ );
+
+ // 6. Check a report is sent to the openee.
+ let report =
+ await receiveReport(report_token, "access-from-coop-page-to-other")
+ assert_equals(report.type, "coop");
+ assert_equals(report.url, opener_url.replace(/"/g, '%22'));
+ assert_equals(report.body.disposition, "reporting");
+ assert_equals(report.body.effectivePolicy, "same-origin-plus-coep");
+ assert_equals(report.body.property, "blur");
+ assert_source_location_found(report);
+ assert_equals(report.body.openerURL, undefined);
+ assert_equals(report.body.openeeURL, undefined);
+ assert_equals(report.body.otherDocumentURL, other_url.replace(/"/g, '%22'));
+ assert_equals(report.body.referrer, undefined);
+ assert_equals(report.body.initialPopupURL, undefined);
+}, "access-from-coop-page-to-other (COOP-RO)");
+
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/access-from-coop-page-to-other_coop-ro_cross-origin.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/access-from-coop-page-to-other_coop-ro_cross-origin.https.html
new file mode 100644
index 0000000000..f0d60c2531
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/access-from-coop-page-to-other_coop-ro_cross-origin.https.html
@@ -0,0 +1,93 @@
+<title>
+ One window accesses a second one. They are aren't related by an opener/openee
+ relationship. The first window has set
+ Cross-Origin-Opener-Policy-Report-Only:same-origin, so it receives a
+ "access-from-coop-page-to-other" report.
+</title>
+<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="/common/dispatcher/dispatcher.js"></script>
+<script src="/html/cross-origin-opener-policy/resources/common.js"></script>
+<script src="/html/cross-origin-opener-policy/reporting/resources/reporting-common.js"></script>
+<script src="/html/cross-origin-opener-policy/reporting/resources/try-access.js"></script>
+<script>
+
+const directory = "/html/cross-origin-opener-policy";
+const same_origin= get_host_info().HTTPS_ORIGIN;
+const cross_origin= get_host_info().HTTPS_REMOTE_ORIGIN;
+
+let escapeComma = url => url.replace(/,/g, '\\,');
+
+promise_test(async t => {
+ const report_token= token();
+ const report_to = reportToHeaders(report_token);
+
+ // The test window.
+ const this_window_token = token();
+
+ // The "opener" window. With COOP:same-origin + reporter.
+ const opener_token = token();
+ const opener_url = same_origin + executor_path + report_to.header +
+ report_to.coopReportOnlySameOriginHeader + coep_header +
+ `&uuid=${opener_token}`;
+
+ // The "openee" window. With COOP:same-origin + reporter.
+ const openee_token = token();
+ const openee_url = same_origin + executor_path + report_to.header +
+ report_to.coopReportOnlySameOriginHeader + coep_header +
+ `&uuid=${openee_token}`;
+
+ // The "other" window.
+ const other_token = token();
+ const other_url = cross_origin + executor_path + report_to.header +
+ `&uuid=${other_token}`;
+
+ t.add_cleanup(() => {
+ send(opener_token, "window.close()")
+ send(openee_token, "window.close()")
+ send(other_token, "window.close()")
+ })
+
+ // 1. Create the "opener" window.
+ let opener_window_proxy = window.open(opener_url);
+
+ // 2. Create the "openee" window.
+ send(opener_token, `
+ window.openee = window.open('${escapeComma(openee_url)}');
+ `);
+
+ // 3. Create the "other" window.
+ send(openee_token, `
+ window.other = window.open('${escapeComma(other_url)}');
+ `);
+
+ // 4. Wait for "other" to load its document.
+ send(other_token, `send('${this_window_token}', "Loaded");`);
+ assert_equals(await receive(this_window_token), "Loaded");
+
+ // 5. "opener" accesses "other" window, through "openee".
+
+ send(opener_token, addScriptAndTriggerOnload(
+ directory + "/reporting/resources/try-access.js",
+ "tryAccess(openee.other);")
+ );
+
+ // 6. Check a report is sent to the openee.
+ let report =
+ await receiveReport(report_token, "access-from-coop-page-to-other")
+ assert_equals(report.type, "coop");
+ assert_equals(report.url, opener_url.replace(/"/g, '%22'));
+ assert_equals(report.body.disposition, "reporting");
+ assert_equals(report.body.effectivePolicy, "same-origin-plus-coep");
+ assert_equals(report.body.property, "blur");
+ assert_source_location_found(report);
+ assert_equals(report.body.openerURL, undefined);
+ assert_equals(report.body.openeeURL, undefined);
+ assert_equals(report.body.otherDocumentURL, "");
+ assert_equals(report.body.referrer, undefined);
+}, "access-from-coop-page-to-other (COOP-RO)");
+
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/access-to-coop-page-from-openee_coop-ro.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/access-to-coop-page-from-openee_coop-ro.https.html
new file mode 100644
index 0000000000..9f0a8821a4
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/access-to-coop-page-from-openee_coop-ro.https.html
@@ -0,0 +1,77 @@
+<title>
+ COOP reports are to the opener when the opener used COOP-RO+COEP and then its
+ same-origin openee tries to access it.
+</title>
+<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="/common/dispatcher/dispatcher.js"></script>
+<script src="/html/cross-origin-opener-policy/resources/common.js"></script>
+<script src="/html/cross-origin-opener-policy/reporting/resources/reporting-common.js"></script>
+<script src="/html/cross-origin-opener-policy/reporting/resources/try-access.js"></script>
+<script>
+
+const directory = "/html/cross-origin-opener-policy";
+const redirect_path = directory + "/resources/redirect.py?";
+const same_origin = get_host_info().HTTPS_ORIGIN;
+
+let runTest = (openee_redirect, name) => promise_test(async t => {
+ // The test window.
+ const this_window_token = token();
+
+ // The "opener" window. This has COOP and a reporter.
+ const opener_report_token= token();
+ const opener_token = token();
+ const opener_reportTo = reportToHeaders(opener_report_token);
+ const opener_url = same_origin + executor_path + opener_reportTo.header +
+ opener_reportTo.coopReportOnlySameOriginHeader + coep_header +
+ `&uuid=${opener_token}`;
+
+ // The "openee" window. This is same origin with the "opener".
+ const openee_report_token= token();
+ const openee_token = token();
+ const openee_url = same_origin + executor_path + `&uuid=${openee_token}`;
+ const openee_redirect_url = same_origin + redirect_path + openee_url
+ const openee_requested_url = openee_redirect ? openee_redirect_url
+ : openee_url;
+
+ // 1. Create the opener window.
+ let opener_window_proxy = window.open(opener_url);
+ t.add_cleanup(() => send(opener_token, "window.close()"));
+
+ // 2. The opener opens its openee.
+ send(opener_token, `
+ openee = window.open("${openee_requested_url}");
+ send("${this_window_token}", "ACK 1");
+ `);
+ assert_equals("ACK 1", await receive(this_window_token));
+ t.add_cleanup(() => send(openee_token, "window.close()"));
+
+ // 3. The openee tries to access its opener.
+ send(openee_token, addScriptAndTriggerOnload(
+ directory + "/reporting/resources/try-access.js",
+ "tryAccess(opener);")
+ );
+
+ // 4. Check a report sent to the opener.
+ let report =
+ await receiveReport(opener_report_token, "access-to-coop-page-from-openee")
+ assert_equals(report.type, "coop");
+ assert_equals(report.url, opener_url.replace(/"/g, '%22'));
+ assert_equals(report.body.disposition, "reporting");
+ assert_equals(report.body.effectivePolicy, "same-origin-plus-coep");
+ assert_equals(report.body.property, "blur");
+ assert_source_location_missing(report);
+ assert_equals(report.body.openerURL, undefined);
+ assert_equals(report.body.openeeURL, openee_url);
+ assert_equals(report.body.otherDocumentURL, undefined);
+ assert_equals(report.body.referrer, undefined);
+ assert_equals(report.body.initialPopupURL, openee_requested_url);
+}, name);
+
+runTest(false, "access-to-coop-page-from-openee, same-origin");
+runTest(true , "access-to-coop-page-from-openee, same-origin + redirect");
+
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/access-to-coop-page-from-openee_coop-ro_cross-origin.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/access-to-coop-page-from-openee_coop-ro_cross-origin.https.html
new file mode 100644
index 0000000000..d9577836d9
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/access-to-coop-page-from-openee_coop-ro_cross-origin.https.html
@@ -0,0 +1,79 @@
+<title>
+ COOP reports are to the opener when the opener used COOP-RO+COEP and then its
+ cross-origin openee tries to access it.
+</title>
+<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="/common/dispatcher/dispatcher.js"></script>
+<script src="/html/cross-origin-opener-policy/resources/common.js"></script>
+<script src="/html/cross-origin-opener-policy/reporting/resources/reporting-common.js"></script>
+<script src="/html/cross-origin-opener-policy/reporting/resources/try-access.js"></script>
+<script>
+
+const directory = "/html/cross-origin-opener-policy";
+const redirect_path = directory + "/resources/redirect.py?";
+const same_origin = get_host_info().HTTPS_REMOTE_ORIGIN;
+const cross_origin= get_host_info().HTTPS_ORIGIN;
+
+let runTest = (openee_redirect, name) => promise_test(async t => {
+ // The test window.
+ const this_window_token = token();
+
+ // The "opener" window. This has COOP and a reporter.
+ const opener_report_token= token();
+ const opener_token = token();
+ const opener_reportTo = reportToHeaders(opener_report_token);
+ const opener_url = same_origin + executor_path + opener_reportTo.header +
+ opener_reportTo.coopReportOnlySameOriginHeader + coep_header +
+ `&uuid=${opener_token}`;
+
+ // The "openee" window. This is cross origin with the "opener".
+ const openee_report_token= token();
+ const openee_token = token();
+ const openee_url = cross_origin + executor_path + `&uuid=${openee_token}`;
+ const openee_redirect_url = same_origin + redirect_path + openee_url
+ const openee_requested_url = openee_redirect ? openee_redirect_url
+ : openee_url;
+
+ // 1. Create the opener window.
+ let opener_window_proxy = window.open(opener_url);
+ t.add_cleanup(() => send(opener_token, "window.close()"));
+
+ // 2. The opener opens its openee.
+ send(opener_token, `
+ openee = window.open("${openee_requested_url}");
+ send("${this_window_token}", "ACK 1");
+ `);
+ assert_equals("ACK 1", await receive(this_window_token));
+ t.add_cleanup(() => send(openee_token, "window.close()"));
+
+ // 3. The openee tries to access its opener.
+ send(openee_token, addScriptAndTriggerOnload(
+ directory + "/reporting/resources/try-access.js",
+ "tryAccess(opener);")
+ );
+
+ // 4. Check a report sent to the opener.
+ let report =
+ await receiveReport(opener_report_token, "access-to-coop-page-from-openee")
+ assert_equals(report.type, "coop");
+ assert_equals(report.url, opener_url.replace(/"/g, '%22'));
+ assert_equals(report.body.disposition, "reporting");
+ assert_equals(report.body.effectivePolicy, "same-origin-plus-coep");
+ assert_equals(report.body.property, "blur");
+ assert_source_location_missing(report);
+ assert_equals(report.body.openerURL, undefined);
+ assert_equals(report.body.openeeURL, "");
+ assert_equals(report.body.otherDocumentURL, undefined);
+ assert_equals(report.body.referrer, undefined);
+ assert_equals(report.body.referrer, undefined);
+ assert_equals(report.body.initialPopupURL, openee_requested_url);
+}, name);
+
+runTest(false, "access-to-coop-page-from-openee, cross-origin");
+runTest(true , "access-to-coop-page-from-openee, cross-origin + redirect)");
+
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/access-to-coop-page-from-opener_coop-ro.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/access-to-coop-page-from-opener_coop-ro.https.html
new file mode 100644
index 0000000000..8a643d762c
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/access-to-coop-page-from-opener_coop-ro.https.html
@@ -0,0 +1,67 @@
+<title>
+ COOP reports are sent when the openee used COOP-RO+COEP and then its
+ same-origin opener tries to access it.
+</title>
+<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="/common/dispatcher/dispatcher.js"></script>
+<script src="/html/cross-origin-opener-policy/reporting/resources/reporting-common.js"></script>
+<script src="/html/cross-origin-opener-policy/reporting/resources/try-access.js"></script>
+<script>
+
+const directory = "/html/cross-origin-opener-policy";
+const redirect_path = directory + "/resources/redirect.py?";
+const same_origin = get_host_info().HTTPS_ORIGIN;
+
+let runTest = (openee_redirect, name) => promise_test(async t => {
+ const report_token = token();
+ const openee_token = token();
+ const opener_token = token(); // The current test window.
+
+ const opener_url = location.href;
+
+ const reportTo = reportToHeaders(report_token);
+ const openee_url = same_origin + executor_path + reportTo.header +
+ reportTo.coopReportOnlySameOriginHeader + coep_header +
+ `&uuid=${openee_token}`;
+ const openee_redirect_url = same_origin + redirect_path + openee_url
+ const openee_requested_url = openee_redirect ? openee_redirect_url
+ : openee_url;
+
+
+ const openee = window.open(openee_requested_url);
+ t.add_cleanup(() => send(openee_token, "window.close()"))
+
+ // 1. Make sure the new document to be loaded.
+ send(openee_token, `
+ send("${opener_token}", "Ready");
+ `);
+ let reply = await receive(opener_token);
+ assert_equals(reply, "Ready");
+
+ // 2. Try to access the openee. A report is sent, because of COOP-RO+COEP.
+ tryAccess(openee);
+
+ // 3. Check a report is sent to the openee.
+ let report =
+ await receiveReport(report_token, "access-to-coop-page-from-opener")
+ assert_equals(report.type, "coop");
+ assert_equals(report.url, openee_url.replace(/"/g, '%22'));
+ assert_equals(report.body.disposition, "reporting");
+ assert_equals(report.body.effectivePolicy, "same-origin-plus-coep");
+ assert_equals(report.body.property, "blur");
+ assert_source_location_missing(report);
+ assert_equals(report.body.openerURL, opener_url);
+ assert_equals(report.body.openeeURL, undefined);
+ assert_equals(report.body.otherDocumentURL, undefined);
+ assert_equals(report.body.referrer, opener_url);
+ assert_equals(report.body.initialPopupURL, undefined);
+}, name);
+
+runTest(false, "access-to-coop-page-from-opener, same-origin");
+runTest(true , "access-to-coop-page-from-opener, same-origin + redirect");
+
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/access-to-coop-page-from-opener_coop-ro_cross-origin.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/access-to-coop-page-from-opener_coop-ro_cross-origin.https.html
new file mode 100644
index 0000000000..7e1ae870a7
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/access-to-coop-page-from-opener_coop-ro_cross-origin.https.html
@@ -0,0 +1,68 @@
+<title>
+ COOP reports are sent when the openee used COOP-RO+COEP and then its
+ cross-origin opener tries to access it.
+</title>
+<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="/common/dispatcher/dispatcher.js"></script>
+<script src="/html/cross-origin-opener-policy/reporting/resources/reporting-common.js"></script>
+<script src="/html/cross-origin-opener-policy/reporting/resources/try-access.js"></script>
+<script>
+
+const directory = "/html/cross-origin-opener-policy";
+const redirect_path = directory + "/resources/redirect.py?";
+const same_origin = get_host_info().HTTPS_ORIGIN;
+const cross_origin = get_host_info().HTTPS_REMOTE_ORIGIN;
+
+let runTest = (openee_redirect, name) => promise_test(async t => {
+ const report_token = token();
+ const openee_token = token();
+ const opener_token = token(); // The current test window.
+
+ const opener_origin = location.origin + '/';
+
+ const reportTo = reportToHeaders(report_token);
+ const openee_url = cross_origin + executor_path +
+ reportTo.header + reportTo.coopReportOnlySameOriginHeader + coep_header +
+ `&uuid=${openee_token}`;
+ const openee_redirect_url = same_origin + redirect_path + openee_url
+ const openee_requested_url = openee_redirect ? openee_redirect_url
+ : openee_url;
+
+
+ const openee = window.open(openee_requested_url);
+ t.add_cleanup(() => send(openee_token, "window.close()"))
+
+ // 1. Make sure the new document to be loaded.
+ send(openee_token, `
+ send("${opener_token}", "Ready");
+ `);
+ let reply = await receive(opener_token);
+ assert_equals(reply, "Ready");
+
+ // 2. Try to access the openee. A report is sent, because of COOP-RO+COEP.
+ tryAccess(openee);
+
+ // 3. Check a report is sent to the openee.
+ let report =
+ await receiveReport(report_token, "access-to-coop-page-from-opener")
+ assert_equals(report.type, "coop");
+ assert_equals(report.url, openee_url.replace(/"/g, '%22'));
+ assert_equals(report.body.disposition, "reporting");
+ assert_equals(report.body.effectivePolicy, "same-origin-plus-coep");
+ assert_equals(report.body.property, "blur");
+ assert_source_location_missing(report);
+ assert_equals(report.body.openerURL, "");
+ assert_equals(report.body.openeeURL, undefined);
+ assert_equals(report.body.otherDocumentURL, undefined);
+ assert_equals(report.body.referrer, opener_origin);
+ assert_equals(report.body.initialPopupURL, undefined);
+}, name);
+
+runTest(false, "access-to-coop-page-from-opener, cross-origin");
+runTest(true , "access-to-coop-page-from-opener, cross-origin + redirect");
+
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/access-to-coop-page-from-other_coop-ro.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/access-to-coop-page-from-other_coop-ro.https.html
new file mode 100644
index 0000000000..b73bab8610
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/access-to-coop-page-from-other_coop-ro.https.html
@@ -0,0 +1,82 @@
+<title>
+ One window accesses a second one. They are aren't related by an opener/openee
+ relationship. The second window has set
+ Cross-Origin-Opener-Policy-Report-Only:same-origin, so it receives a
+ "access-to-coop-page-from-other" report.
+</title>
+<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="/common/dispatcher/dispatcher.js"></script>
+<script src="/html/cross-origin-opener-policy/resources/common.js"></script>
+<script src="/html/cross-origin-opener-policy/reporting/resources/reporting-common.js"></script>
+<script src="/html/cross-origin-opener-policy/reporting/resources/try-access.js"></script>
+<script>
+
+const directory = "/html/cross-origin-opener-policy";
+const same_origin = get_host_info().HTTPS_ORIGIN;
+
+promise_test(async t => {
+ // The test window.
+ const this_window_token = token();
+
+ // The "opener" window.
+ const opener_token = token();
+ const opener_url = same_origin + executor_path + `&uuid=${opener_token}`;
+
+ // The "openee" window. With COOP:same-origin + reporter.
+ const openee_report_token= token();
+ const openee_token = token();
+ const openee_reportTo = reportToHeaders(openee_report_token);
+ const openee_url = same_origin + executor_path + openee_reportTo.header +
+ openee_reportTo.coopReportOnlySameOriginHeader + coep_header +
+ `&uuid=${openee_token}`;
+
+ // The "other" window.
+ const other_token = token();
+ const other_url = same_origin + executor_path + `&uuid=${other_token}`;
+
+ t.add_cleanup(() => {
+ send(opener_token, "window.close()")
+ send(openee_token, "window.close()")
+ send(other_token, "window.close()")
+ })
+
+ // 1. Create the opener window.
+ let opener_window_proxy = window.open(opener_url);
+
+ // 2. The opener opens its openee and the other window.
+ send(opener_token, `
+ window.openee = window.open('${openee_url.replace(/,/g, '\\,')}');
+ window.other = window.open('${other_url}');
+ `);
+
+ // 3. Make sure the openee is loaded.
+ send(openee_token, `send("${this_window_token}", "Loaded");`);
+ assert_equals(await receive(this_window_token), "Loaded");
+
+ // 4. The "other" window attempts to access the openee though the opener.
+ send(other_token, addScriptAndTriggerOnload(
+ directory + "/reporting/resources/try-access.js",
+ "tryAccess(opener.openee);")
+ );
+
+ // 4. Check a report sent to the openee.
+ let report =
+ await receiveReport(openee_report_token, "access-to-coop-page-from-other")
+ assert_equals(report.type, "coop");
+ assert_equals(report.url, openee_url.replace(/"/g, '%22'));
+ assert_equals(report.body.disposition, "reporting");
+ assert_equals(report.body.effectivePolicy, "same-origin-plus-coep");
+ assert_equals(report.body.property, "blur");
+ assert_source_location_missing(report);
+ assert_equals(report.body.openerURL, undefined);
+ assert_equals(report.body.openeeURL, undefined);
+ assert_equals(report.body.otherDocumentURL, other_url);
+ assert_equals(report.body.referrer, undefined);
+ assert_equals(report.body.initialPopupURL, undefined);
+}, "access-to-coop-page-from-other (COOP-RO)");
+
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/access-to-coop-page-from-other_coop-ro_cross-origin.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/access-to-coop-page-from-other_coop-ro_cross-origin.https.html
new file mode 100644
index 0000000000..c86daa3dca
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/access-to-coop-page-from-other_coop-ro_cross-origin.https.html
@@ -0,0 +1,83 @@
+<title>
+ One window accesses a second one. They are aren't related by an opener/openee
+ relationship. The second window has set
+ Cross-Origin-Opener-Policy-Report-Only:same-origin, so it receives a
+ "access-to-coop-page-from-other" report.
+</title>
+<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="/common/dispatcher/dispatcher.js"></script>
+<script src="/html/cross-origin-opener-policy/resources/common.js"></script>
+<script src="/html/cross-origin-opener-policy/reporting/resources/reporting-common.js"></script>
+<script src="/html/cross-origin-opener-policy/reporting/resources/try-access.js"></script>
+<script>
+
+const directory = "/html/cross-origin-opener-policy";
+const same_origin = get_host_info().HTTPS_ORIGIN;
+const cross_origin = get_host_info().HTTPS_REMOTE_ORIGIN;
+
+promise_test(async t => {
+ // The test window.
+ const this_window_token = token();
+
+ // The "opener" window.
+ const opener_token = token();
+ const opener_url = same_origin + executor_path + `&uuid=${opener_token}`;
+
+ // The "openee" window. With COOP:same-origin + reporter.
+ const openee_report_token= token();
+ const openee_token = token();
+ const openee_reportTo = reportToHeaders(openee_report_token);
+ const openee_url = cross_origin + executor_path + openee_reportTo.header +
+ openee_reportTo.coopReportOnlySameOriginHeader + coep_header +
+ `&uuid=${openee_token}`;
+
+ // The "other" window.
+ const other_token = token();
+ const other_url = same_origin + executor_path + `&uuid=${other_token}`;
+
+ t.add_cleanup(() => {
+ send(opener_token, "window.close()")
+ send(openee_token, "window.close()")
+ send(other_token, "window.close()")
+ })
+
+ // 1. Create the opener window.
+ let opener_window_proxy = window.open(opener_url);
+
+ // 2. The opener opens its openee and the other window.
+ send(opener_token, `
+ window.openee = window.open('${openee_url.replace(/,/g, '\\,')}');
+ window.other = window.open('${other_url}');
+ `);
+
+ // 3. Make sure the openee is loaded.
+ send(openee_token, `send("${this_window_token}", "Loaded");`);
+ assert_equals(await receive(this_window_token), "Loaded");
+
+ // 4. The "other" window attempts to access the openee though the opener.
+ send(other_token, addScriptAndTriggerOnload(
+ directory + "/reporting/resources/try-access.js",
+ "tryAccess(opener.openee);")
+ );
+
+ // 4. Check a report sent to the openee.
+ let report =
+ await receiveReport(openee_report_token, "access-to-coop-page-from-other")
+ assert_equals(report.type, "coop");
+ assert_equals(report.url, openee_url.replace(/"/g, '%22'));
+ assert_equals(report.body.disposition, "reporting");
+ assert_equals(report.body.effectivePolicy, "same-origin-plus-coep");
+ assert_equals(report.body.property, "blur");
+ assert_source_location_missing(report);
+ assert_equals(report.body.openerURL, undefined);
+ assert_equals(report.body.openeeURL, undefined);
+ assert_equals(report.body.otherDocumentURL, "");
+ assert_equals(report.body.referrer, undefined);
+ assert_equals(report.body.initialPopupURL, undefined);
+}, "access-to-coop-page-from-other (COOP-RO)");
+
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/property-blur.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/property-blur.https.html
new file mode 100644
index 0000000000..849bf6579a
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/property-blur.https.html
@@ -0,0 +1,13 @@
+<title> Check openee.blur() access is checked</title>
+<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="/common/dispatcher/dispatcher.js"></script>
+<script src="/html/cross-origin-opener-policy/reporting/resources/reporting-common.js"></script>
+<script src="/html/cross-origin-opener-policy/reporting/resources/test-access-property.js"></script>
+<script>
+
+testAccessProperty("blur", w => w.blur());
+
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/property-close.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/property-close.https.html
new file mode 100644
index 0000000000..7696600488
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/property-close.https.html
@@ -0,0 +1,13 @@
+<title> Check openee.close() access is checked</title>
+<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="/common/dispatcher/dispatcher.js"></script>
+<script src="/html/cross-origin-opener-policy/reporting/resources/reporting-common.js"></script>
+<script src="/html/cross-origin-opener-policy/reporting/resources/test-access-property.js"></script>
+<script>
+
+testAccessProperty("close", w => w.close());
+
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/property-closed.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/property-closed.https.html
new file mode 100644
index 0000000000..c678d18a80
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/property-closed.https.html
@@ -0,0 +1,13 @@
+<title> Check openee.closed access is checked</title>
+<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="/common/dispatcher/dispatcher.js"></script>
+<script src="/html/cross-origin-opener-policy/reporting/resources/reporting-common.js"></script>
+<script src="/html/cross-origin-opener-policy/reporting/resources/test-access-property.js"></script>
+<script>
+
+testAccessProperty("closed", w => w.closed);
+
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/property-focus.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/property-focus.https.html
new file mode 100644
index 0000000000..363c0d294f
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/property-focus.https.html
@@ -0,0 +1,13 @@
+<title> Check openee.focus() access is checked</title>
+<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="/common/dispatcher/dispatcher.js"></script>
+<script src="/html/cross-origin-opener-policy/reporting/resources/reporting-common.js"></script>
+<script src="/html/cross-origin-opener-policy/reporting/resources/test-access-property.js"></script>
+<script>
+
+testAccessProperty("focus", w => w.focus());
+
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/property-frames.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/property-frames.https.html
new file mode 100644
index 0000000000..fc1925045f
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/property-frames.https.html
@@ -0,0 +1,13 @@
+<title> Check openee.frames access is checked</title>
+<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="/common/dispatcher/dispatcher.js"></script>
+<script src="/html/cross-origin-opener-policy/reporting/resources/reporting-common.js"></script>
+<script src="/html/cross-origin-opener-policy/reporting/resources/test-access-property.js"></script>
+<script>
+
+testAccessProperty("frames", w => w.frames);
+
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/property-indexed-getter.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/property-indexed-getter.https.html
new file mode 100644
index 0000000000..b6c5f5acb1
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/property-indexed-getter.https.html
@@ -0,0 +1,66 @@
+<title> Check reports are sent for the indexed getter</title>
+<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="/common/dispatcher/dispatcher.js"></script>
+<script>
+
+const directory = "/html/cross-origin-opener-policy";
+const executor_path = "/common/dispatcher/executor.html?pipe=";
+const coep_header = '|header(Cross-Origin-Embedder-Policy,require-corp)';
+
+let origin = [
+ ["cross-origin" , get_host_info().HTTPS_REMOTE_ORIGIN ] ,
+ ["same-site" , get_host_info().HTTPS_ORIGIN ] ,
+];
+
+let testCase = [
+//[operation , expectReport ] ,
+ [w => w[0] , true ], // Existing iframe.
+ [w => w[1] , false ], // Out of bounds (positive).
+ [w => w[-1] , false ], // Out of bounds (negative).
+];
+
+origin.forEach(([origin_name, origin]) => {
+ testCase.forEach(([op, expectReport]) => {
+ promise_test(async t => {
+ const opener_token = token();
+ const openee_token = token();
+
+ const openee_url = origin+ executor_path + `&uuid=${openee_token}`;
+ const openee = window.open(openee_url);
+ t.add_cleanup(() => send(openee_token, "window.close()"))
+
+ // 1. Create an iframe in the openee.
+ send(openee_token, `
+ let iframe = document.createElement("iframe");
+ document.body.appendChild(iframe);
+
+ send("${opener_token}", "openee loaded");
+ `);
+ let reply = await receive(opener_token);
+ assert_equals(reply, "openee loaded");
+
+ // 2. Try to access the openee.
+ let observer = new ReportingObserver(()=>{});
+ observer.observe();
+ try {op(openee)} catch(e) {}
+ let reports = observer.takeRecords();
+ observer.disconnect();
+
+ // 3. Check the received reports.
+ if (expectReport) {
+ assert_equals(reports.length, 1);
+ assert_equals(reports[0].type, "coop-access-violation");
+ assert_equals(reports[0].body.property, "indexed");
+ } else {
+ assert_equals(reports.length, 0);
+ }
+
+ }, `${origin_name} > ${op}`);
+});
+});
+
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/property-indexed-getter.https.html.headers b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/property-indexed-getter.https.html.headers
new file mode 100644
index 0000000000..64f4d5fedf
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/property-indexed-getter.https.html.headers
@@ -0,0 +1 @@
+Cross-Origin-Opener-Policy-Report-Only: same-origin; report-to="none"
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/property-length.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/property-length.https.html
new file mode 100644
index 0000000000..a9f3614cb5
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/property-length.https.html
@@ -0,0 +1,13 @@
+<title> Check openee.length access is checked</title>
+<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="/common/dispatcher/dispatcher.js"></script>
+<script src="/html/cross-origin-opener-policy/reporting/resources/reporting-common.js"></script>
+<script src="/html/cross-origin-opener-policy/reporting/resources/test-access-property.js"></script>
+<script>
+
+testAccessProperty("length", w => w.length);
+
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/property-location-get.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/property-location-get.https.html
new file mode 100644
index 0000000000..442817748d
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/property-location-get.https.html
@@ -0,0 +1,13 @@
+<title> Check openee.location access is checked</title>
+<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="/common/dispatcher/dispatcher.js"></script>
+<script src="/html/cross-origin-opener-policy/reporting/resources/reporting-common.js"></script>
+<script src="/html/cross-origin-opener-policy/reporting/resources/test-access-property.js"></script>
+<script>
+
+testAccessProperty("location", w => w.location);
+
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/property-location-set.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/property-location-set.https.html
new file mode 100644
index 0000000000..e42f084821
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/property-location-set.https.html
@@ -0,0 +1,13 @@
+<title> Check openee.location access is checked</title>
+<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="/common/dispatcher/dispatcher.js"></script>
+<script src="/html/cross-origin-opener-policy/reporting/resources/reporting-common.js"></script>
+<script src="/html/cross-origin-opener-policy/reporting/resources/test-access-property.js"></script>
+<script>
+
+testAccessProperty("location", w => w.location = "#");
+
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/property-named-getter.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/property-named-getter.https.html
new file mode 100644
index 0000000000..27be9a48d1
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/property-named-getter.https.html
@@ -0,0 +1,71 @@
+<title> Check reports are sent for the indexed getter</title>
+<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="/common/dispatcher/dispatcher.js"></script>
+<script>
+
+const executor_path = "/common/dispatcher/executor.html?pipe=";
+let crossOrigin = ["cross-origin" , get_host_info().HTTPS_REMOTE_ORIGIN ];
+let sameOrigin = ["same-site" , get_host_info().HTTPS_ORIGIN ];
+
+let testCase = [
+//[ operation , origin , expectReport ],
+ [ w => w["iframeName"] , sameOrigin , true ],
+ [ w => w["iframeName"] , crossOrigin , true ],
+ [ w => w["divID"] , sameOrigin , true ],
+ [ w => w["divID"] , crossOrigin , false ],
+ [ w => w["existingGlobal"] , sameOrigin , false ],
+ [ w => w["existingGlobal"] , crossOrigin , false ],
+ [ w => w["missingGlobal"] , sameOrigin , false ],
+ [ w => w["missingGlobal"] , crossOrigin , false ],
+];
+
+testCase.forEach(([op, [origin_name, origin], expectReport]) => {
+ promise_test(async t => {
+ const opener_token = token();
+ const openee_token = token();
+
+ const openee_url = origin + executor_path + `&uuid=${openee_token}`;
+ const openee = window.open(openee_url);
+ t.add_cleanup(() => send(openee_token, "window.close()"))
+
+ // 1. Make sure the new document to be loaded. Populate the document.
+ send(openee_token, `
+ let iframe = document.createElement("iframe");
+ iframe.name = "iframeName";
+ document.body.appendChild(iframe);
+
+ let div = document.createElement("div");
+ div.id = "divID";
+ document.body.appendChild(div);
+
+ window.existingGlobal = "test";
+
+ send("${opener_token}", "Ready");
+ `);
+ let reply = await receive(opener_token);
+ assert_equals(reply, "Ready");
+
+ // 2. Try to access the openee.
+ let observer = new ReportingObserver(()=>{});
+ observer.observe();
+ try {op(openee)} catch(e) {}
+ let reports = observer.takeRecords();
+ observer.disconnect();
+
+ // 3. Check the received reports.
+ if (expectReport) {
+ assert_equals(reports.length, 1);
+ assert_equals(reports[0].type, "coop-access-violation");
+ assert_equals(reports[0].body.property, "named");
+ } else {
+ assert_equals(reports.length, 0);
+ }
+
+ }, `${origin_name} > ${op}`);
+});
+
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/property-named-getter.https.html.headers b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/property-named-getter.https.html.headers
new file mode 100644
index 0000000000..64f4d5fedf
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/property-named-getter.https.html.headers
@@ -0,0 +1 @@
+Cross-Origin-Opener-Policy-Report-Only: same-origin; report-to="none"
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/property-opener-get.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/property-opener-get.https.html
new file mode 100644
index 0000000000..b99dfdc562
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/property-opener-get.https.html
@@ -0,0 +1,13 @@
+<title> Check openee.opener access is checked</title>
+<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="/common/dispatcher/dispatcher.js"></script>
+<script src="/html/cross-origin-opener-policy/reporting/resources/reporting-common.js"></script>
+<script src="/html/cross-origin-opener-policy/reporting/resources/test-access-property.js"></script>
+<script>
+
+testAccessProperty("opener", w => w.opener);
+
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/property-opener-set.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/property-opener-set.https.html
new file mode 100644
index 0000000000..10c251140b
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/property-opener-set.https.html
@@ -0,0 +1,13 @@
+<title> Check openee.opener access is checked</title>
+<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="/common/dispatcher/dispatcher.js"></script>
+<script src="/html/cross-origin-opener-policy/reporting/resources/reporting-common.js"></script>
+<script src="/html/cross-origin-opener-policy/reporting/resources/test-access-property.js"></script>
+<script>
+
+testAccessProperty("opener", w => w.opener = "", /* expectReport = */false);
+
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/property-postmessage-1.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/property-postmessage-1.https.html
new file mode 100644
index 0000000000..a9168fdaa5
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/property-postmessage-1.https.html
@@ -0,0 +1,13 @@
+<title> Check openee.postMessage(arg1, arg2) access is checked</title>
+<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="/common/dispatcher/dispatcher.js"></script>
+<script src="/html/cross-origin-opener-policy/reporting/resources/reporting-common.js"></script>
+<script src="/html/cross-origin-opener-policy/reporting/resources/test-access-property.js"></script>
+<script>
+
+testAccessProperty("postMessage", w => w.postMessage("", ""));
+
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/property-postmessage-2.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/property-postmessage-2.https.html
new file mode 100644
index 0000000000..4341f245d5
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/property-postmessage-2.https.html
@@ -0,0 +1,13 @@
+<title> Check openee.postMessage(arg1) access is checked</title>
+<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="/common/dispatcher/dispatcher.js"></script>
+<script src="/html/cross-origin-opener-policy/reporting/resources/reporting-common.js"></script>
+<script src="/html/cross-origin-opener-policy/reporting/resources/test-access-property.js"></script>
+<script>
+
+testAccessProperty("postMessage", w => w.postMessage(""));
+
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/property-self.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/property-self.https.html
new file mode 100644
index 0000000000..7a7d5a3fec
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/property-self.https.html
@@ -0,0 +1,13 @@
+<title> Check openee.self access is checked</title>
+<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="/common/dispatcher/dispatcher.js"></script>
+<script src="/html/cross-origin-opener-policy/reporting/resources/reporting-common.js"></script>
+<script src="/html/cross-origin-opener-policy/reporting/resources/test-access-property.js"></script>
+<script>
+
+testAccessProperty("self", w => w.self);
+
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/property-top.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/property-top.https.html
new file mode 100644
index 0000000000..1b75ecc105
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/property-top.https.html
@@ -0,0 +1,13 @@
+<title> Check openee.top access is checked</title>
+<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="/common/dispatcher/dispatcher.js"></script>
+<script src="/html/cross-origin-opener-policy/reporting/resources/reporting-common.js"></script>
+<script src="/html/cross-origin-opener-policy/reporting/resources/test-access-property.js"></script>
+<script>
+
+testAccessProperty("top", w => w.top);
+
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/property-window.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/property-window.https.html
new file mode 100644
index 0000000000..07278b4a11
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/property-window.https.html
@@ -0,0 +1,13 @@
+<title> Check openee.window access is checked</title>
+<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="/common/dispatcher/dispatcher.js"></script>
+<script src="/html/cross-origin-opener-policy/reporting/resources/reporting-common.js"></script>
+<script src="/html/cross-origin-opener-policy/reporting/resources/test-access-property.js"></script>
+<script>
+
+testAccessProperty("window", w => w.window);
+
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/report-to-both_coop-ro.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/report-to-both_coop-ro.https.html
new file mode 100644
index 0000000000..46cdc6eb27
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/report-to-both_coop-ro.https.html
@@ -0,0 +1,124 @@
+<title>
+ Both the openee and the opener have a COOP reporter. The report are sent to
+ both side.
+</title>
+<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="/common/dispatcher/dispatcher.js"></script>
+<script src="/html/cross-origin-opener-policy/resources/common.js"></script>
+<script src="/html/cross-origin-opener-policy/reporting/resources/reporting-common.js"></script>
+<script src="/html/cross-origin-opener-policy/reporting/resources/try-access.js"></script>
+<script>
+
+const directory = "/html/cross-origin-opener-policy";
+const origin_opener = get_host_info().HTTPS_ORIGIN;
+const origin_openee = get_host_info().HTTPS_REMOTE_ORIGIN;
+
+let escapeComma = url => url.replace(/,/g, '\\,');
+
+let genericSetup = async function(test) {
+ // The test window.
+ const this_window_token = token();
+
+ // The "opener" window. This has COOP and a reporter.
+ const opener_report_token= token();
+ const opener_token = token();
+ const opener_reportTo = reportToHeaders(opener_report_token);
+ const opener_url = origin_opener+ executor_path + opener_reportTo.header +
+ opener_reportTo.coopReportOnlySameOriginHeader + coep_header +
+ `&uuid=${opener_token}`;
+
+ // The "openee" window. This has COOP and a reporter.
+ const openee_report_token= token();
+ const openee_token = token();
+ const openee_reportTo = reportToHeaders(openee_report_token);
+ const openee_url = origin_openee + executor_path + openee_reportTo.header +
+ openee_reportTo.coopReportOnlySameOriginHeader + coep_header +
+ `&uuid=${openee_token}`;
+
+ // Cleanup at the end of the test.
+ test.add_cleanup(() => {
+ send(openee_token, 'window.close()');
+ send(opener_token, 'window.close()');
+ });
+
+ // 1. Spawn the opener and the openee windows.
+ window.open(opener_url);
+ send(opener_token, `
+ openee = window.open('${escapeComma(openee_url)}');
+ `);
+
+ // 2. Wait for both to be loaded.
+ send(openee_token, `send('${this_window_token}', 'ACK');`);
+ assert_equals(await receive(this_window_token), 'ACK');
+
+ return [
+ this_window_token,
+ opener_token, opener_report_token, opener_url,
+ openee_token, openee_report_token, openee_url,
+ ];
+}
+
+let assert_generic_coop_report = function(report) {
+ assert_equals(report.type, "coop");
+ assert_equals(report.body.disposition, "reporting");
+ assert_equals(report.body.effectivePolicy, "same-origin-plus-coep");
+ assert_equals(report.body.property, "blur");
+}
+
+promise_test(async test => {
+ let [
+ this_window_token,
+ opener_token, opener_report_token, opener_url,
+ openee_token, openee_report_token, openee_url,
+ ] = await genericSetup(test);
+
+ send(opener_token, addScriptAndTriggerOnload(
+ directory + "/reporting/resources/try-access.js",
+ "tryAccess(openee);")
+ );
+
+ let report_opener =
+ await receiveReport(opener_report_token, "access-from-coop-page-to-openee")
+ let report_openee =
+ await receiveReport(openee_report_token, "access-to-coop-page-from-opener")
+
+ assert_generic_coop_report(report_openee);
+ assert_generic_coop_report(report_opener);
+
+ assert_equals(report_opener.url, opener_url.replace(/"/g, '%22'));
+ assert_equals(report_openee.url, openee_url.replace(/"/g, '%22'));
+ assert_source_location_found(report_opener);
+ assert_source_location_missing(report_openee);
+}, "Access from opener")
+
+promise_test(async test => {
+ let [
+ this_window_token,
+ opener_token, opener_report_token, opener_url,
+ openee_token, openee_report_token, openee_url,
+ ] = await genericSetup(test);
+
+ send(openee_token, addScriptAndTriggerOnload(
+ directory + "/reporting/resources/try-access.js",
+ "tryAccess(opener);")
+ );
+
+ let report_opener =
+ await receiveReport(opener_report_token, "access-to-coop-page-from-openee")
+ let report_openee =
+ await receiveReport(openee_report_token, "access-from-coop-page-to-opener")
+
+ assert_generic_coop_report(report_openee);
+ assert_generic_coop_report(report_opener);
+
+ assert_equals(report_opener.url, opener_url.replace(/"/g, '%22'));
+ assert_equals(report_openee.url, openee_url.replace(/"/g, '%22'));
+ assert_source_location_missing(report_opener);
+ assert_source_location_found(report_openee);
+}, "Access from openee")
+
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/reporting-observer.html b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/reporting-observer.html
new file mode 100644
index 0000000000..375c627d27
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/access-reporting/reporting-observer.html
@@ -0,0 +1,275 @@
+<!doctype html>
+<meta charset="utf-8">
+<meta name="timeout" content="long">
+<title>
+ Check the ReportingObserver(s) are notified about the coop-access-violation
+ events.
+</title>
+<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="/common/dispatcher/dispatcher.js"></script>
+<script src="/html/cross-origin-opener-policy/resources/common.js"></script>
+<script src="/html/cross-origin-opener-policy/reporting/resources/reporting-common.js"></script>
+<script src="/html/cross-origin-opener-policy/reporting/resources/try-access.js"></script>
+<script>
+
+const directory = "/html/cross-origin-opener-policy";
+const same_origin = get_host_info().HTTPS_ORIGIN;
+const cross_site = get_host_info().HTTPS_NOTSAMESITE_ORIGIN;
+const corp_header = '|header(Cross-Origin-Resource-Policy,cross-origin)';
+
+promise_test(async t => {
+ // This test window.
+ const this_window_token = token();
+
+ // The "opener" window, using COOP-Report-Only and a reporter.
+ const opener_token = token();
+ const opener_reportTo = reportToHeaders(token());
+ const opener_url = same_origin + executor_path + opener_reportTo.header +
+ opener_reportTo.coopReportOnlySameOriginHeader + coep_header +
+ `&uuid=${opener_token}`;
+
+ // The "openee" window, NOT using COOP.
+ const openee_token = token();
+ const openee_url = same_origin + executor_path + `&uuid=${openee_token}`;
+
+ // 1. Create the opener window.
+ window.open(opener_url);
+ t.add_cleanup(() => send(opener_token, "window.close();"));
+
+ // 2. The opener opens its openee.
+ send(opener_token, `openee = window.open('${openee_url}');`);
+ t.add_cleanup(() => send(openee_token, `window.close();`));
+
+ // 3. Wait for the openee to load its document.
+ send(openee_token, `send("${this_window_token}", "Ready");`);
+ assert_equals(await receive(this_window_token), "Ready");
+
+ // 4. The opener tries to access its openee. All reports for blocked access
+ // from the COOP page should notify the ReportingObservers.
+ send(opener_token, addScriptAndTriggerOnload(
+ directory + "/reporting/resources/try-access.js", `
+ let observer = new ReportingObserver(()=>{});
+ observer.observe();
+ tryAccess(openee);
+ let reports = observer.takeRecords();
+ send("${this_window_token}", JSON.stringify(reports));
+ observer.disconnect();
+ `));
+
+ let report_access_from = JSON.parse(await receive(this_window_token));
+ assert_equals(report_access_from.length, 1, "No report received.");
+ assert_equals(report_access_from[0].type, "coop-access-violation");
+ assert_equals(report_access_from[0].url, opener_url.replace(/"/g, '%22'));
+ assert_source_location_found(report_access_from[0])
+ assert_equals(report_access_from[0].body.type,
+ "access-from-coop-page-to-openee");
+ assert_equals(report_access_from[0].body.openeeURL, openee_url);
+ assert_equals(report_access_from[0].body.openerURL, undefined);
+ assert_equals(report_access_from[0].body.otherDocumentURL, undefined);
+
+ // 5. The openee tries to access its opener. No reports for blocked access
+ // to the COOP page should be dispatched.
+ send(openee_token, addScriptAndTriggerOnload(
+ directory + "/reporting/resources/try-access.js", `
+ let observer = new ReportingObserver(()=>{});
+ observer.observe();
+ tryAccess(opener);
+ let reports = observer.takeRecords();
+ send("${this_window_token}", JSON.stringify(reports));
+ observer.disconnect();
+ `));
+ let report_access_to = JSON.parse(await receive(this_window_token));
+ assert_equals(report_access_to.length, 0, "Unexpected report received.");
+}, "Opener COOP");
+
+promise_test(async t => {
+ // This test window.
+ const this_window_token = token();
+
+ // The "opener" window, NOT using COOP.
+ const opener_token = token();
+ const opener_url = same_origin + executor_path + `&uuid=${opener_token}`;
+
+ // The "openee" window, using COOP-Report-Only and a reporter.
+ const openee_token = token();
+ const openee_reportTo = reportToHeaders(token());
+ const openee_url = same_origin + executor_path + openee_reportTo.header +
+ openee_reportTo.coopReportOnlySameOriginHeader + coep_header +
+ `&uuid=${openee_token}`;
+
+ // 1. Create the opener window.
+ window.open(opener_url);
+ t.add_cleanup(() => send(opener_token, "window.close();"));
+
+ // 2. The opener opens its openee.
+ send(opener_token,
+ `openee = window.open('${openee_url.replace(/,/g, '\\,')}');`);
+ t.add_cleanup(() => send(openee_token, `window.close();`));
+
+ // 3. The openee tries to access its opener. All reports for blocked access
+ // from the COOP page should notify the ReportingObservers.
+ send(openee_token, addScriptAndTriggerOnload(
+ directory + "/reporting/resources/try-access.js", `
+ let observer = new ReportingObserver(()=>{});
+ observer.observe();
+ tryAccess(opener);
+ let reports = observer.takeRecords();
+ send("${this_window_token}", JSON.stringify(reports));
+ observer.disconnect();
+ `));
+ let report_access_from = JSON.parse(await receive(this_window_token));
+ assert_equals(report_access_from.length, 1, "No report received.");
+ assert_equals(report_access_from[0].type, "coop-access-violation");
+ assert_equals(report_access_from[0].url, openee_url.replace(/"/g, '%22'));
+ assert_true(report_access_from[0].body.sourceFile.includes("try-access.js"));
+ assert_source_location_found(report_access_from[0])
+ assert_equals(report_access_from[0].body.type,
+ "access-from-coop-page-to-opener");
+ assert_equals(report_access_from[0].body.openeeURL, undefined);
+ assert_equals(report_access_from[0].body.openerURL, opener_url);
+ assert_equals(report_access_from[0].body.otherDocumentURL, undefined);
+
+ // 4. The opener tries to access its openee. No reports for blocked access
+ // to the COOP page should be dispatched.
+ send(opener_token, addScriptAndTriggerOnload(
+ directory + "/reporting/resources/try-access.js", `
+ let observer = new ReportingObserver(()=>{});
+ observer.observe();
+ tryAccess(openee);
+ let reports = observer.takeRecords();
+ send("${this_window_token}", JSON.stringify(reports));
+ observer.disconnect();
+ `));
+ let report_access_to = JSON.parse(await receive(this_window_token));
+ assert_equals(report_access_to.length, 0, "Unexpected report received.");
+}, "Openee COOP");
+
+promise_test(async t => {
+ // This test window.
+ const this_window_token = token();
+
+ // The "opener" window, using COOP-Report-Only and a reporter.
+ const opener_token = token();
+ const opener_reportTo = reportToHeaders(token());
+ const opener_url = same_origin + executor_path + opener_reportTo.header +
+ opener_reportTo.coopReportOnlySameOriginHeader + coep_header +
+ `&uuid=${opener_token}`;
+
+ // The "opener's iframe", same-origin with its parent.
+ const opener_iframe_token = token();
+ const opener_iframe_url = same_origin + executor_path + coep_header +
+ `&uuid=${opener_iframe_token}`;
+
+ // The "openee" window, NOT using COOP.
+ const openee_token = token();
+ const openee_url = same_origin + executor_path + coep_header +
+ `&uuid=${openee_token}`;
+
+ // 1. Create the opener window.
+ window.open(opener_url);
+ t.add_cleanup(() => send(opener_token, "window.close();"));
+
+ // 2. The opener opens an iframe, and install a ReportingObserver to catch
+ // future accesses.
+ send(opener_token, `
+ iframe = document.createElement("iframe");
+ iframe.src = "${opener_iframe_url}";
+ document.body.appendChild(iframe);
+
+ let observer = new ReportingObserver(reports => {
+ send("${this_window_token}", JSON.stringify(reports));
+ observer.disconnect();
+ });
+ observer.observe();
+ `);
+
+ // 3. The iframe opens the openee.
+ send(opener_iframe_token, `openee = window.open('${openee_url}');`);
+ t.add_cleanup(() => send(openee_token, `window.close();`));
+
+ // 4. Wait for the openee to load its document.
+ send(openee_token, `send("${this_window_token}", "Ready");`);
+ assert_equals(await receive(this_window_token), "Ready");
+
+ // 4. The opener's iframe tries to access the openee. This is an
+ // "access-from-coop-page" from a same-origin iframe, so the
+ // ReportingObserver(s) are notified.
+ send(opener_iframe_token, addScriptAndTriggerOnload(
+ directory + "/reporting/resources/try-access.js", `tryAccess(openee);`));
+
+ let reports = await receive(this_window_token);
+ reports = JSON.parse(reports);
+ assert_equals(reports.length, 1, "No report received.");
+ assert_equals(reports[0].type, "coop-access-violation");
+ assert_equals(reports[0].url, opener_url.replace(/"/g, '%22'));
+ assert_true(reports[0].body.sourceFile.includes("try-access.js"));
+ assert_source_location_found(reports[0]);
+ assert_equals(reports[0].body.type,
+ "access-from-coop-page-to-openee");
+ assert_equals(reports[0].body.openeeURL, openee_url);
+ assert_equals(reports[0].body.openerURL, undefined);
+ assert_equals(reports[0].body.otherDocumentURL, undefined);
+}, "Access from same-origin iframe")
+
+promise_test(async t => {
+ // This test window.
+ const this_window_token = token();
+
+ // The "opener" window, using COOP-Report-Only and a reporter.
+ const opener_token = token();
+ const opener_reportTo = reportToHeaders(token());
+ const opener_url = same_origin + executor_path + opener_reportTo.header +
+ opener_reportTo.coopReportOnlySameOriginHeader + coep_header +
+ `&uuid=${opener_token}`;
+
+ // The "opener's iframe", same-origin with its parent.
+ const opener_iframe_token = token();
+ const opener_iframe_url = cross_site + executor_path + coep_header +
+ corp_header +
+ `&uuid=${opener_iframe_token}`;
+
+ // The "openee" window, NOT using COOP.
+ const openee_token = token();
+ const openee_url = same_origin + executor_path + coep_header +
+ `&uuid=${openee_token}`;
+
+ // 1. Create the opener window.
+ window.open(opener_url);
+ t.add_cleanup(() => send(opener_token, "window.close();"));
+
+ // 2. The opener opens an iframe, and install a ReportingObserver to catch
+ // future accesses.
+ send(opener_token, `
+ iframe = document.createElement("iframe");
+ iframe.src = "${opener_iframe_url}";
+ document.body.appendChild(iframe);
+
+ let observer = new ReportingObserver(reports => {
+ send("${this_window_token}", JSON.stringify(reports));
+ observer.disconnect();
+ });
+ observer.observe();
+ `);
+
+ // 3. The iframe opens the openee.
+ send(opener_iframe_token, `openee = window.open('${openee_url}');`);
+ t.add_cleanup(() => send(openee_token, `window.close();`));
+
+ // 4. Wait for the openee to load its document.
+ send(openee_token, `send("${this_window_token}", "Ready");`);
+ assert_equals(await receive(this_window_token), "Ready");
+
+ // 5. The opener's iframe tries to access the openee. This is an
+ // "access-from-coop-page" from a cross-site iframe. The ReportingObservers
+ // from the main document aren't notified.
+ send(opener_iframe_token, addScriptAndTriggerOnload(
+ directory + "/reporting/resources/try-access.js", `tryAccess(openee);`));
+
+ let reports = await receive(this_window_token, 2000);
+ assert_equals(reports, "timeout", "Unexpected report received.");
+}, "Access from cross-site iframe")
+
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/document-reporting/report-only-four-reports.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/document-reporting/report-only-four-reports.https.html
new file mode 100644
index 0000000000..7bfdab1330
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/document-reporting/report-only-four-reports.https.html
@@ -0,0 +1,86 @@
+
+<meta name=timeout content=long>
+<title>A test with both COOP and COOP report only setup using Reporting-Endpoints header</title>
+<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="/common/dispatcher/dispatcher.js"></script>
+<script src="/html/cross-origin-opener-policy/resources/common.js"></script>
+<script
+ src="/html/cross-origin-opener-policy/reporting/resources/reporting-common.js?pipe=sub&report_id=2aee31d2-cd11-43bd-b34d-5f081ca3b2b4&report_only_id=d18f1779-e2ab-4a7a-8b1c-44e3a6f440f5"></script>
+
+<script>
+let tests = [
+ // popup origin, popup COOP, popup COEP, popup COOP report-only, popup COEP report-only, expected reports
+
+ // Open a cross-origin popup with both normal and report-only COOP. Four
+ // reports are sent.
+ [
+ CROSS_ORIGIN,
+ `same-origin-allow-popups; report-to="${popupReportEndpoint.name}"`,
+ "require-corp",
+ `same-origin; report-to="${popupReportOnlyEndpoint.name}"`,
+ "require-corp",
+ [
+ {
+ "endpoint": reportEndpoint,
+ "report": {
+ "body": {
+ "disposition": "enforce",
+ "effectivePolicy": "same-origin-allow-popups",
+ "nextResponseURL": /uuid=EXECUTOR_UUID$/, // next document URL
+ "type": "navigation-from-response"
+ },
+ "url": `${location.href}`,
+ "type": "coop"
+ }
+ },
+ {
+ "endpoint": reportOnlyEndpoint,
+ "report": {
+ "body": {
+ "disposition": "reporting",
+ "effectivePolicy": "same-origin-plus-coep",
+ "nextResponseURL": /uuid=EXECUTOR_UUID$/, // next document URL
+ "type": "navigation-from-response"
+ },
+ "url": `${location.href}`,
+ "type": "coop"
+ }
+ },
+ {
+ "endpoint": popupReportEndpoint,
+ "report": {
+ "body": {
+ "disposition": "enforce",
+ "effectivePolicy": "same-origin-allow-popups",
+ "previousResponseURL": "",
+ "referrer": `${location.origin}/`, // referrer
+ "type": "navigation-to-response"
+ },
+ "url": /uuid=EXECUTOR_UUID$/,
+ "type": "coop"
+ }
+ },
+ {
+ "endpoint": popupReportOnlyEndpoint,
+ "report": {
+ "body": {
+ "disposition": "reporting",
+ "effectivePolicy": "same-origin-plus-coep",
+ "previousResponseURL": "",
+ "referrer": `${location.origin}/`, // referrer
+ "type": "navigation-to-response"
+ },
+ "url": /uuid=EXECUTOR_UUID$/,
+ "type": "coop"
+ }
+ }
+ ]
+ ]
+];
+
+runNavigationDocumentReportingTests(document.title, tests);
+
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/document-reporting/report-only-four-reports.https.html.sub.headers b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/document-reporting/report-only-four-reports.https.html.sub.headers
new file mode 100644
index 0000000000..de48445f38
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/document-reporting/report-only-four-reports.https.html.sub.headers
@@ -0,0 +1,6 @@
+Cross-Origin-Opener-Policy: same-origin-allow-popups; report-to="coop-report-endpoint"
+Cross-Origin-Opener-Policy-Report-Only: same-origin; report-to="coop-report-only-endpoint"
+Cross-Origin-Embedder-Policy: require-corp
+Cross-Origin-Embedder-Policy-Report-Only: require-corp
+Referrer-Policy: origin
+Reporting-Endpoints: coop-report-endpoint="https://{{host}}:{{ports[https][0]}}/reporting/resources/report.py?reportID=2aee31d2-cd11-43bd-b34d-5f081ca3b2b4", coop-report-only-endpoint="https://{{host}}:{{ports[https][0]}}/reporting/resources/report.py?reportID=d18f1779-e2ab-4a7a-8b1c-44e3a6f440f5"
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/document-reporting/report-to-both_coop-ro.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/document-reporting/report-to-both_coop-ro.https.html
new file mode 100644
index 0000000000..409628c15c
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/document-reporting/report-to-both_coop-ro.https.html
@@ -0,0 +1,124 @@
+<title>
+ Both the openee and the opener have a COOP reporter. The report are sent to
+ both side.
+</title>
+<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="/common/dispatcher/dispatcher.js"></script>
+<script src="/html/cross-origin-opener-policy/resources/common.js"></script>
+<script src="/html/cross-origin-opener-policy/reporting/resources/reporting-common.js"></script>
+<script src="/html/cross-origin-opener-policy/reporting/resources/try-access.js"></script>
+<script>
+
+const directory = "/html/cross-origin-opener-policy";
+const origin_opener = get_host_info().HTTPS_ORIGIN;
+const origin_openee = get_host_info().HTTPS_REMOTE_ORIGIN;
+
+let escapeComma = url => url.replace(/,/g, '\\,');
+
+let genericSetup = async function(test) {
+ // The test window.
+ const this_window_token = token();
+
+ // The "opener" window. This has COOP and a reporter.
+ const opener_token = token();
+ const opener_report_token = reportToken();
+ const opener_reporting = reportingEndpointsHeaders(opener_report_token);
+ const opener_url = origin_opener+ executor_path + opener_reporting.header +
+ opener_reporting.coopReportOnlySameOriginHeader + coep_header +
+ `&uuid=${opener_token}`;
+
+ // The "openee" window. This has COOP and a reporter.
+ const openee_token = token();
+ const openee_report_token = reportToken();
+ const openee_reporting = reportingEndpointsHeaders(openee_report_token);
+ const openee_url = origin_openee + executor_path + openee_reporting.header +
+ openee_reporting.coopReportOnlySameOriginHeader + coep_header +
+ `&uuid=${openee_token}`;
+
+ // Cleanup at the end of the test.
+ test.add_cleanup(() => {
+ send(openee_token, 'window.close()');
+ send(opener_token, 'window.close()');
+ });
+
+ // 1. Spawn the opener and the openee windows.
+ window.open(opener_url);
+ send(opener_token, `
+ openee = window.open('${escapeComma(openee_url)}');
+ `);
+
+ // 2. Wait for both to be loaded.
+ send(openee_token, `send('${this_window_token}', 'ACK');`);
+ assert_equals(await receive(this_window_token), 'ACK');
+
+ return [
+ this_window_token,
+ opener_token, opener_report_token, opener_url,
+ openee_token, openee_report_token, openee_url,
+ ];
+}
+
+let assert_generic_coop_report = function(report) {
+ assert_equals(report.type, "coop");
+ assert_equals(report.body.disposition, "reporting");
+ assert_equals(report.body.effectivePolicy, "same-origin-plus-coep");
+ assert_equals(report.body.property, "blur");
+}
+
+promise_test(async test => {
+ let [
+ this_window_token,
+ opener_token, opener_report_token, opener_url,
+ openee_token, openee_report_token, openee_url,
+ ] = await genericSetup(test);
+
+ send(opener_token, addScriptAndTriggerOnload(
+ directory + "/reporting/resources/try-access.js",
+ "tryAccess(openee);")
+ );
+
+ let report_opener =
+ await receiveReport(opener_report_token, "access-from-coop-page-to-openee")
+ let report_openee =
+ await receiveReport(openee_report_token, "access-to-coop-page-from-opener")
+
+ assert_generic_coop_report(report_openee);
+ assert_generic_coop_report(report_opener);
+
+ assert_equals(report_opener.url, opener_url.replace(/"/g, '%22'));
+ assert_equals(report_openee.url, openee_url.replace(/"/g, '%22'));
+ assert_source_location_found(report_opener);
+ assert_source_location_missing(report_openee);
+}, "Access from opener")
+
+promise_test(async test => {
+ let [
+ this_window_token,
+ opener_token, opener_report_token, opener_url,
+ openee_token, openee_report_token, openee_url,
+ ] = await genericSetup(test);
+
+ send(openee_token, addScriptAndTriggerOnload(
+ directory + "/reporting/resources/try-access.js",
+ "tryAccess(opener);")
+ );
+
+ let report_opener =
+ await receiveReport(opener_report_token, "access-to-coop-page-from-openee")
+ let report_openee =
+ await receiveReport(openee_report_token, "access-from-coop-page-to-opener")
+
+ assert_generic_coop_report(report_openee);
+ assert_generic_coop_report(report_opener);
+
+ assert_equals(report_opener.url, opener_url.replace(/"/g, '%22'));
+ assert_equals(report_openee.url, openee_url.replace(/"/g, '%22'));
+ assert_source_location_missing(report_opener);
+ assert_source_location_found(report_openee);
+}, "Access from openee")
+
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/document-reporting/reporting-redirect-with-same-origin-allow-popups.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/document-reporting/reporting-redirect-with-same-origin-allow-popups.https.html
new file mode 100644
index 0000000000..b2ff818d56
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/document-reporting/reporting-redirect-with-same-origin-allow-popups.https.html
@@ -0,0 +1,111 @@
+<title>
+ Tests the redirect interaction with COOP same-origin-allow-popups.
+</title>
+<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="/common/dispatcher/dispatcher.js"></script>
+<script src="/html/cross-origin-opener-policy/resources/common.js"></script>
+<script src="/html/cross-origin-opener-policy/reporting/resources/reporting-common.js"></script>
+<script>
+
+const same_origin = {
+ host: get_host_info().HTTPS_ORIGIN,
+ name: "Same origin"
+};
+const cross_origin = {
+ host: get_host_info().HTTPS_REMOTE_ORIGIN,
+ name: "Cross origin"
+};
+
+// Tests the redirect interaction with COOP same-origin-allow-popups and
+// reporting:
+// 1 - open the opener document on origin same_origin wit COOP
+// same-origin-allow-popups.
+// 2 - opener opens popup with document on origin popup_origin, no COOP and a
+// redirect header (HTTP 302, location).
+// 3 - redirection to a document with origin same_origin and COOP
+// same-origin-allow-popups.
+//
+// The navigation (2) to the first document of the popup stays in the same
+// browsing context group due to the same-origin-allow-popups COOP of the
+// opener.
+// The redirect (3) to the final document does since it compares the
+// popup_origin/unsafe-none document with the
+// same-origin/same-origin-allow-popups document.
+//
+// A opens B, B redirects to C.
+//
+// Document Origin COOP
+// -------- ------------ ------------------------
+// A same-origin same-origin-allow-popups
+// B popup-origin unsafe-none
+// C same-origin same-origin-allow-popups
+function redirect_test(popup_origin) {
+ promise_test(async t => {
+ // The test window.
+ const this_window_token = token();
+
+ // The "opener" window. This has COOP same-origin-allow-popups and a
+ // reporter.
+ const opener_token = token();
+ const opener_report_token = reportToken();
+ const opener_reporting = reportingEndpointsHeaders(opener_report_token);
+ const opener_url = same_origin.host + executor_path +
+ opener_reporting.header + opener_reporting.coopSameOriginAllowPopupsHeader +
+ `&uuid=${opener_token}`;
+
+ // The "openee" window.
+ // The initial document does not have COOP and is on popup_origin, it
+ // redirects to a same-origin (with the opener) document with COOP
+ // same-origin-allow-popups.
+ const openee_token = token();
+ const openee_redirect_url = same_origin.host + executor_path +
+ opener_reporting.header + opener_reporting.coopSameOriginAllowPopupsHeader +
+ `&uuid=${openee_token}`;
+ const redirect_header = 'status(302)' +
+ `|header(Location,${encodeURIComponent(
+ openee_redirect_url
+ .replace(/,/g, "\\,")
+ .replace(/\\\\,/g, "\\\\\\,")
+ .replace(/\(/g, "%28")
+ .replace(/\)/g, "%29"))})`;
+ const openee_url = popup_origin.host + executor_path + redirect_header +
+ `&uuid=${openee_token}`;
+ // 1. Create the opener window.
+ let opener_window_proxy = window.open(opener_url);
+ t.add_cleanup(() => send(opener_token, "window.close()"));
+
+ // 2. The opener opens its openee.
+ send(opener_token, `
+ openee = window.open("${openee_url}");
+ `);
+ t.add_cleanup(() => send(openee_token, "window.close()"));
+
+ // 3. Check the opener status on the openee.
+ send(openee_token, `
+ send("${this_window_token}", opener !== null);
+ `);
+ assert_equals(await receive(this_window_token), "false", "opener");
+
+ // 4. Check the openee status on the opener.
+ send(opener_token, `
+ send("${this_window_token}", openee.closed);
+ `);
+ assert_equals(await receive(this_window_token), "true", "openee.closed");
+
+ // 5. Check a report sent to the openee.
+ let report = await receiveReport(
+ opener_report_token,
+ "navigation-to-response");
+ assert_equals(report.type, "coop");
+ assert_equals(report.body.disposition, "enforce");
+ assert_equals(report.body.effectivePolicy, "same-origin-allow-popups");
+ }, `${popup_origin.name} openee redirected to same-origin with same-origin-allow-popups`);
+}
+
+redirect_test(same_origin);
+redirect_test(cross_origin);
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/document-reporting/reporting-redirect-with-unsafe-none.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/document-reporting/reporting-redirect-with-unsafe-none.https.html
new file mode 100644
index 0000000000..bd89856305
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/document-reporting/reporting-redirect-with-unsafe-none.https.html
@@ -0,0 +1,130 @@
+<title>
+ Tests the redirect interaction with COOP unsafe-none.
+</title>
+<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="/common/dispatcher/dispatcher.js"></script>
+<script src="/html/cross-origin-opener-policy/resources/common.js"></script>
+<script src="/html/cross-origin-opener-policy/reporting/resources/reporting-common.js"></script>
+<script>
+
+const same_origin = {
+ host: get_host_info().HTTPS_ORIGIN,
+ name: "Same origin"
+};
+const cross_origin = {
+ host: get_host_info().HTTPS_REMOTE_ORIGIN,
+ name: "Cross origin"
+};
+
+// Repeated call receive() to fetch all reports received within 1 second.
+async function fetchReportsByID(uuid){
+ let timeStart = new Date().getTime();
+ const reports = [];
+ while(new Date().getTime() - timeStart < 1000) {
+ // Promise.race is used to timeout since receive() has no timeout mechanism.
+ reports.push(...await Promise.race([
+ receive(uuid).then(JSON.parse),
+ new Promise(resolve => step_timeout(resolve, 1000, []))
+ ]));
+ }
+ return reports;
+}
+
+function fetchReportByType(reports, type){
+ return reports.filter((report)=> (report.body.type === type));
+}
+
+ // Tests the redirect interaction with COOP unsafe-none and reporting:
+ // 1 - open the opener document on origin same_origin with COOP
+ // unsafe-none.
+ // 2 - opener opens popup with document on origin popup_origin, with COOP
+ // same-origin, Reporting-Endpoints header and a redirect header
+ // (HTTP 302, location).
+ // 3 - redirection to a document with origin same-origin and COOP
+ // unsafe-none.
+ //
+ // Navigation 2) should generate a report sent to B's reporter(navigation-to).
+ // Navigation 3) should generate a report sent to B's reporter(navigation-from).
+ //
+ // A opens B, B redirects to C.
+ //
+ // Document Origin COOP
+ // -------- ------------ ------------------------
+ // A same-origin unsafe-none
+ // B popup-origin same-origin
+ // C same-origin unsafe-none
+function redirect_test(popup_origin) {
+ promise_test(async t => {
+ // The test window.
+ const this_window_token = token();
+
+ // The "opener" window. This has COOP unsafe-none and no reporter.
+ const opener_token = token();
+ const opener_url = same_origin.host + executor_path +
+ `&uuid=${opener_token}`;
+
+ // The "openee" window.
+ // The initial document have COOP, reporter and is on popup_origin, it
+ // redirects to a same-origin (with the opener) document with no COOP.
+ const openee_token = token();
+ const openee_report_token = reportToken();
+ const openee_reporting = reportingEndpointsHeaders(openee_report_token);
+ const openee_redirect_url = same_origin.host + executor_path +
+ `&uuid=${openee_token}`;
+ const redirect_header = '|status(302)' +
+ `|header(Location,${encodeURIComponent(
+ openee_redirect_url)})`;
+ const openee_url = (popup_origin.host + executor_path
+ + openee_reporting.header + openee_reporting.coopSameOriginHeader
+ + redirect_header + `&uuid=${openee_token}`)
+ .replace(/,/g, "\\,")
+ .replace(/\\\\,/g, "\\\\\\,")
+ .replace(/\(/g, "%28")
+ .replace(/\)/g, "%29");
+ // 1. Create the opener window.
+ let opener_window_proxy = window.open(opener_url);
+ t.add_cleanup(() => send(opener_token, "window.close()"));
+
+ // 2. The opener opens its openee.
+ send(opener_token, `
+ openee = window.open(\`${openee_url}\`);
+ `);
+ t.add_cleanup(() => send(openee_token, "window.close()"));
+
+ // 3. Check the opener status on the openee.
+ send(openee_token, `
+ send("${this_window_token}", opener !== null);
+ `);
+ assert_equals(await receive(this_window_token), "false", "opener");
+
+ // 4. Check the openee status on the opener.
+ send(opener_token, `
+ send("${this_window_token}", openee.closed);
+ `);
+ assert_equals(await receive(this_window_token), "true", "openee.closed");
+
+ // 5. Check a report sent to B's reporting endpoint when A opens B.
+ const reports = await fetchReportsByID(openee_report_token);
+ const navigationToReport = fetchReportByType(
+ reports, "navigation-to-response");
+ assert_equals(navigationToReport.length, 1);
+ assert_equals(navigationToReport[0].type, "coop");
+ assert_equals(navigationToReport[0].body.disposition, "enforce");
+ assert_equals(navigationToReport[0].body.effectivePolicy, "same-origin");
+ // 6. Check a report sent to B's reporting endpoint when B redirects to C.
+ const navigationFromReport = fetchReportByType(
+ reports, "navigation-from-response");
+ assert_equals(navigationFromReport.length, 1);
+ assert_equals(navigationFromReport[0].type, "coop");
+ assert_equals(navigationFromReport[0].body.disposition, "enforce");
+ assert_equals(navigationFromReport[0].body.effectivePolicy, "same-origin");
+ }, `${popup_origin.name} openee redirected to same-origin with unsafe-none`);
+}
+
+redirect_test(same_origin);
+redirect_test(cross_origin);
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/report-only-four-reports.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/report-only-four-reports.https.html
new file mode 100644
index 0000000000..ca1471ccc0
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/report-only-four-reports.https.html
@@ -0,0 +1,86 @@
+<meta name=timeout content=long>
+<title>A test with both COOP and COOP report only setup</title>
+<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="/common/dispatcher/dispatcher.js"></script>
+<script src="/html/cross-origin-opener-policy/resources/common.js"></script>
+<script
+ src="/html/cross-origin-opener-policy/reporting/resources/reporting-common.js?pipe=sub&report_id=47b45e17-51c5-4691-bdd5-8f343bbfcf42&report_only_id=3eb3ad1d-872e-4ea8-8b40-0e98783a0683"></script>
+
+<script>
+
+let tests = [
+ // popup origin, popup COOP, popup COEP, popup COOP report-only, popup COEP report-only, expected reports
+
+ // Open a cross-origin popup with both normal and report-only COOP. Four
+ // reports are sent.
+ [
+ CROSS_ORIGIN,
+ `same-origin-allow-popups; report-to="${popupReportEndpoint.name}"`,
+ "require-corp",
+ `same-origin; report-to="${popupReportOnlyEndpoint.name}"`,
+ "require-corp",
+ [
+ {
+ "endpoint": reportEndpoint,
+ "report": {
+ "body": {
+ "disposition": "enforce",
+ "effectivePolicy": "same-origin-allow-popups",
+ "nextResponseURL": /uuid=EXECUTOR_UUID$/, // next document URL
+ "type": "navigation-from-response"
+ },
+ "url": `${location.href}`,
+ "type": "coop"
+ }
+ },
+ {
+ "endpoint": reportOnlyEndpoint,
+ "report": {
+ "body": {
+ "disposition": "reporting",
+ "effectivePolicy": "same-origin-plus-coep",
+ "nextResponseURL": /uuid=EXECUTOR_UUID$/, // next document URL
+ "type": "navigation-from-response"
+ },
+ "url": `${location.href}`,
+ "type": "coop"
+ }
+ },
+ {
+ "endpoint": popupReportEndpoint,
+ "report": {
+ "body": {
+ "disposition": "enforce",
+ "effectivePolicy": "same-origin-allow-popups",
+ "previousResponseURL": "",
+ "referrer": `${location.origin}/`, // referrer
+ "type": "navigation-to-response"
+ },
+ "url": /uuid=EXECUTOR_UUID$/,
+ "type": "coop"
+ }
+ },
+ {
+ "endpoint": popupReportOnlyEndpoint,
+ "report": {
+ "body": {
+ "disposition": "reporting",
+ "effectivePolicy": "same-origin-plus-coep",
+ "previousResponseURL": "",
+ "referrer": `${location.origin}/`, // referrer
+ "type": "navigation-to-response"
+ },
+ "url": /uuid=EXECUTOR_UUID$/,
+ "type": "coop"
+ }
+ }
+ ]
+ ]
+];
+
+runNavigationReportingTests(document.title, tests);
+
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/report-only-four-reports.https.html.sub.headers b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/report-only-four-reports.https.html.sub.headers
new file mode 100644
index 0000000000..50c3045bb6
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/report-only-four-reports.https.html.sub.headers
@@ -0,0 +1,6 @@
+Cross-Origin-Opener-Policy: same-origin-allow-popups; report-to="coop-report-endpoint"
+Cross-Origin-Opener-Policy-Report-Only: same-origin; report-to="coop-report-only-endpoint"
+Cross-Origin-Embedder-Policy: require-corp
+Cross-Origin-Embedder-Policy-Report-Only: require-corp
+Referrer-Policy: origin
+Reporting-Endpoints: coop-report-endpoint="https://{{host}}:{{ports[https][0]}}/reporting/resources/report.py?reportID=47b45e17-51c5-4691-bdd5-8f343bbfcf42", coop-report-only-endpoint="https://{{host}}:{{ports[https][0]}}/reporting/resources/report.py?reportID=3eb3ad1d-872e-4ea8-8b40-0e98783a0683" \ No newline at end of file
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/report-only-from-unsafe-none.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/report-only-from-unsafe-none.https.html
new file mode 100644
index 0000000000..cca2e7e1ae
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/report-only-from-unsafe-none.https.html
@@ -0,0 +1,71 @@
+
+<meta name=timeout content=long>
+<title>Report only tests for an opener without any COOP/COOP report only set</title>
+<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="/common/dispatcher/dispatcher.js"></script>
+<script src="/html/cross-origin-opener-policy/resources/common.js"></script>
+<script src="/html/cross-origin-opener-policy/reporting/resources/reporting-common.js"></script>
+
+<script>
+
+let tests = [
+ // popup origin, popup COOP, popup COEP, popup COOP report-only, popup COEP report-only, expected reports
+
+ // Open a same-origin popup with a same-origin COOP report-only value, which
+ // would cause a browsing context group swap, hence a report is sent.
+ [
+ SAME_ORIGIN,
+ "",
+ "",
+ `same-origin; report-to="${popupReportOnlyEndpoint.name}"`,
+ "",
+ [
+ {
+ "endpoint": popupReportOnlyEndpoint,
+ "report": {
+ "body": {
+ "disposition": "reporting",
+ "effectivePolicy": "same-origin",
+ "previousResponseURL": `${location.href}`, // previous documnent url
+ "referrer": `${location.origin}/`, // referrer (origin, as dictated by the referrer policy)
+ "type": "navigation-to-response"
+ },
+ "url": /uuid=EXECUTOR_UUID$/,
+ "type": "coop"
+ }
+ }
+ ]
+ ],
+ // Open a cross-origin popup with a same-origin COOP report-only value, which
+ // would cause a browsing context group swap, hence a report is sent.
+ [
+ CROSS_ORIGIN,
+ "",
+ "",
+ `same-origin; report-to="${popupReportOnlyEndpoint.name}"`,
+ "",
+ [
+ {
+ "endpoint": popupReportOnlyEndpoint,
+ "report": {
+ "body": {
+ "disposition": "reporting",
+ "effectivePolicy": "same-origin",
+ "previousResponseURL": "",
+ "referrer": `${location.origin}/`, // referrer (origin, as dictated by the referrer policy)
+ "type": "navigation-to-response"
+ },
+ "url": /uuid=EXECUTOR_UUID$/,
+ "type": "coop"
+ }
+ }
+ ]
+ ],
+];
+
+runNavigationReportingTests(document.title, tests);
+
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/report-only-from-unsafe-none.https.html.headers b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/report-only-from-unsafe-none.https.html.headers
new file mode 100644
index 0000000000..5b29739bbd
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/report-only-from-unsafe-none.https.html.headers
@@ -0,0 +1 @@
+Referrer-Policy: origin
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/report-only-same-origin-report-to.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/report-only-same-origin-report-to.https.html
new file mode 100644
index 0000000000..52b1f2a09f
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/report-only-same-origin-report-to.https.html
@@ -0,0 +1,96 @@
+<meta name=timeout content=long>
+<title>reporting same origin with report-to</title>
+<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="/common/dispatcher/dispatcher.js"></script>
+<script src="/html/cross-origin-opener-policy/resources/common.js"></script>
+<script
+ src="/html/cross-origin-opener-policy/reporting/resources/reporting-common.js?pipe=sub&report_id=380ca360-d1ae-4329-b1dd-69cea49cd705&report_only_id=cf9ac91d-6c5d-4489-a420-10be9402ef84"></script>
+
+<script>
+
+let tests = [
+ // popup origin, popup COOP, popup COEP, popup COOP report-only, popup COEP report-only, expected reports
+
+ // Open a cross-origin popup without any COOP setup, the current document
+ // (opener) report-only would cause a browsing context group swap, hence a
+ // report is sent to the corresponding endpoint.
+ [
+ CROSS_ORIGIN,
+ "",
+ "",
+ "",
+ "",
+ [
+ {
+ "endpoint": reportOnlyEndpoint,
+ "report": {
+ "body": {
+ "disposition": "reporting",
+ "effectivePolicy": "same-origin",
+ "nextResponseURL": /uuid=EXECUTOR_UUID$/, // next document URL
+ "type": "navigation-from-response"
+ },
+ "url": `${location.href}`,
+ "type": "coop"
+ }
+ },
+ ]
+ ],
+ // Open a cross-origin popup with a same-origin COOP report-only value, which
+ // would cause a browsing context group swap, hence a report is sent to both
+ // endpoints.
+ [
+ CROSS_ORIGIN,
+ "",
+ "",
+ `same-origin; report-to="${popupReportOnlyEndpoint.name}"`,
+ "",
+ [
+ {
+ "endpoint": reportOnlyEndpoint,
+ "report": {
+ "body": {
+ "disposition": "reporting",
+ "effectivePolicy": "same-origin",
+ "nextResponseURL": /uuid=EXECUTOR_UUID$/, // next document URL
+ "type": "navigation-from-response"
+ },
+ "url": `${location.href}`,
+ "type": "coop"
+ }
+ },
+ {
+ "endpoint": popupReportOnlyEndpoint,
+ "report": {
+ "body": {
+ "disposition": "reporting",
+ "effectivePolicy": "same-origin",
+ "previousResponseURL": "",
+ "referrer": `${location.origin}/`, // referrer
+ "type": "navigation-to-response"
+ },
+ "url": /uuid=EXECUTOR_UUID$/,
+ "type": "coop"
+ }
+ }
+ ]
+ ],
+ // Open a same-origin popup with a same-origin COOP report-only value, the two
+ // COOP-report-only values match, hence no virtual browsing context group swap
+ // happens and no report is sent.
+ [
+ SAME_ORIGIN,
+ "",
+ "",
+ `same-origin; report-to="${popupReportOnlyEndpoint.name}"`,
+ "",
+ []
+ ],
+];
+
+runNavigationReportingTests(document.title, tests);
+
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/report-only-same-origin-report-to.https.html.sub.headers b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/report-only-same-origin-report-to.https.html.sub.headers
new file mode 100644
index 0000000000..04bc49906b
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/report-only-same-origin-report-to.https.html.sub.headers
@@ -0,0 +1,3 @@
+Cross-Origin-Opener-Policy-Report-Only: same-origin; report-to="coop-report-only-endpoint"
+Referrer-Policy: origin
+Reporting-Endpoints: coop-report-endpoint="https://{{host}}:{{ports[https][0]}}/reporting/resources/report.py?reportID=380ca360-d1ae-4329-b1dd-69cea49cd705", coop-report-only-endpoint="https://{{host}}:{{ports[https][0]}}/reporting/resources/report.py?reportID=cf9ac91d-6c5d-4489-a420-10be9402ef84"
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/report-only-same-origin-with-coep-report-only.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/report-only-same-origin-with-coep-report-only.https.html
new file mode 100644
index 0000000000..148c700ee5
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/report-only-same-origin-with-coep-report-only.https.html
@@ -0,0 +1,32 @@
+
+<meta name=timeout content=long>
+<title>reporting same origin with report-to</title>
+<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="/common/dispatcher/dispatcher.js"></script>
+<script src="/html/cross-origin-opener-policy/resources/common.js"></script>
+<script src="/html/cross-origin-opener-policy/reporting/resources/reporting-common.js"></script>
+
+<script>
+
+let tests = [
+ // popup origin, popup COOP, popup COEP, popup COOP report-only, popup COEP report-only, expected reports
+
+ // Open a cross-origin popup with COOP report-only with coep, which mismatches
+ // with the current document (opener) COOP (unsafe-none) and COOP report-only
+ // (same-origin) values.
+ [
+ SAME_ORIGIN,
+ "",
+ "require-corp",
+ `same-origin; report-to="${popupReportOnlyEndpoint.name}"`,
+ "",
+ []
+ ],
+];
+
+runNavigationReportingTests(document.title, tests);
+
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/report-only-same-origin-with-coep-report-only.https.html.headers b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/report-only-same-origin-with-coep-report-only.https.html.headers
new file mode 100644
index 0000000000..58ab03394a
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/report-only-same-origin-with-coep-report-only.https.html.headers
@@ -0,0 +1,3 @@
+Cross-Origin-Opener-Policy-Report-Only: same-origin
+Cross-Origin-Embedder-Policy-Report-Only: require-corp
+Referrer-Policy: origin
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/report-only-same-origin-with-coep.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/report-only-same-origin-with-coep.https.html
new file mode 100644
index 0000000000..148c700ee5
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/report-only-same-origin-with-coep.https.html
@@ -0,0 +1,32 @@
+
+<meta name=timeout content=long>
+<title>reporting same origin with report-to</title>
+<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="/common/dispatcher/dispatcher.js"></script>
+<script src="/html/cross-origin-opener-policy/resources/common.js"></script>
+<script src="/html/cross-origin-opener-policy/reporting/resources/reporting-common.js"></script>
+
+<script>
+
+let tests = [
+ // popup origin, popup COOP, popup COEP, popup COOP report-only, popup COEP report-only, expected reports
+
+ // Open a cross-origin popup with COOP report-only with coep, which mismatches
+ // with the current document (opener) COOP (unsafe-none) and COOP report-only
+ // (same-origin) values.
+ [
+ SAME_ORIGIN,
+ "",
+ "require-corp",
+ `same-origin; report-to="${popupReportOnlyEndpoint.name}"`,
+ "",
+ []
+ ],
+];
+
+runNavigationReportingTests(document.title, tests);
+
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/report-only-same-origin-with-coep.https.html.headers b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/report-only-same-origin-with-coep.https.html.headers
new file mode 100644
index 0000000000..2ba7ffb592
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/report-only-same-origin-with-coep.https.html.headers
@@ -0,0 +1,3 @@
+Cross-Origin-Opener-Policy-Report-Only: same-origin
+Cross-Origin-Embedder-Policy: require-corp
+Referrer-Policy: origin
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/report-only-same-origin.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/report-only-same-origin.https.html
new file mode 100644
index 0000000000..8a63682c69
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/report-only-same-origin.https.html
@@ -0,0 +1,73 @@
+
+<meta name=timeout content=long>
+<title>reporting same origin with report-to</title>
+<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="/common/dispatcher/dispatcher.js"></script>
+<script src="/html/cross-origin-opener-policy/resources/common.js"></script>
+<script src="/html/cross-origin-opener-policy/reporting/resources/reporting-common.js"></script>
+
+<script>
+
+let tests = [
+ // popup origin, popup COOP, popup COEP, popup COOP report-only, popup COEP report-only, expected reports
+
+ // Open a cross-origin popup with COOP report-only with coep, which mismatches
+ // with the current document (opener) COOP (unsafe-none) and COOP report-only
+ // (same-origin) values.
+ [
+ SAME_ORIGIN,
+ "",
+ "require-corp",
+ `same-origin; report-to="${popupReportOnlyEndpoint.name}"`,
+ "",
+ [
+ {
+ "endpoint": popupReportOnlyEndpoint,
+ "report": {
+ "body": {
+ "disposition": "reporting",
+ "effectivePolicy": "same-origin-plus-coep",
+ "previousResponseURL": `${location.href}`,
+ "referrer": `${location.origin}/`,
+ "type": "navigation-to-response"
+ },
+ "url": /uuid=EXECUTOR_UUID$/,
+ "type": "coop"
+ }
+ }
+ ]
+ ],
+ // Open a cross-origin popup with COOP report-only with coep report-only,
+ // which mismatches with the current document (opener) COOP (unsafe-none) and
+ // COOP report-only (same-origin) values.
+ [
+ SAME_ORIGIN,
+ "",
+ "",
+ `same-origin; report-to="${popupReportOnlyEndpoint.name}"`,
+ "require-corp",
+ [
+ {
+ "endpoint": popupReportOnlyEndpoint,
+ "report": {
+ "body": {
+ "disposition": "reporting",
+ "effectivePolicy": "same-origin-plus-coep",
+ "previousResponseURL": `${location.href}`,
+ "referrer": `${location.origin}/`,
+ "type": "navigation-to-response"
+ },
+ "url": /uuid=EXECUTOR_UUID$/,
+ "type": "coop"
+ }
+ }
+ ]
+ ],
+];
+
+runNavigationReportingTests(document.title, tests);
+
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/report-only-same-origin.https.html.headers b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/report-only-same-origin.https.html.headers
new file mode 100644
index 0000000000..9a8445a43e
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/report-only-same-origin.https.html.headers
@@ -0,0 +1,2 @@
+Cross-Origin-Opener-Policy-Report-Only: same-origin
+Referrer-Policy: origin
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-coop-navigated-opener.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-coop-navigated-opener.https.html
new file mode 100644
index 0000000000..893dfa20b8
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-coop-navigated-opener.https.html
@@ -0,0 +1,67 @@
+<title>
+ Reports a browsing context group switch when an opener with COOP navigates.
+</title>
+<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="/common/dispatcher/dispatcher.js"></script>
+<script src="/html/cross-origin-opener-policy/reporting/resources/reporting-common.js"></script>
+<script>
+
+const directory = "/html/cross-origin-opener-policy";
+const same_origin = get_host_info().HTTPS_ORIGIN;
+
+let escapeComma = url => url.replace(/,/g, '\\,');
+
+promise_test(async t => {
+ // The test window.
+ const this_window_token = token();
+
+ // The "opener" window.
+ const opener_token = token();
+ const opener_url = same_origin + executor_path + `&uuid=${opener_token}`;
+
+ // The "openee" window.
+ const openee_token = token();
+ const openee_url = same_origin + executor_path + `&uuid=${openee_token}`;
+
+ // The "final" url the opener will navigate to. It has COOP and a reporter.
+ const final_report_token = reportToken();
+ const final_token = token();
+ const final_reportTo = reportingEndpointsHeaders(final_report_token);
+ const final_url = same_origin + executor_path + final_reportTo.header +
+ final_reportTo.coopSameOriginHeader +`&uuid=${final_token}`;
+
+ // 1. Create the opener window and ensure it doesn't have an opener.
+ let opener_window_proxy = window.open(opener_url, '_blank', 'noopener');
+ t.add_cleanup(() => send(opener_token, "window.close()"));
+
+ // 2. The opener opens a window.
+ send(opener_token, `
+ openee = window.open('${escapeComma(openee_url)}');
+ `);
+
+ // 3. Ensure the openee loads.
+ send(openee_token, `
+ send("${this_window_token}", "ACK");
+ `);
+ assert_equals("ACK", await receive(this_window_token));
+
+ // 4. The opener navigates.
+ send(opener_token, `
+ location.replace('${escapeComma(final_url)}');
+ `);
+
+ // 5. Check a report was sent to the opener.
+ let report =
+ await receiveReport(final_report_token, "navigation-to-response")
+ assert_equals(report.type, "coop");
+ assert_equals(report.url, final_url.replace(/"/g, '%22'));
+ assert_equals(report.body.disposition, "enforce");
+ assert_equals(report.body.effectivePolicy, "same-origin");
+ assert_equals(report.body.previousResponseURL, opener_url.replace(/"/g, '%22'));
+}, "navigation-report-from-opener-navigation");
+
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-coop-navigated-popup.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-coop-navigated-popup.https.html
new file mode 100644
index 0000000000..b625b285cf
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-coop-navigated-popup.https.html
@@ -0,0 +1,85 @@
+<title>Cross-Origin-Opener-Policy: a navigated popup with reporting</title>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src="/common/utils.js"></script> <!-- Use token() to allow running tests in parallel -->
+<script src="/common/dispatcher/dispatcher.js"></script>
+<script
+ src="/html/cross-origin-opener-policy/reporting/resources/reporting-common.js?pipe=sub&report_id=df3cde15-b00b-4a59-b6e2-498b67a6146e&report_only_id=ebf3a415-7a74-42e1-92d1-e600b1bbe22e"></script>
+
+<script>
+
+// This test does the following:
+// 1 - This document has COOP: same-origin-allow-popups; report-to="coop-report-endpoint"
+// 2 - Open a popup on a same-origin page without COOP, with the coop-popup-report-endpoint
+// 3 - Navigate the popup to a same-origin page with COOP, with the coop-redirect-report-endpoint
+// it verifies that the reports are properly send for the browsing context switch
+// during the navigation in the popup (step 3). The current document (the opener)
+// endpoint should not receive any report as no switch ocurred on 2.
+promise_test( async t => {
+ const callbackToken = token();
+ const noCoopToken = token();
+ const coopToken= token();
+ await reportingTest(async resolve => {
+ const noCOOPUrl = executor_path +
+ convertToWPTHeaderPipe(getReportingEndpointsHeader(location.origin)) +
+ `|header(Cross-Origin-Opener-Policy,${encodeURIComponent(`unsafe-none; report-to="${popupReportEndpoint.name}"`)})` +
+ `&uuid=${noCoopToken}`;
+ const coopUrl = executor_path +
+ convertToWPTHeaderPipe(getReportingEndpointsHeader(location.origin)) +
+ `|header(Cross-Origin-Opener-Policy,${encodeURIComponent(`same-origin; report-to="${redirectReportEndpoint.name}"`)})` +
+ `&uuid=${coopToken}`;
+
+ // 1. Open a popup without COOP and with reporting. COOP does not trigger
+ // a browsing context group switch because the current document is
+ // same-origin-allow-popups
+ const popup = window.open(noCOOPUrl);
+ t.add_cleanup(() => send(noCoopToken, "window.close()"));
+
+ // 2. Navigate the popup to a COOP document, which switches the browsing
+ // context group.
+ send(noCoopToken, `window.location = "${coopUrl}";`);
+ t.add_cleanup(() => send(coopToken, "window.close()"));
+
+ // 3. Make sure the new document is loaded.
+ send(coopToken, `
+ send("${callbackToken}", "Ready");
+ `);
+ let reply = await receive(callbackToken);
+ resolve();
+ },
+ "", // executor token for the report replacements, unused in this test
+ [
+ // Reports expected for the navigation from "noCOOP" to "coop"
+ {
+ "endpoint": popupReportEndpoint,
+ "report": {
+ "body": {
+ "disposition": "enforce",
+ "effectivePolicy": "unsafe-none",
+ "nextResponseURL": RegExp(`uuid=${coopToken}$`),
+ "type": "navigation-from-response"
+ },
+ "url": RegExp(`uuid=${noCoopToken}$`),
+ "type": "coop"
+ }
+ },
+ {
+ "endpoint": redirectReportEndpoint,
+ "report": {
+ "body": {
+ "disposition": "enforce",
+ "effectivePolicy": "same-origin",
+ "previousResponseURL": RegExp(`uuid=${noCoopToken}$`),
+ "referrer": RegExp(`uuid=${noCoopToken}$`),
+ "type": "navigation-to-response"
+ },
+ "url": RegExp(`uuid=${coopToken}$`),
+ "type": "coop"
+ }
+ },
+ ]);
+}, "Open a popup to a document without COOP, then navigate it to a document with");
+
+verifyRemainingReports();
+
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-coop-navigated-popup.https.html.sub.headers b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-coop-navigated-popup.https.html.sub.headers
new file mode 100644
index 0000000000..a6a27c2d3e
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-coop-navigated-popup.https.html.sub.headers
@@ -0,0 +1,2 @@
+Cross-Origin-Opener-Policy: same-origin-allow-popups; report-to="coop-report-endpoint"
+Reporting-Endpoints: coop-report-endpoint="https://{{host}}:{{ports[https][0]}}/reporting/resources/report.py?reportID=df3cde15-b00b-4a59-b6e2-498b67a6146e", coop-report-only-endpoint="https://{{host}}:{{ports[https][0]}}/reporting/resources/report.py?reportID=ebf3a415-7a74-42e1-92d1-e600b1bbe22e"
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-popup-same-origin-allow-popups-report-to.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-popup-same-origin-allow-popups-report-to.https.html
new file mode 100644
index 0000000000..d674e2e449
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-popup-same-origin-allow-popups-report-to.https.html
@@ -0,0 +1,126 @@
+<meta name=timeout content=long>
+<title>reporting same origin with report-to</title>
+<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="/common/dispatcher/dispatcher.js"></script>
+<script src="/html/cross-origin-opener-policy/resources/common.js"></script>
+<script
+src="/html/cross-origin-opener-policy/reporting/resources/reporting-common.js?pipe=sub&report_id=6a739c25-0ec5-4832-b4a3-847281006857&report_only_id=f91209ee-b3a3-474b-b337-d663533745fb"></script>
+
+<script>
+
+let tests = [
+ // popup origin, popup COOP, popup COEP, popup COOP report only, popup COEP report only, expected reports
+
+ // Open a same-origin popup with a same-origin COOP and no COEP. Produces two
+ // reports (one from and one to). Both pages being same origin, the
+ // next/pervious document urls are available.
+ [
+ SAME_ORIGIN,
+ `same-origin; report-to="${popupReportEndpoint.name}"`,
+ "",
+ "",
+ "",
+ [
+ {
+ "endpoint": reportEndpoint,
+ "report": {
+ "body": {
+ "disposition": "enforce",
+ "effectivePolicy": "same-origin-allow-popups",
+ "nextResponseURL": /uuid=EXECUTOR_UUID$/, // next document URL
+ "type": "navigation-from-response"
+ },
+ "url": `${location.href}`,
+ "type": "coop"
+ }
+ },
+ {
+ "endpoint": popupReportEndpoint,
+ "report": {
+ "body": {
+ "disposition": "enforce",
+ "effectivePolicy": "same-origin",
+ "previousResponseURL": `${location.href}`, // previous documnent url
+ "referrer": `${location.origin}/`, // referrer (origin, as dictated by the referrer policy)
+ "type": "navigation-to-response"
+ },
+ "url": /uuid=EXECUTOR_UUID$/,
+ "type": "coop"
+ }
+ }
+ ]
+ ],
+ // Open a cross-origin popup with a same-origin-allow-popup COOP and noCOEP.
+ // Produces two reports (one from and one to). Both pages being cross origin,
+ // the next/pervious document urls are not available and the initial document
+ // url/referrer are used instead.
+ [
+ CROSS_ORIGIN,
+ `same-origin-allow-popups; report-to="${popupReportEndpoint.name}"`,
+ "require-corp",
+ "",
+ "",
+ [
+ {
+ "endpoint": reportEndpoint,
+ "report": {
+ "body": {
+ "disposition": "enforce",
+ "effectivePolicy": "same-origin-allow-popups",
+ "nextResponseURL": /uuid=EXECUTOR_UUID$/, // next document URL
+ "type": "navigation-from-response"
+ },
+ "url": `${location.href}`,
+ "type": "coop"
+ }
+ },
+ {
+ "endpoint": popupReportEndpoint,
+ "report": {
+ "body": {
+ "disposition": "enforce",
+ "effectivePolicy": "same-origin-allow-popups",
+ "previousResponseURL": ``,
+ "referrer": `${location.origin}/`, // referrer (origin, as dictated by the referrer policy)
+ "type": "navigation-to-response"
+ },
+ "url": /uuid=EXECUTOR_UUID$/,
+ "type": "coop"
+ }
+ }
+ ]
+ ],
+ // Open a cross-origin popup with a same-origin COOP and COEP, and no reporting.
+ // Produces one navigation-from-report for this document (the opener). The
+ // pages being cross origin, the next/pervious document urls are not available
+ // and the initial document url/referrer are used instead.
+ [
+ CROSS_ORIGIN,
+ `same-origin`,
+ "require-corp",
+ "",
+ "",
+ [
+ {
+ "endpoint": reportEndpoint,
+ "report": {
+ "body": {
+ "disposition": "enforce",
+ "effectivePolicy": "same-origin-allow-popups",
+ "nextResponseURL": /uuid=EXECUTOR_UUID$/, // initial navigation URL
+ "type": "navigation-from-response"
+ },
+ "url": `${location.href}`,
+ "type": "coop"
+ }
+ }
+ ]
+ ],
+];
+
+runNavigationReportingTests(document.title, tests);
+
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-popup-same-origin-allow-popups-report-to.https.html.sub.headers b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-popup-same-origin-allow-popups-report-to.https.html.sub.headers
new file mode 100644
index 0000000000..3e213a95a3
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-popup-same-origin-allow-popups-report-to.https.html.sub.headers
@@ -0,0 +1,3 @@
+Reporting-Endpoints: coop-report-endpoint="https://{{host}}:{{ports[https][0]}}/reporting/resources/report.py?reportID=6a739c25-0ec5-4832-b4a3-847281006857", coop-report-only-endpoint="https://{{host}}:{{ports[https][0]}}/reporting/resources/report.py?reportID=f91209ee-b3a3-474b-b337-d663533745fb"
+Cross-Origin-Opener-Policy: same-origin-allow-popups; report-to="coop-report-endpoint"
+Referrer-Policy: origin
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-popup-same-origin-coep-report-to.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-popup-same-origin-coep-report-to.https.html
new file mode 100644
index 0000000000..88b180702f
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-popup-same-origin-coep-report-to.https.html
@@ -0,0 +1,173 @@
+<meta name=timeout content=long>
+<title>reporting same origin with report-to</title>
+<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="/common/dispatcher/dispatcher.js"></script>
+<script src="/html/cross-origin-opener-policy/resources/common.js"></script>
+<script
+ src="/html/cross-origin-opener-policy/reporting/resources/reporting-common.js?pipe=sub&report_id=edbbace3-40ca-4640-8d50-dc6e52acc1da&report_only_id=f65cf51a-ca6f-4028-a2c3-0c06183faa13"></script>
+<script>
+
+let tests = [
+ // popup origin, popup COOP, popup COEP, popup COOP report only, popup COEP report only, expected reports
+
+ // Open and navigate a popup to a same-origin page with the same COOP-COEP
+ // settings: no browsing context group switch hence no report expected.
+ [
+ SAME_ORIGIN,
+ `same-origin; report-to="${popupReportEndpoint.name}"`,
+ "require-corp",
+ "",
+ "",
+ []
+ ],
+ // Open a same-origin popup with a same-origin COOP but no COEP. Produces two
+ // reports (one from and one to). The from report has an effectivePolicy of
+ // same-origin-plus-coep, both pages being same origin, the entire
+ // next/pervious document urls are available.
+ [
+ SAME_ORIGIN,
+ `same-origin; report-to="${popupReportEndpoint.name}"`,
+ "",
+ "",
+ "",
+ [
+ {
+ "endpoint": reportEndpoint,
+ "report": {
+ "body": {
+ "disposition": "enforce",
+ "effectivePolicy": "same-origin-plus-coep",
+ "nextResponseURL": /uuid=EXECUTOR_UUID$/, // next destination url
+ "type": "navigation-from-response"
+ },
+ "url": `${location.href}`,
+ "type": "coop"
+ }
+ },
+ {
+ "endpoint": popupReportEndpoint,
+ "report": {
+ "body": {
+ "disposition": "enforce",
+ "effectivePolicy": "same-origin",
+ "previousResponseURL": `${location.href}`, // previous document url
+ "referrer": `${location.origin}/`, // referrer (origin, as dictated by the referrer policy)
+ "type": "navigation-to-response"
+ },
+ "url": /uuid=EXECUTOR_UUID$/,
+ "type": "coop"
+ }
+ }
+ ]
+ ],
+ // Open a cross-origin popup with a same-origin COOP and COEP. Produces two
+ // reports (one from and one to). The from report has an effectivePolicy of
+ // same-origin-plus-coep, both pages being cross origin, the next/pervious
+ // document urls are not available and the initial document url/referrer are
+ // used instead.
+ [
+ CROSS_ORIGIN,
+ `same-origin; report-to="${popupReportEndpoint.name}"`,
+ "require-corp",
+ "",
+ "",
+ [
+ {
+ "endpoint": reportEndpoint,
+ "report": {
+ "body": {
+ "disposition": "enforce",
+ "effectivePolicy": "same-origin-plus-coep",
+ "nextResponseURL": /uuid=EXECUTOR_UUID$/, // initial navigation url
+ "type": "navigation-from-response"
+ },
+ "url": `${location.href}`,
+ "type": "coop"
+ }
+ },
+ {
+ "endpoint": popupReportEndpoint,
+ "report": {
+ "body": {
+ "disposition": "enforce",
+ "effectivePolicy": "same-origin-plus-coep",
+ "previousResponseURL": ``,
+ "referrer": `${location.origin}/`, // referrer (origin, as dictated by the referrer policy)
+ "type": "navigation-to-response"
+ },
+ "url": /uuid=EXECUTOR_UUID$/,
+ "type": "coop"
+ }
+ }
+ ]
+ ],
+ // Open a same-origin popup with a same-origin COOP report only. One report
+ // is sent to this page's endpoint, but none to the report-only endpoint.
+ [
+ SAME_ORIGIN,
+ "",
+ "",
+ `same-origin; report-to="${popupReportOnlyEndpoint.name}"`,
+ "require-corp",
+ [
+ {
+ "endpoint": reportEndpoint,
+ "report": {
+ "body": {
+ "disposition": "enforce",
+ "effectivePolicy": "same-origin-plus-coep",
+ "nextResponseURL": /uuid=EXECUTOR_UUID$/, // initial navigation url
+ "type": "navigation-from-response"
+ },
+ "url": `${location.href}`,
+ "type": "coop"
+ }
+ }
+ ]
+ ],
+ // Open a cross-origin popup with a same-origin COOP report only. A report is
+ // sent to both this page's endpoint and the popup's.
+ [
+ CROSS_ORIGIN,
+ "",
+ "",
+ `same-origin; report-to="${popupReportOnlyEndpoint.name}"`,
+ "require-corp",
+ [
+ {
+ "endpoint": reportEndpoint,
+ "report": {
+ "body": {
+ "disposition": "enforce",
+ "effectivePolicy": "same-origin-plus-coep",
+ "nextResponseURL": /uuid=EXECUTOR_UUID$/, // initial navigation url
+ "type": "navigation-from-response"
+ },
+ "url": `${location.href}`,
+ "type": "coop"
+ }
+ },
+ {
+ "endpoint": popupReportOnlyEndpoint,
+ "report": {
+ "body": {
+ "disposition": "reporting",
+ "effectivePolicy": "same-origin-plus-coep",
+ "previousResponseURL": ``,
+ "referrer": `${location.origin}/`, // referrer (origin, as dictated by the referrer policy)
+ "type": "navigation-to-response"
+ },
+ "url": /uuid=EXECUTOR_UUID$/,
+ "type": "coop"
+ }
+ }
+ ]
+ ],
+];
+
+runNavigationReportingTests(document.title, tests);
+
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-popup-same-origin-coep-report-to.https.html.sub.headers b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-popup-same-origin-coep-report-to.https.html.sub.headers
new file mode 100644
index 0000000000..0f78bdb2d0
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-popup-same-origin-coep-report-to.https.html.sub.headers
@@ -0,0 +1,4 @@
+Reporting-Endpoints: coop-report-endpoint="https://{{host}}:{{ports[https][0]}}/reporting/resources/report.py?reportID=edbbace3-40ca-4640-8d50-dc6e52acc1da", coop-report-only-endpoint="https://{{host}}:{{ports[https][0]}}/reporting/resources/report.py?reportID=f65cf51a-ca6f-4028-a2c3-0c06183faa13"
+Cross-Origin-Opener-Policy: same-origin; report-to="coop-report-endpoint"
+Cross-Origin-Embedder-Policy: require-corp
+Referrer-Policy: origin
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-popup-same-origin-report-to.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-popup-same-origin-report-to.https.html
new file mode 100644
index 0000000000..47bb67cc4b
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-popup-same-origin-report-to.https.html
@@ -0,0 +1,216 @@
+<meta name=timeout content=long>
+<title>reporting same origin with report-to</title>
+<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="/common/dispatcher/dispatcher.js"></script>
+<script src="/html/cross-origin-opener-policy/resources/common.js"></script>
+<script src="/html/cross-origin-opener-policy/reporting/resources/reporting-common.js?pipe=sub&report_id=6aad9729-8642-4894-91d9-a4d44707cd4a&report_only_id=69eb1838-6a03-4cda-97b0-c126ffcb9e8a"></script>
+
+<script>
+
+let tests = [
+ // popup origin, popup COOP, popup COEP, popup COOP report only, popup COEP report only, expected reports
+
+ // Open a popup on a same-origin page, with a compatible COOP.
+ // This is a sanity check that no report are produced.
+ [
+ SAME_ORIGIN,
+ `same-origin; report-to="${popupReportEndpoint.name}"`,
+ "",
+ "",
+ "",
+ []
+ ],
+ // Open a cross-origin popup with a same-origin COOP. Produces two
+ // reports (one from and one to). The from report has an effectivePolicy of
+ // same-origin (corresponding to the current document), both pages being
+ // cross origin, the next/pervious document urls are not available and the
+ // initial document url/referrer are used instead.
+ [
+ CROSS_ORIGIN,
+ `same-origin; report-to="${popupReportEndpoint.name}"`,
+ "",
+ "",
+ "",
+ [
+ {
+ "endpoint": reportEndpoint,
+ "report": {
+ "body": {
+ "disposition": "enforce",
+ "effectivePolicy": "same-origin",
+ "nextResponseURL": /uuid=EXECUTOR_UUID$/,
+ "type": "navigation-from-response"
+ },
+ "url": `${location.href}`,
+ "type": "coop"
+ }
+ },
+ {
+ "endpoint": popupReportEndpoint,
+ "report": {
+ "body": {
+ "disposition": "enforce",
+ "effectivePolicy": "same-origin",
+ "previousResponseURL": "",
+ "referrer": '', // referrer (empty due to the Referrer Policy)
+ "type": "navigation-to-response"
+ },
+ "url": /uuid=EXECUTOR_UUID$/,
+ "type": "coop"
+ }
+ }
+ ]
+ ],
+ // Open a same-origin popup with a unsafe-none COOP and no COEP. COOP switches
+ // the browsing context group and hence produces two reports (one from and one
+ // to). This test verifies that unsafe-none properly sends report.
+ [
+ SAME_ORIGIN,
+ `unsafe-none; report-to="${popupReportEndpoint.name}"`,
+ "",
+ "",
+ "",
+ [
+ {
+ "endpoint": reportEndpoint,
+ "report": {
+ "body": {
+ "disposition": "enforce",
+ "effectivePolicy": "same-origin",
+ "nextResponseURL": /uuid=EXECUTOR_UUID$/,
+ "type": "navigation-from-response"
+ },
+ "url": `${location.href}`,
+ "type": "coop"
+ }
+ },
+ {
+ "endpoint": popupReportEndpoint,
+ "report": {
+ "body": {
+ "disposition": "enforce",
+ "effectivePolicy": "unsafe-none",
+ "previousResponseURL": `${location.href}`,
+ "referrer": '', // referrer (empty due to the Referrer Policy)
+ "type": "navigation-to-response"
+ },
+ "url": /uuid=EXECUTOR_UUID$/,
+ "type": "coop"
+ }
+ }
+ ]
+ ],
+ // Open a same-origin popup with a same-origin COOP and COEP. The difference
+ // of COEP values leads to the browsing context group switch and produces two
+ // reports. This verifies that the navigation-to-document report has an
+ // effectivePolicy of same-origin-plus-coep.
+ [
+ SAME_ORIGIN,
+ `same-origin; report-to="${popupReportEndpoint.name}"`,
+ "require-corp",
+ "",
+ "",
+ [
+ {
+ "endpoint": reportEndpoint,
+ "report": {
+ "body": {
+ "disposition": "enforce",
+ "effectivePolicy": "same-origin",
+ "nextResponseURL": /uuid=EXECUTOR_UUID$/,
+ "type": "navigation-from-response"
+ },
+ "url": `${location.href}`,
+ "type": "coop"
+ }
+ },
+ {
+ "endpoint": popupReportEndpoint,
+ "report": {
+ "body": {
+ "disposition": "enforce",
+ "effectivePolicy": "same-origin-plus-coep",
+ "previousResponseURL": `${location.href}`,
+ "referrer": '', // referrer (empty due to the Referrer Policy)
+ "type": "navigation-to-response"
+ },
+ "url": /uuid=EXECUTOR_UUID$/,
+ "type": "coop"
+ }
+ }
+ ]
+ ],
+ // Open a cross-origin popup with no COOP (but reporting) and no COEP.
+ // Produces two reports. The pages being cross origin, the next/pervious
+ // document urls are not available and the initial document url/referrer are
+ // used instead.
+ [
+ CROSS_ORIGIN,
+ `unsafe-none; report-to="${popupReportEndpoint.name}"`,
+ "",
+ "",
+ "",
+ [
+ {
+ "endpoint": reportEndpoint,
+ "report": {
+ "body": {
+ "disposition": "enforce",
+ "effectivePolicy": "same-origin",
+ "nextResponseURL": /uuid=EXECUTOR_UUID$/,
+ "type": "navigation-from-response"
+ },
+ "url": `${location.href}`,
+ "type": "coop"
+ }
+ },
+ {
+ "endpoint": popupReportEndpoint,
+ "report": {
+ "body": {
+ "disposition": "enforce",
+ "effectivePolicy": "unsafe-none",
+ "previousResponseURL": "",
+ "referrer": '', // referrer (empty due to the Referrer Policy)
+ "type": "navigation-to-response"
+ },
+ "url": /uuid=EXECUTOR_UUID$/,
+ "type": "coop"
+ }
+ }
+ ]
+ ],
+ // Open a same-origin popup with no COOP (without reporting) and no COEP.
+ // Produces one report to this page (opener) endpoint.
+ // This verifies that the navigated-to-document's COOP report values do not
+ // impact the navigated-from-document's COOP.
+ [
+ SAME_ORIGIN,
+ "unsafe-none",
+ "",
+ "",
+ "",
+ [
+ {
+ "endpoint": reportEndpoint,
+ "report": {
+ "body": {
+ "disposition": "enforce",
+ "effectivePolicy": "same-origin",
+ "nextResponseURL": /uuid=EXECUTOR_UUID$/,
+ "type": "navigation-from-response"
+ },
+ "url": `${location.href}`,
+ "type": "coop"
+ }
+ }
+ ]
+ ]
+];
+
+runNavigationReportingTests(document.title, tests);
+
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-popup-same-origin-report-to.https.html.sub.headers b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-popup-same-origin-report-to.https.html.sub.headers
new file mode 100644
index 0000000000..79c851a86c
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-popup-same-origin-report-to.https.html.sub.headers
@@ -0,0 +1,3 @@
+Reporting-Endpoints: coop-report-endpoint="https://{{host}}:{{ports[https][0]}}/reporting/resources/report.py?reportID=6aad9729-8642-4894-91d9-a4d44707cd4a", coop-report-only-endpoint="https://{{host}}:{{ports[https][0]}}/reporting/resources/report.py?reportID=69eb1838-6a03-4cda-97b0-c126ffcb9e8a"
+Cross-Origin-Opener-Policy: same-origin; report-to="coop-report-endpoint"
+Referrer-Policy: no-referrer
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-popup-same-origin.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-popup-same-origin.https.html
new file mode 100644
index 0000000000..3a8f343f37
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-popup-same-origin.https.html
@@ -0,0 +1,110 @@
+<meta name=timeout content=long>
+<title>reporting same origin</title>
+<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="/common/dispatcher/dispatcher.js"></script>
+<script src="/html/cross-origin-opener-policy/resources/common.js"></script>
+<script src="/html/cross-origin-opener-policy/reporting/resources/reporting-common.js"></script>
+
+<script>
+
+let tests = [
+ // popup origin, popup COOP, popup COEP, popup COOP report only, popup COEP report only, expected reports
+
+ // Open a cross-origin popup with a same-origin COOP and no COEP. COOP
+ // switches the browsing context group and hence produces one report.
+ // This test verifies that the navigated to document properly sends a
+ // navigation-to report. The navigationURI is the referrer.
+ [
+ CROSS_ORIGIN,
+ `same-origin; report-to="${popupReportEndpoint.name}"`,
+ "",
+ "",
+ "",
+ [
+ {
+ "endpoint": popupReportEndpoint,
+ "report": {
+ "body": {
+ "disposition": "enforce",
+ "effectivePolicy": "same-origin",
+ "previousResponseURL": "",
+ "referrer": `${location.origin}/`, // referrer
+ "type": "navigation-to-response"
+ },
+ "url": /uuid=EXECUTOR_UUID$/,
+ "type": "coop"
+ }
+ }
+ ]
+ ],
+ // Open a same-origin popup with a unsafe-none COOP and no COEP. COOP switches
+ // the browsing context group and hence produces one report.
+ // This test verifies that having different policies on same origin documents
+ // still properly produces report to the navigated-to-document.
+ [
+ SAME_ORIGIN,
+ `unsafe-none; report-to="${popupReportEndpoint.name}"`,
+ "",
+ "",
+ "",
+ [
+ {
+ "endpoint": popupReportEndpoint,
+ "report": {
+ "body": {
+ "disposition": "enforce",
+ "effectivePolicy": "unsafe-none",
+ "previousResponseURL": `${location.href}`,
+ "referrer": `${location.href}`, // referrer
+ "type": "navigation-to-response"
+ },
+ "url": /uuid=EXECUTOR_UUID$/,
+ "type": "coop"
+ }
+ }
+ ]
+ ],
+ // Open a cross-origin popup with a unsafe-none COOP (with reporting) and no
+ // COEP. COOP switches the browsing context group and hence produces one
+ // reports to the unsafe-none document. This test verifies that unsafe-none
+ // properly sends report in that configuration.
+ [
+ CROSS_ORIGIN,
+ `unsafe-none; report-to="${popupReportEndpoint.name}"`,
+ "",
+ "",
+ "",
+ [
+ {
+ "endpoint": popupReportEndpoint,
+ "report": {
+ "body": {
+ "disposition": "enforce",
+ "previousResponseURL": "",
+ "referrer": `${location.origin}/`, // referrer
+ "type": "navigation-to-response"
+ },
+ "url": /uuid=EXECUTOR_UUID$/,
+ "type": "coop"
+ }
+ }
+ ]
+ ],
+ // Open a same-origin popup with a same-origin COOP Report only value, the
+ // report only matches the previous document COOP value, no report is sent.
+ [
+ SAME_ORIGIN,
+ "",
+ "",
+ `same-origin; report-to="${popupReportOnlyEndpoint.name}"`,
+ "",
+ []
+ ],
+];
+
+runNavigationReportingTests(document.title, tests);
+
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-popup-same-origin.https.html.headers b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-popup-same-origin.https.html.headers
new file mode 100644
index 0000000000..46ad58d83b
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-popup-same-origin.https.html.headers
@@ -0,0 +1 @@
+Cross-Origin-Opener-Policy: same-origin
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-popup-unsafe-none-report-to.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-popup-unsafe-none-report-to.https.html
new file mode 100644
index 0000000000..2563dbb01f
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-popup-unsafe-none-report-to.https.html
@@ -0,0 +1,126 @@
+<meta name=timeout content=long>
+<title>reporting same origin with report-to</title>
+<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="/common/dispatcher/dispatcher.js"></script>
+<script src="/html/cross-origin-opener-policy/resources/common.js"></script>
+<script
+ src="/html/cross-origin-opener-policy/reporting/resources/reporting-common.js?pipe=sub&report_id=1f79b0d5-c2a2-4e0b-8e8c-651af2321964&report_only_id=c50700c8-db1e-4224-b06f-4c6a95a5f4be"></script>
+
+<script>
+
+let tests = [
+ // popup origin, popup COOP, popup COEP, popup COOP report only, popup COEP report only, expected reports
+
+ // Open a same-origin popup with a same-origin COOP with reporting and no COEP.
+ // COOP switches the browsing context group and hence produces two reports
+ // (one from and one to). This test verifies that unsafe-none (from the opener)
+ // properly sends a report.
+ [
+ SAME_ORIGIN,
+ `same-origin; report-to="${popupReportEndpoint.name}"`,
+ "",
+ "",
+ "",
+ [
+ {
+ "endpoint": reportEndpoint,
+ "report": {
+ "body": {
+ "disposition": "enforce",
+ "effectivePolicy": "unsafe-none",
+ "nextResponseURL": /uuid=EXECUTOR_UUID$/, // next document URL
+ "type": "navigation-from-response"
+ },
+ "url": `${location.href}`,
+ "type": "coop"
+ }
+ },
+ {
+ "endpoint": popupReportEndpoint,
+ "report": {
+ "body": {
+ "disposition": "enforce",
+ "effectivePolicy": "same-origin",
+ "previousResponseURL": `${location.href}`, // previous document url
+ "referrer": `${location.href}`, // referrer
+ "type": "navigation-to-response"
+ },
+ "url": /uuid=EXECUTOR_UUID$/,
+ "type": "coop"
+ }
+ }
+ ]
+ ],
+ // Open a same-origin popup with a same-origin COOP (no reporting)and no COEP.
+ // COOP switches the browsing context group and hence produces one report for
+ // the navigated from document (this page, the opener). This test differs with
+ // the previous one as it assert that the navigated to document's COOP reporting
+ // values do not interfere.
+ [
+ SAME_ORIGIN,
+ `same-origin`,
+ "",
+ "",
+ "",
+ [
+ {
+ "endpoint": reportEndpoint,
+ "report": {
+ "body": {
+ "disposition": "enforce",
+ "effectivePolicy": "unsafe-none",
+ "nextResponseURL": /uuid=EXECUTOR_UUID$/, // next document URL
+ "type": "navigation-from-response"
+ },
+ "url": `${location.href}`,
+ "type": "coop"
+ }
+ }
+ ]
+ ],
+ // Open a cross-origin popup with a same-origin COOP and no COEP. COOP switches
+ // the browsing context group and hence produces two reports.
+ [
+ CROSS_ORIGIN,
+ `same-origin; report-to="${popupReportEndpoint.name}"`,
+ "",
+ "",
+ "",
+ [
+ {
+ "endpoint": reportEndpoint,
+ "report": {
+ "body": {
+ "disposition": "enforce",
+ "effectivePolicy": "unsafe-none",
+ "nextResponseURL": /uuid=EXECUTOR_UUID$/, // next document URL
+ "type": "navigation-from-response"
+ },
+ "url": `${location.href}`,
+ "type": "coop"
+ }
+ },
+ {
+ "endpoint": popupReportEndpoint,
+ "report": {
+ "body": {
+ "disposition": "enforce",
+ "effectivePolicy": "same-origin",
+ "previousResponseURL": ``,
+ "referrer": `${location.origin}/`, // referrer
+ "type": "navigation-to-response"
+ },
+ "url": /uuid=EXECUTOR_UUID$/,
+ "type": "coop"
+ }
+ }
+ ]
+ ]
+];
+
+runNavigationReportingTests(document.title, tests);
+
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-popup-unsafe-none-report-to.https.html.sub.headers b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-popup-unsafe-none-report-to.https.html.sub.headers
new file mode 100644
index 0000000000..f1f18d6708
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-popup-unsafe-none-report-to.https.html.sub.headers
@@ -0,0 +1,2 @@
+Reporting-Endpoints: coop-report-endpoint="https://{{host}}:{{ports[https][0]}}/reporting/resources/report.py?reportID=1f79b0d5-c2a2-4e0b-8e8c-651af2321964", coop-report-only-endpoint="https://{{host}}:{{ports[https][0]}}/reporting/resources/report.py?reportID=c50700c8-db1e-4224-b06f-4c6a95a5f4be"
+Cross-Origin-Opener-Policy: unsafe-none; report-to="coop-report-endpoint"
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-redirect-with-same-origin-allow-popups.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-redirect-with-same-origin-allow-popups.https.html
new file mode 100644
index 0000000000..cd2f6b67b3
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/navigation-reporting/reporting-redirect-with-same-origin-allow-popups.https.html
@@ -0,0 +1,111 @@
+<title>
+ Tests the redirect interaction with COOP same-origin-allow-popups.
+</title>
+<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="/common/dispatcher/dispatcher.js"></script>
+<script src="/html/cross-origin-opener-policy/reporting/resources/reporting-common.js"></script>
+<script>
+
+const directory = "/html/cross-origin-opener-policy";
+const same_origin = {
+ host: get_host_info().HTTPS_ORIGIN,
+ name: "Same origin"
+};
+const cross_origin = {
+ host: get_host_info().HTTPS_REMOTE_ORIGIN,
+ name: "Cross origin"
+};
+
+// Tests the redirect interaction with COOP same-origin-allow-popups and
+// reporting:
+// 1 - open the opener document on origin same_origin with COOP
+// same-origin-allow-popups.
+// 2 - opener opens popup with document on origin popup_origin, no COOP and a
+// redirect header (HTTP 302, location).
+// 3 - redirection to a document with origin same_origin and COOP
+// same-origin-allow-popups.
+//
+// The navigation (2) to the first document of the popup stays in the same
+// browsing context group due to the same-origin-allow-popups COOP of the
+// opener.
+// The redirect (3) to the final document does since it compares the
+// popup_origin/unsafe-none document with the
+// same-origin/same-origin-allow-popups document.
+//
+// A opens B, B redirects to C.
+//
+// Document Origin COOP
+// -------- ------------ ------------------------
+// A same-origin same-origin-allow-popups
+// B popup-origin unsafe-none
+// C same-origin same-origin-allow-popups
+function redirect_test( popup_origin ) {
+ promise_test(async t => {
+ // The test window.
+ const this_window_token = token();
+
+ // The "opener" window. This has COOP same-origin-allow-popups and a
+ // reporter.
+ const opener_report_token = reportToken();
+ const opener_token = token();
+ const opener_reportTo = reportingEndpointsHeaders(opener_report_token);
+ const opener_url = same_origin.host + executor_path +
+ opener_reportTo.header + opener_reportTo.coopSameOriginAllowPopupsHeader +
+ `&uuid=${opener_token}`;
+
+ // The "openee" window.
+ // The initial document does not have COOP and is on popup_origin, it
+ // redirects to a same-origin (with the opener) document with COOP
+ // same-origin-allow-popups.
+ const openee_token = token();
+ const openee_redirect_url = same_origin.host + executor_path +
+ opener_reportTo.header + opener_reportTo.coopSameOriginAllowPopupsHeader +
+ `&uuid=${openee_token}`;
+ const redirect_header = 'status(302)' +
+ `|header(Location,${encodeURIComponent(
+ openee_redirect_url
+ .replace(/,/g, "\\,")
+ .replace(/\\\\,/g, "\\\\\\,")
+ .replace(/\(/g, "%28")
+ .replace(/\)/g, "%29"))})`;
+ const openee_url = popup_origin.host + executor_path + redirect_header +
+ `&uuid=${openee_token}`;
+ // 1. Create the opener window.
+ let opener_window_proxy = window.open(opener_url);
+ t.add_cleanup(() => send(opener_token, "window.close()"));
+
+ // 2. The opener opens its openee.
+ send(opener_token, `
+ openee = window.open("${openee_url}");
+ `);
+ t.add_cleanup(() => send(openee_token, "window.close()"));
+
+ // 3. Check the opener status on the openee.
+ send(openee_token, `
+ send("${this_window_token}", opener !== null);
+ `);
+ assert_equals(await receive(this_window_token), "false", "opener");
+
+ // 4. Check the openee status on the opener.
+ send(opener_token, `
+ send("${this_window_token}", openee.closed);
+ `);
+ assert_equals(await receive(this_window_token), "true", "openee.closed");
+
+ // 5. Check a report sent to the openee.
+ let report = await receiveReport(
+ opener_report_token,
+ "navigation-to-response");
+ assert_equals(report.type, "coop");
+ assert_equals(report.body.disposition, "enforce");
+ assert_equals(report.body.effectivePolicy, "same-origin-allow-popups");
+ }, `${popup_origin.name} openee redirected to same-origin with same-origin-allow-popups`);
+}
+
+redirect_test(same_origin);
+redirect_test(cross_origin);
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/resources/reporting-common.js b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/resources/reporting-common.js
new file mode 100644
index 0000000000..19f6410cbf
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/resources/reporting-common.js
@@ -0,0 +1,405 @@
+const executor_path = "/common/dispatcher/executor.html?pipe=";
+const coep_header = '|header(Cross-Origin-Embedder-Policy,require-corp)';
+
+// Report endpoint keys must start with a lower case alphabet character.
+// https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-header-structure-15#section-4.2.3.3
+const reportToken = () => {
+ return token().replace(/./, 'a');
+}
+
+const isWPTSubEnabled = "{{GET[pipe]}}".includes("sub");
+
+const getReportEndpointURL = (reportID) =>
+ `/reporting/resources/report.py?reportID=${reportID}`;
+
+const reportEndpoint = {
+ name: "coop-report-endpoint",
+ reportID: isWPTSubEnabled ? "{{GET[report_id]}}" : token(),
+ reports: []
+};
+const reportOnlyEndpoint = {
+ name: "coop-report-only-endpoint",
+ reportID: isWPTSubEnabled ? "{{GET[report_only_id]}}" : token(),
+ reports: []
+};
+const popupReportEndpoint = {
+ name: "coop-popup-report-endpoint",
+ reportID: token(),
+ reports: []
+};
+const popupReportOnlyEndpoint = {
+ name: "coop-popup-report-only-endpoint",
+ reportID: token(),
+ reports: []
+};
+const redirectReportEndpoint = {
+ name: "coop-redirect-report-endpoint",
+ reportID: token(),
+ reports: []
+};
+const redirectReportOnlyEndpoint = {
+ name: "coop-redirect-report-only-endpoint",
+ reportID: token(),
+ reports: []
+};
+
+const reportEndpoints = [
+ reportEndpoint,
+ reportOnlyEndpoint,
+ popupReportEndpoint,
+ popupReportOnlyEndpoint,
+ redirectReportEndpoint,
+ redirectReportOnlyEndpoint
+];
+
+// Allows RegExps to be pretty printed when printing unmatched expected reports.
+Object.defineProperty(RegExp.prototype, "toJSON", {
+ value: RegExp.prototype.toString
+});
+
+function wait(ms) {
+ return new Promise(resolve => step_timeout(resolve, ms));
+}
+
+// Check whether a |report| is a "opener breakage" COOP report.
+function isCoopOpenerBreakageReport(report) {
+ if (report.type != "coop")
+ return false;
+
+ if (report.body.type != "navigation-from-response" &&
+ report.body.type != "navigation-to-response") {
+ return false;
+ }
+
+ return true;
+}
+
+async function clearReportsOnServer(host) {
+ const res = await fetch(
+ '/reporting/resources/report.py', {
+ method: "POST",
+ body: JSON.stringify({
+ op: "DELETE",
+ reportIDs: reportEndpoints.map(endpoint => endpoint.reportID)
+ })
+ });
+ assert_equals(res.status, 200, "reports cleared");
+}
+
+async function pollReports(endpoint) {
+ const res = await fetch(getReportEndpointURL(endpoint.reportID),
+ { cache: 'no-store' });
+ if (res.status !== 200) {
+ return;
+ }
+ for (const report of await res.json()) {
+ if (isCoopOpenerBreakageReport(report))
+ endpoint.reports.push(report);
+ }
+}
+
+// Recursively check that all members of expectedReport are present or matched
+// in report.
+// Report may have members not explicitly expected by expectedReport.
+function isObjectAsExpected(report, expectedReport) {
+ if (( report === undefined || report === null
+ || expectedReport === undefined || expectedReport === null )
+ && report !== expectedReport ) {
+ return false;
+ }
+ if (expectedReport instanceof RegExp && typeof report === "string") {
+ return expectedReport.test(report);
+ }
+ // Perform this check now, as RegExp and strings above have different typeof.
+ if (typeof report !== typeof expectedReport)
+ return false;
+ if (typeof expectedReport === 'object') {
+ return Object.keys(expectedReport).every(key => {
+ return isObjectAsExpected(report[key], expectedReport[key]);
+ });
+ }
+ return report == expectedReport;
+}
+
+async function checkForExpectedReport(expectedReport) {
+ return new Promise( async (resolve, reject) => {
+ const polls = 20;
+ const waitTime = 200;
+ for (var i=0; i < polls; ++i) {
+ pollReports(expectedReport.endpoint);
+ for (var j=0; j<expectedReport.endpoint.reports.length; ++j){
+ if (isObjectAsExpected(expectedReport.endpoint.reports[j],
+ expectedReport.report)){
+ expectedReport.endpoint.reports.splice(j,1);
+ resolve();
+ return;
+ }
+ };
+ await wait(waitTime);
+ }
+ reject(
+ replaceTokensInReceivedReport(
+ "No report matched the expected report for endpoint: "
+ + expectedReport.endpoint.name
+ + ", expected report: " + JSON.stringify(expectedReport.report)
+ + ", within available reports: "
+ + JSON.stringify(expectedReport.endpoint.reports)
+ ));
+ });
+}
+
+function replaceFromRegexOrString(str, match, value) {
+ if (str instanceof RegExp) {
+ return RegExp(str.source.replace(match, value));
+ }
+ return str.replace(match, value);
+}
+
+// Replace generated values in regexes and strings of an expected report:
+// EXECUTOR_UUID: the uuid generated with token().
+function replaceValuesInExpectedReport(expectedReport, executorUuid) {
+ if (expectedReport.report.body !== undefined) {
+ if (expectedReport.report.body.nextResponseURL !== undefined) {
+ expectedReport.report.body.nextResponseURL = replaceFromRegexOrString(
+ expectedReport.report.body.nextResponseURL, "EXECUTOR_UUID",
+ executorUuid);
+ }
+ if (expectedReport.report.body.previousResponseURL !== undefined) {
+ expectedReport.report.body.previousResponseURL = replaceFromRegexOrString(
+ expectedReport.report.body.previousResponseURL, "EXECUTOR_UUID",
+ executorUuid);
+ }
+ if (expectedReport.report.body.referrer !== undefined) {
+ expectedReport.report.body.referrer = replaceFromRegexOrString(
+ expectedReport.report.body.referrer, "EXECUTOR_UUID",
+ executorUuid);
+ }
+ }
+ if (expectedReport.report.url !== undefined) {
+ expectedReport.report.url = replaceFromRegexOrString(
+ expectedReport.report.url, "EXECUTOR_UUID", executorUuid);
+ }
+ return expectedReport;
+}
+
+function replaceTokensInReceivedReport(str) {
+ return str.replace(/.{8}-.{4}-.{4}-.{4}-.{12}/g, `(uuid)`);
+}
+
+// Run a test then check that all expected reports are present.
+async function reportingTest(testFunction, executorToken, expectedReports) {
+ await new Promise(testFunction);
+ expectedReports = Array.from(
+ expectedReports,
+ report => replaceValuesInExpectedReport(report, executorToken) );
+ await Promise.all(Array.from(expectedReports, checkForExpectedReport));
+}
+
+function convertToWPTHeaderPipe([name, value]) {
+ return `header(${name}, ${encodeURIComponent(value)})`;
+}
+
+function getReportToHeader(host) {
+ return [
+ "Report-To",
+ reportEndpoints.map(
+ reportEndpoint => {
+ const reportToJSON = {
+ 'group': `${reportEndpoint.name}`,
+ 'max_age': 3600,
+ 'endpoints': [{
+ 'url': `${host}${getReportEndpointURL(reportEndpoint.reportID)}`
+ }]
+ };
+ // Escape comma as required by wpt pipes.
+ return JSON.stringify(reportToJSON)
+ .replace(/,/g, '\\,')
+ .replace(/\(/g, '\\\(')
+ .replace(/\)/g, '\\\)=');
+ }
+ ).join("\\, ")];
+}
+
+function getReportingEndpointsHeader(host) {
+ return [
+ "Reporting-Endpoints",
+ reportEndpoints.map(reportEndpoint => {
+ return `${reportEndpoint.name}="${host}${getReportEndpointURL(reportEndpoint.reportID)}"`;
+ }).join("\\, ")];
+}
+
+// Return Report and Report-Only policy headers.
+function getPolicyHeaders(coop, coep, coopRo, coepRo) {
+ return [
+ [`Cross-Origin-Opener-Policy`, coop],
+ [`Cross-Origin-Embedder-Policy`, coep],
+ [`Cross-Origin-Opener-Policy-Report-Only`, coopRo],
+ [`Cross-Origin-Embedder-Policy-Report-Only`, coepRo]];
+}
+
+function navigationReportingTest(testName, host, coop, coep, coopRo, coepRo,
+ expectedReports) {
+ const executorToken = token();
+ const callbackToken = token();
+ promise_test(async t => {
+ await reportingTest(async resolve => {
+ const openee_headers = [
+ getReportingEndpointsHeader(host.origin),
+ ...getPolicyHeaders(coop, coep, coopRo, coepRo)
+ ].map(convertToWPTHeaderPipe);
+ const openee_url = host.origin + executor_path +
+ openee_headers.join('|') + `&uuid=${executorToken}`;
+ const openee = window.open(openee_url);
+ const uuid = token();
+ t.add_cleanup(() => send(uuid, "window.close()"));
+
+ // 1. Make sure the new document is loaded.
+ send(executorToken, `
+ send("${callbackToken}", "Ready");
+ `);
+ let reply = await receive(callbackToken);
+ assert_equals(reply, "Ready");
+ resolve();
+ }, executorToken, expectedReports);
+ }, `coop reporting test ${testName} to ${host.name} with ${coop}, ${coep}, ${coopRo}, ${coepRo}`);
+}
+
+function navigationDocumentReportingTest(testName, host, coop, coep, coopRo,
+ coepRo, expectedReports) {
+ const executorToken = token();
+ const callbackToken = token();
+ promise_test(async t => {
+ const openee_headers = [
+ getReportingEndpointsHeader(host.origin),
+ ...getPolicyHeaders(coop, coep, coopRo, coepRo)
+ ].map(convertToWPTHeaderPipe);
+ const openee_url = host.origin + executor_path +
+ openee_headers.join('|') + `&uuid=${executorToken}`;
+ window.open(openee_url);
+ t.add_cleanup(() => send(executorToken, "window.close()"));
+ // Have openee window send a message through dispatcher, once we receive
+ // the Ready message from dispatcher it means the openee is fully loaded.
+ send(executorToken, `
+ send("${callbackToken}", "Ready");
+ `);
+ let reply = await receive(callbackToken);
+ assert_equals(reply, "Ready");
+
+ await wait(1000);
+
+ expectedReports = expectedReports.map(
+ (report) => replaceValuesInExpectedReport(report, executorToken));
+ return Promise.all(expectedReports.map(
+ async ({ endpoint, report: expectedReport }) => {
+ await pollReports(endpoint);
+ for (let report of endpoint.reports) {
+ assert_true(isObjectAsExpected(report, expectedReport),
+ `report received for endpoint: ${endpoint.name} ${JSON.stringify(report)} should match ${JSON.stringify(expectedReport)}`);
+ }
+ assert_equals(endpoint.reports.length, 1, `has exactly one report for ${endpoint.name}`)
+ }));
+ }, `coop document reporting test ${testName} to ${host.name} with ${coop}, ${coep}, ${coopRo}, ${coepRo}`);
+}
+
+// Run an array of reporting tests then verify there's no reports that were not
+// expected.
+// Tests' elements contain: host, coop, coep, coop-report-only,
+// coep-report-only, expectedReports.
+// See isObjectAsExpected for explanations regarding the matching behavior.
+async function runNavigationReportingTests(testName, tests) {
+ await clearReportsOnServer();
+ tests.forEach(test => {
+ navigationReportingTest(testName, ...test);
+ });
+ verifyRemainingReports();
+}
+
+// Run an array of reporting tests using Reporting-Endpoints header then
+// verify there's no reports that were not expected.
+// Tests' elements contain: host, coop, coep, coop-report-only,
+// coep-report-only, expectedReports.
+// See isObjectAsExpected for explanations regarding the matching behavior.
+function runNavigationDocumentReportingTests(testName, tests) {
+ clearReportsOnServer();
+ tests.forEach(test => {
+ navigationDocumentReportingTest(testName, ...test);
+ });
+}
+
+function verifyRemainingReports() {
+ promise_test(t => {
+ return Promise.all(reportEndpoints.map(async (endpoint) => {
+ await pollReports(endpoint);
+ assert_equals(endpoint.reports.length, 0, `${endpoint.name} should be empty`);
+ }));
+ }, "verify remaining reports");
+}
+
+const receiveReport = async function(uuid, type) {
+ while(true) {
+ let reports = await Promise.race([
+ receive(uuid),
+ new Promise(resolve => {
+ step_timeout(resolve, 1000, "timeout");
+ })
+ ]);
+ if (reports == "timeout")
+ return "timeout";
+ reports = JSON.parse(reports);
+ for(report of reports) {
+ if (report?.body?.type == type)
+ return report;
+ }
+ }
+}
+
+// Build a set of 'Cross-Origin-Opener-Policy' and
+// 'Cross-Origin-Opener-Policy-Report-Only' headers.
+const coopHeaders = function (uuid) {
+ return {
+ coopSameOriginHeader: `|header(Cross-Origin-Opener-Policy,same-origin%3Breport-to="${uuid}")`,
+ coopSameOriginAllowPopupsHeader: `|header(Cross-Origin-Opener-Policy,same-origin-allow-popups%3Breport-to="${uuid}")`,
+ coopReportOnlySameOriginHeader: `|header(Cross-Origin-Opener-Policy-Report-Only,same-origin%3Breport-to="${uuid}")`,
+ coopReportOnlySameOriginAllowPopupsHeader: `|header(Cross-Origin-Opener-Policy-Report-Only,same-origin-allow-popups%3Breport-to="${uuid}")`
+ };
+}
+
+// Build a set of headers to tests the reporting API. This defines a set of
+// matching 'Report-To', 'Cross-Origin-Opener-Policy' and
+// 'Cross-Origin-Opener-Policy-Report-Only' headers.
+const reportToHeaders = function(uuid) {
+ const report_endpoint_url = dispatcher_path + `?uuid=${uuid}`;
+ let reportToJSON = {
+ 'group': `${uuid}`,
+ 'max_age': 3600,
+ 'endpoints': [
+ {'url': report_endpoint_url.toString()},
+ ]
+ };
+ reportToJSON = JSON.stringify(reportToJSON)
+ .replace(/,/g, '\\,')
+ .replace(/\(/g, '\\\(')
+ .replace(/\)/g, '\\\)=');
+
+ return {
+ header: `|header(report-to,${reportToJSON})`,
+ ...coopHeaders(uuid)
+ };
+};
+
+// Build a set of headers to tests the reporting API. This defines a set of
+// matching 'Reporting-Endpoints', 'Cross-Origin-Opener-Policy' and
+// 'Cross-Origin-Opener-Policy-Report-Only' headers.
+const reportingEndpointsHeaders = function (uuid) {
+ // Report endpoint keys must start with a lower case alphabet:
+ // https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-header-structure-15#section-4.2.3.3
+ assert_true(uuid.match(/^[a-z].*/) != null, 'Use reportToken() instead.');
+
+ const report_endpoint_url = dispatcher_path + `?uuid=${uuid}`;
+ const reporting_endpoints_header = `${uuid}="${report_endpoint_url}"`;
+
+ return {
+ header: `|header(Reporting-Endpoints,${reporting_endpoints_header})`,
+ ...coopHeaders(uuid)
+ };
+};
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/resources/test-access-property.js b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/resources/test-access-property.js
new file mode 100644
index 0000000000..fe01e9128c
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/resources/test-access-property.js
@@ -0,0 +1,57 @@
+const same_origin = get_host_info().HTTPS_ORIGIN;
+const cross_origin = get_host_info().HTTPS_REMOTE_ORIGIN;
+
+const origin = [
+ ["same-origin" , same_origin ],
+ ["cross-origin", cross_origin],
+];
+let escapeComma = url => url.replace(/,/g, '\\,');
+
+let testAccessProperty = (property, op, expectReport = true) => {
+ origin.forEach(([origin_name, origin]) => {
+ promise_test(async t => {
+ const this_window_token = token();
+
+ // The opener window:
+ const opener_token = token();
+ const opener_url = get_host_info().HTTP_ORIGIN + executor_path +
+ `&uuid=${opener_token}`;
+
+ // The openee window:
+ const openee_token = token();
+ const openee_report_token = token();
+ const openee_report_to = reportToHeaders(openee_report_token);
+ const openee_url = origin + executor_path + openee_report_to.header +
+ openee_report_to.coopReportOnlySameOriginHeader + coep_header +
+ `&uuid=${openee_token}`;
+
+ t.add_cleanup(() => {
+ send(opener_token, "window.close()")
+ send(openee_token, "window.close()")
+ });
+
+ // Open the two windows. Wait for them to be loaded.
+ window.open(opener_url);
+ send(opener_token, `
+ window.openee = window.open('${escapeComma(openee_url)}');
+ `);
+ send(openee_token, `send("${this_window_token}", "Ready");`);
+ assert_equals(await receive(this_window_token), "Ready");
+
+ // 2. Try to access the openee.
+ send(opener_token, `(${op})(openee);`);
+
+ // 3. Fetch reports sent to the openee.
+ let report = await receiveReport(openee_report_token,
+ "access-to-coop-page-from-opener");
+ if (expectReport) {
+ assert_equals(report.body.property, property);
+ } else {
+ // "timeout" should be returned if no such reports are received.
+ assert_equals(report, "timeout");
+ }
+
+
+ }, `${origin_name} > ${op}`);
+ })
+};
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/resources/try-access.js b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/resources/try-access.js
new file mode 100644
index 0000000000..a06cb07904
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/reporting/resources/try-access.js
@@ -0,0 +1,20 @@
+// A function trying to access to |w| through a "CrossOrigin" attribute (blur).
+// This function is kept in its own file to ensure the source location of the
+// call stays constant.
+function tryAccess(w) {
+ try {
+ w.blur();
+ } catch(e) {}
+}
+
+function assert_source_location_found(report) {
+ assert_true(report.body.sourceFile.includes("try-access.js"));
+ assert_equals(report.body.lineNumber, 6);
+ assert_equals(report.body.columnNumber, 7);
+}
+
+function assert_source_location_missing(report) {
+ assert_equals(report.body.sourceFile, undefined);
+ assert_equals(report.body.lineNumber, undefined);
+ assert_equals(report.body.columnNumber, undefined);
+}
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/resource-popup.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/resource-popup.https.html
new file mode 100644
index 0000000000..481cceb72f
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/resource-popup.https.html
@@ -0,0 +1,91 @@
+<!DOCTYPE html>
+<html lang="en">
+<meta charset="utf-8">
+<title>Cross-Origin-Opener-Policy forces browsing context switch in various popup document types</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/utils.js"></script>
+
+<p>These tests create a "parent" popup window which is an HTML document with a
+specific Cross-Origin-Opener-Policy. The parent creates a "child" popup window
+which is a non-HTML document with a Cross-Origin-Opener-Policy of its own. The
+parent waits for the child's location to change from "<code>about:blank</code>"
+and then inspects its <code>name</code> and <code>closed</code> properties
+which it reports back to the test context.</p>
+
+<p>The HTTP `Refresh` header is used to ensure the child eventually closes
+itself (since proper observance of COOP will prevent the parent from closing
+the child in some cases).</p>
+
+<script>
+'use strict';
+
+const coop_resource_test = ({parentCoop, resourceCoop, resource, resourceName, validate}) => {
+ async_test((t) => {
+ const bc = new BroadcastChannel(token());
+ bc.onmessage = t.step_func_done(({data}) => validate(data));
+ const childLocation = resource +
+ `?pipe=header(Refresh,2;url=/html/cross-origin-opener-policy/resources/resource-cleanup.html?channel=${bc.name})` +
+ (resourceCoop ? `|header(Cross-Origin-Opener-Policy,${resourceCoop})` : '');
+ const parentLocation = 'resources/resource-popup.html' +
+ `?channel_name=${bc.name}` +
+ `&resource=${encodeURIComponent(childLocation)}` +
+ `&resource_name=${resourceName}` +
+ (parentCoop ? `&pipe=header(Cross-Origin-Opener-Policy,${parentCoop})` : '');
+
+ open(parentLocation);
+
+ t.add_cleanup(() => {
+ // Close the "parent" popup and the "child" popup if it has already
+ // redirected to the HTML document.
+ bc.postMessage(null);
+ // Prepare to close the "child" popup in the case that it has not yet
+ // redirected to the the HTML document.
+ bc.onmessage = () => bc.postMessage(null);
+ });
+ }, `${resource} - parent COOP: "${parentCoop}"; child COOP: "${resourceCoop}"`);
+};
+
+const resources = [
+ '/common/dummy.xml',
+ '/images/red.png',
+ '/common/text-plain.txt',
+ '/media/2x2-green.mp4',
+];
+
+for (const resource of resources) {
+ coop_resource_test({
+ parentCoop: '',
+ resourceCoop: 'same-origin',
+ resource,
+ resourceName: 'foobar',
+ validate(data) {
+ assert_equals(data.name, null);
+ assert_equals(data.closed, true);
+ }
+ });
+
+ coop_resource_test({
+ parentCoop: 'same-origin',
+ resourceCoop: '',
+ resource,
+ resourceName: 'foobar',
+ validate(data) {
+ assert_equals(data.name, null);
+ assert_equals(data.closed, true);
+ }
+ });
+
+ coop_resource_test({
+ parentCoop: 'same-origin',
+ resourceCoop: 'same-origin',
+ resource,
+ resourceName: 'foobar',
+ validate(data) {
+ assert_equals(data.name, 'foobar');
+ assert_equals(data.closed, false);
+ }
+ });
+}
+</script>
+</html>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/resources/call-functionCalledByOpenee.html b/testing/web-platform/tests/html/cross-origin-opener-policy/resources/call-functionCalledByOpenee.html
new file mode 100644
index 0000000000..d0ff0b723e
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/resources/call-functionCalledByOpenee.html
@@ -0,0 +1,5 @@
+<!doctype html>
+<meta charset=utf-8>
+<script>
+window.opener.functionCalledByOpenee();
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/resources/common.js b/testing/web-platform/tests/html/cross-origin-opener-policy/resources/common.js
new file mode 100644
index 0000000000..a005cb8a20
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/resources/common.js
@@ -0,0 +1,86 @@
+// To use the functions below, be sure to include the following files in your
+// test:
+// - "/common/get-host-info.sub.js" to get the different origin values.
+
+const SAME_ORIGIN = {origin: get_host_info().HTTPS_ORIGIN, name: "SAME_ORIGIN"};
+const SAME_SITE = {origin: get_host_info().HTTPS_REMOTE_ORIGIN, name: "SAME_SITE"};
+const CROSS_ORIGIN = {origin: get_host_info().HTTPS_NOTSAMESITE_ORIGIN, name: "CROSS_ORIGIN"}
+
+function addScriptAndTriggerOnload(src, onload){
+ return `script = document.createElement("script");
+ script.src= "${src}" ;
+ script.onload = () => {
+ ${onload}
+ };
+ document.head.append(script);`
+}
+
+function verify_window(callback, w, hasOpener) {
+ // If there's no opener, the w must be closed:
+ assert_equals(w.closed, !hasOpener, 'w.closed');
+ // Opener's access on w.length is possible only if hasOpener:
+ assert_equals(w.length, hasOpener? 1: 0, 'w.length');
+ callback();
+}
+
+function validate_results(callback, test, w, channelName, hasOpener, openerDOMAccess, payload) {
+ assert_equals(payload.name, hasOpener ? channelName : "", 'name');
+ assert_equals(payload.opener, hasOpener, 'opener');
+ // TODO(zcorpan): add openerDOMAccess expectations to all tests
+ if (openerDOMAccess !== undefined) {
+ assert_equals(payload.openerDOMAccess, openerDOMAccess, 'openerDOMAccess');
+ }
+
+ // The window proxy in Chromium might still reflect the previous frame,
+ // until its unloaded. This delays the verification of w here.
+ if( !w.closed && w.length == 0) {
+ test.step_timeout( () => {
+ verify_window(callback, w, hasOpener);
+ }, 500);
+ } else {
+ verify_window(callback, w, hasOpener);
+ }
+}
+
+// Note: This function is deprecated and should not be used by new tests.
+// Instead, use `dispatcher_url_test()`.
+function url_test(t, url, channelName, hasOpener, openerDOMAccess, callback) {
+ if (callback === undefined) {
+ callback = () => { t.done(); };
+ }
+ const bc = new BroadcastChannel(channelName);
+ bc.onmessage = t.step_func(event => {
+ const payload = event.data;
+ validate_results(callback, t, w, channelName, hasOpener, openerDOMAccess, payload);
+ });
+
+ const w = window.open(url, channelName);
+
+ // Close the popup once the test is complete.
+ // The browsing context might be closed hence use the broadcast channel
+ // to trigger the closure.
+ t.add_cleanup(() => {
+ bc.postMessage("close");
+ });
+}
+
+// Similar to `url_test()` above except that this uses a dispatcher instead of
+// BroadcastChannel (useful in cases where the context we are testing in is a
+// third-party iframe that doesn't share a partition with the top-level
+// site).
+async function dispatcher_url_test(t, url, responseToken, iframeToken, hasOpener, openerDOMAccess, callback) {
+
+ const w = window.open(url, responseToken);
+
+ // Close the popup once the test is complete.
+ // The browsing context might be closed hence we'll have the iframe trigger
+ // the closure by sending it a 'close' message.
+ t.add_cleanup(async () => {
+ await send(iframeToken, "close");
+ });
+
+ var payload = await receive(responseToken);
+ payload = JSON.parse(payload);
+ validate_results(callback, t, w, responseToken, hasOpener, openerDOMAccess, payload);
+}
+
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/resources/coop-coep.py b/testing/web-platform/tests/html/cross-origin-opener-policy/resources/coop-coep.py
new file mode 100644
index 0000000000..d8e3bf0d42
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/resources/coop-coep.py
@@ -0,0 +1,84 @@
+import json
+
+def main(request, response):
+ requestData = request.GET
+ if request.method == u"POST":
+ requestData = request.POST
+
+ coop = requestData.first(b"coop")
+ coopReportOnly = requestData.first(b"coop-report-only", None)
+ coep = requestData.first(b"coep")
+ coepReportOnly = requestData.first(b"coep-report-only", None)
+ redirect = requestData.first(b"redirect", None)
+ if coop != b"":
+ response.headers.set(b"Cross-Origin-Opener-Policy", coop)
+ if coopReportOnly is not None:
+ response.headers.set(b"Cross-Origin-Opener-Policy-Report-Only", coopReportOnly)
+ if coep != b"":
+ response.headers.set(b"Cross-Origin-Embedder-Policy", coep)
+ if coepReportOnly is not None:
+ response.headers.set(b"Cross-Origin-Embedder-Policy-Report-Only", coepReportOnly)
+ if b'cache' in requestData:
+ response.headers.set(b'Cache-Control', b'max-age=3600')
+ host = request.url_parts[1]
+
+ if redirect != None:
+ response.status = 302
+ response.headers.set(b"Location", redirect)
+ return
+
+ # Collect relevant params to be visible to response JS
+ params = {}
+ for key in (b"navHistory", b"avoidBackAndForth", b"navigate", b"channel", b"responseToken", b"iframeToken"):
+ value = requestData.first(key, None)
+ params[key.decode()] = value and value.decode()
+
+ response.content = b"""
+<!doctype html>
+<meta charset=utf-8>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="/html/cross-origin-opener-policy/resources/fully-loaded.js"></script>
+<body>
+<script>
+ const params = %s;
+ const navHistory = params.navHistory;
+ const avoidBackAndForth = params.avoidBackAndForth;
+ const navigate = params.navigate;
+ if (navHistory !== null) {
+ fullyLoaded().then(() => {
+ history.go(Number(navHistory));
+ });
+ } else if (navigate !== null && (history.length === 1 || !avoidBackAndForth)) {
+ fullyLoaded().then(() => {
+ self.location = navigate;
+ });
+ } else {
+ let openerDOMAccessAllowed = false;
+ try {
+ openerDOMAccessAllowed = !!self.opener.document.URL;
+ } catch(ex) {
+ }
+ // Handle the response from the frame, closing the popup once the
+ // test completes.
+ addEventListener("message", event => {
+ if (event.data == "close") {
+ close();
+ }
+ });
+ iframe = document.createElement("iframe");
+ iframe.onload = () => {
+ const payload = { name: self.name, opener: !!self.opener, openerDOMAccess: openerDOMAccessAllowed };
+ iframe.contentWindow.postMessage(payload, "*");
+ };
+ const channelName = params.channel;
+ const responseToken = params.responseToken;
+ const iframeToken = params.iframeToken;
+ iframe.src = `${get_host_info().HTTPS_ORIGIN}/html/cross-origin-opener-policy/resources/postback.html` +
+ `?channel=${encodeURIComponent(channelName)}` +
+ `&responseToken=${responseToken}` +
+ `&iframeToken=${iframeToken}`;
+ document.body.appendChild(iframe);
+ }
+</script>
+</body>
+""" % json.dumps(params).encode("utf-8")
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/resources/coop-same-origin-repeated.asis b/testing/web-platform/tests/html/cross-origin-opener-policy/resources/coop-same-origin-repeated.asis
new file mode 100644
index 0000000000..082478e159
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/resources/coop-same-origin-repeated.asis
@@ -0,0 +1,24 @@
+HTTP/1.1 200 OK
+Cross-Origin-Opener-Policy: same-origin
+Cross-Origin-Opener-Policy: same-origin
+Server: BaseHTTP/0.3 Python/2.7.15+
+Date: Wed, 18 Dec 2019 00:47:08 GMT
+
+<!doctype html>
+<meta charset=utf-8>
+<script src="/common/get-host-info.sub.js"></script>
+<iframe></iframe>
+<script>
+ const navigate = new URL(location).searchParams.get("navigate");
+ if (navigate !== null) {
+ self.location = navigate;
+ } else {
+ const iframe = document.querySelector("iframe");
+ iframe.onload = () => {
+ const payload = { name: self.name, opener: !!self.opener };
+ iframe.contentWindow.postMessage(payload, "*");
+ };
+ const channelName = new URL(location).searchParams.get("channel");
+ iframe.src = `${get_host_info().HTTPS_ORIGIN}/html/cross-origin-opener-policy/resources/postback.html?channel=${channelName}`;
+ }
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/resources/csp-sandbox.py b/testing/web-platform/tests/html/cross-origin-opener-policy/resources/csp-sandbox.py
new file mode 100644
index 0000000000..6cf21aeccf
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/resources/csp-sandbox.py
@@ -0,0 +1,29 @@
+def main(request, response):
+ coop = request.GET.first(b"coop")
+ coep = request.GET.first(b"coep")
+ sandbox = request.GET.first(b"sandbox")
+ if coop != "":
+ response.headers.set(b"Cross-Origin-Opener-Policy", coop)
+ if coep != "":
+ response.headers.set(b"Cross-Origin-Embedder-Policy", coep)
+ response.headers.set(b"Content-Security-Policy", b"sandbox " + sandbox + b";")
+
+ # Open a popup to coop-coep.py with the same parameters (except sandbox)
+ response.content = b"""
+<!doctype html>
+<meta charset=utf-8>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="/html/cross-origin-opener-policy/resources/fully-loaded.js"></script>
+<script>
+ const params = new URL(location).searchParams;
+ params.delete("sandbox");
+ const navigate = params.get("navigate");
+ if (navigate) {
+ fullyLoaded().then(() => {
+ self.location = navigate;
+ });
+ } else {
+ window.open(`/html/cross-origin-opener-policy/resources/coop-coep.py?${params}`);
+ }
+</script>
+"""
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/resources/fully-loaded.js b/testing/web-platform/tests/html/cross-origin-opener-policy/resources/fully-loaded.js
new file mode 100644
index 0000000000..d40e00af43
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/resources/fully-loaded.js
@@ -0,0 +1,10 @@
+// Return a promise, which resolves when new navigations aren't considered
+// client-side redirects anymore.
+//
+// Note: A long `setTimeout` is used, because client-side redirect is an
+// heuristic and isn't clearly specified.
+function fullyLoaded() {
+ return new Promise((resolve, reject) => {
+ addEventListener('load', () => setTimeout(resolve, 2000))
+ });
+}
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/resources/iframe-test.js b/testing/web-platform/tests/html/cross-origin-opener-policy/resources/iframe-test.js
new file mode 100644
index 0000000000..a18688caf7
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/resources/iframe-test.js
@@ -0,0 +1,234 @@
+// To use the functions below, be sure to include the following files in your
+// test:
+// - "/common/get-host-info.sub.js" to get the different origin values.
+// - "common.js" to have the origins easily available.
+// - "/common/dispatcher/dispatcher.js" for cross-origin messaging.
+// - "/common/utils.js" for token().
+
+function getBaseExecutorPath(origin) {
+ return origin + '/common/dispatcher/executor.html';
+}
+
+function getHeadersPipe(headers) {
+ const coop_header = headers.coop ?
+ `|header(Cross-Origin-Opener-Policy,${encodeURIComponent(headers.coop)})` : '';
+ const coep_header = headers.coep ?
+ `|header(Cross-Origin-Embedder-Policy,${encodeURIComponent(headers.coep)})` : '';
+ return coop_header + coep_header;
+}
+
+function getExecutorPath(uuid, origin, headers) {
+ return getBaseExecutorPath(origin) +
+ `?uuid=${uuid}` +
+ `&pipe=${getHeadersPipe(headers)}`;
+}
+
+function evaluate(target_token, script) {
+ const reply_token = token();
+ send(target_token, `send('${reply_token}', ${script});`);
+ return receive(reply_token);
+}
+
+// Return true if an opened iframe can access |property| on a stored
+// window.popup object without throwing an error.
+function iframeCanAccessProperty(iframe_token, property) {
+ const reply_token = token();
+ send(iframe_token,
+ `try {
+ const unused = window.popup['${property}'];
+ send('${reply_token}', 'true')
+ } catch (errors) {
+ send('${reply_token}', 'false')
+ }`);
+ return receive(reply_token);
+}
+
+// Returns the script necessary to open a popup, given the method in
+// `popup_via`. Supported methods are 'window_open' that leverages
+// window.open(), 'anchor' that creates an <a> HTML element and clicks on it,
+// and 'form' that creates a form and submits it.
+function popupOpeningScript(popup_via, popup_url, popup_origin, headers,
+ popup_token) {
+ if (popup_via === 'window_open')
+ return `window.popup = window.open('${popup_url}', '${popup_token}');`;
+
+ if (popup_via === 'anchor') {
+ return `
+ const anchor = document.createElement('a');
+ anchor.href = '${popup_url}';
+ anchor.rel = "opener";
+ anchor.target = '${popup_token}';
+ anchor.innerText = "anchor";
+ document.body.appendChild(anchor);
+ anchor.click();
+ `;
+ }
+
+ if (popup_via === "form") {
+ return `
+ const form = document.createElement("form");
+ form.action = '${getBaseExecutorPath(popup_origin.origin)}';
+ form.target = '${popup_token}';
+ form.method = 'GET';
+ const add_param = (name, value) => {
+ const input = document.createElement("input");
+ input.name = name;
+ input.value = value;
+ form.appendChild(input);
+ };
+ add_param("uuid", "${popup_token}");
+ add_param("pipe", "${getHeadersPipe(headers)}");
+ document.body.appendChild(form);
+ form.submit();
+ `;
+ }
+
+ assert_not_reached('Unrecognized popup opening method.');
+}
+
+
+// Verifies that a popup with origin `popup_origin` and headers `headers` has
+// the expected `opener_state` after being opened from an iframe with origin
+// `iframe_origin`.
+function iframe_test(description, iframe_origin, popup_origin, headers,
+ expected_opener_state) {
+ for (const popup_via of ['window_open', 'anchor','form']) {
+ promise_test(async t => {
+ const iframe_token = token();
+ const popup_token = token();
+ const reply_token = token();
+
+ const frame = document.createElement("iframe");
+ const iframe_url = getExecutorPath(
+ iframe_token,
+ iframe_origin.origin,
+ {});
+
+ frame.src = iframe_url;
+ document.body.append(frame);
+
+ send(iframe_token, `send('${reply_token}', 'Iframe loaded');`);
+ assert_equals(await receive(reply_token), 'Iframe loaded');
+
+ const popup_url = getExecutorPath(
+ popup_token,
+ popup_origin.origin,
+ headers);
+
+ // We open popup and then ping it, it will respond after loading.
+ send(iframe_token, popupOpeningScript(popup_via, popup_url, popup_origin,
+ headers, popup_token));
+ send(popup_token, `send('${reply_token}', 'Popup loaded');`);
+ assert_equals(await receive(reply_token), 'Popup loaded');
+
+ // Make sure the popup and the iframe are removed once the test has run,
+ // keeping a clean state.
+ add_completion_callback(() => {
+ frame.remove();
+ send(popup_token, `close()`);
+ });
+
+ // Give some time for things to settle across processes etc. before
+ // proceeding with verifications.
+ await new Promise(resolve => { t.step_timeout(resolve, 500); });
+
+ // Verify that the opener is in the state we expect it to be in.
+ switch (expected_opener_state) {
+ case 'preserved': {
+ assert_equals(
+ await evaluate(popup_token, 'opener != null'), "true",
+ 'Popup has an opener?');
+ assert_equals(
+ await evaluate(popup_token, `name === '${popup_token}'`), "true",
+ 'Popup has a name?');
+
+ // When the popup was created using window.open, we've kept a handle
+ // and we can do extra verifications.
+ if (popup_via === 'window_open') {
+ assert_equals(
+ await evaluate(iframe_token, 'popup != null'), "true",
+ 'Popup handle is non-null in iframe?');
+ assert_equals(
+ await evaluate(iframe_token, 'popup.closed'), "false",
+ 'Popup appears closed from iframe?');
+ assert_equals(
+ await iframeCanAccessProperty(iframe_token, "document"),
+ popup_origin === iframe_origin ? "true" : "false",
+ 'Iframe has dom access to the popup?');
+ assert_equals(
+ await iframeCanAccessProperty(iframe_token, "frames"), "true",
+ 'Iframe has cross origin access to the popup?');
+ }
+ break;
+ }
+ case 'restricted': {
+ assert_equals(
+ await evaluate(popup_token, 'opener != null'), "true",
+ 'Popup has an opener?');
+ assert_equals(
+ await evaluate(popup_token, `name === '${popup_token}'`), "true",
+ 'Popup has a name?');
+
+ // When the popup was created using window.open, we've kept a handle
+ // and we can do extra verifications.
+ if (popup_via === 'window_open') {
+ assert_equals(
+ await evaluate(iframe_token, 'popup != null'), "true",
+ 'Popup handle is non-null in iframe?');
+ assert_equals(
+ await evaluate(iframe_token, 'popup.closed'), "false",
+ 'Popup appears closed from iframe?');
+ assert_equals(
+ await iframeCanAccessProperty(iframe_token, "document"), "false",
+ 'Iframe has dom access to the popup?');
+ assert_equals(
+ await iframeCanAccessProperty(iframe_token, "frames"), "false",
+ 'Iframe has cross origin access to the popup?');
+ assert_equals(
+ await iframeCanAccessProperty(iframe_token, "closed"), "true",
+ 'Iframe has limited cross origin access to the popup?');
+ }
+ break;
+ }
+ case 'severed': {
+ assert_equals(await evaluate(popup_token, 'opener != null'), "false",
+ 'Popup has an opener?');
+ assert_equals(
+ await evaluate(popup_token, `name === '${popup_token}'`), "false",
+ 'Popup has a name?');
+
+ // When the popup was created using window.open, we've kept a handle
+ // and we can do extra verifications.
+ if (popup_via === 'window_open') {
+ assert_equals(
+ await evaluate(iframe_token, 'popup != null'), "true",
+ 'Popup handle is non-null in iframe?');
+ assert_equals(
+ await evaluate(iframe_token, 'popup.closed'), "true",
+ 'Popup appears closed from iframe?');
+ }
+ break;
+ }
+ case 'noopener': {
+ assert_equals(await evaluate(popup_token, 'opener != null'), "false",
+ 'Popup has an opener?');
+ assert_equals(
+ await evaluate(popup_token, `name === '${popup_token}'`), "false",
+ 'Popup has a name?');
+
+ // When the popup was created using window.open, we've kept a handle
+ // and we can do extra verifications.
+ if (popup_via === 'window_open') {
+ assert_equals(
+ await evaluate(iframe_token, 'popup == null'), "true",
+ 'Popup handle is null in iframe?');
+ }
+ break;
+ }
+ default:
+ assert_not_reached('Unrecognized opener state: ' +
+ expected_opener_state);
+ }
+ }, `${description} with ${popup_via}`);
+ }
+}
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/resources/popup-test.js b/testing/web-platform/tests/html/cross-origin-opener-policy/resources/popup-test.js
new file mode 100644
index 0000000000..c2717bb135
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/resources/popup-test.js
@@ -0,0 +1,99 @@
+// To use the functions below, be sure to include the following files in your
+// test:
+// - "/common/get-host-info.sub.js" to get the different origin values.
+// - "common.js" to have the origins easily available.
+// - "/common/dispatcher/dispatcher.js" for cross-origin messaging.
+// - "/common/utils.js" for token().
+
+function getExecutorPath(uuid, origin, headers) {
+ const executor_path = '/common/dispatcher/executor.html?';
+ const coop_header = headers.coop ?
+ `|header(Cross-Origin-Opener-Policy,${encodeURIComponent(headers.coop)})` : '';
+ const coep_header = headers.coep ?
+ `|header(Cross-Origin-Embedder-Policy,${encodeURIComponent(headers.coep)})` : '';
+ return origin +
+ executor_path +
+ `uuid=${uuid}` +
+ '&pipe=' + coop_header + coep_header;
+}
+
+function getPopupHasOpener(popup_token) {
+ const reply_token = token();
+ send(popup_token, `send('${reply_token}', window.opener != null);`);
+ return receive(reply_token);
+}
+
+// Return true if |object|.|property| can be called without throwing an error.
+function canAccessProperty(object, property) {
+ try {
+ const unused = object[property];
+ return true;
+ } catch (errors) {
+ return false;
+ }
+}
+
+// Verifies that a popup with origin `origin` and headers `headers` has
+// the expected `opener_state` after being opened.
+async function popup_test(description, origin, headers, expected_opener_state) {
+ promise_test(async t => {
+ const popup_token = token();
+ const reply_token = token();
+
+ const popup_url = getExecutorPath(
+ popup_token,
+ origin.origin,
+ headers);
+
+ // We open popup and then ping it, it will respond after loading.
+ const popup = window.open(popup_url);
+ send(popup_token, `send('${reply_token}', 'Popup loaded');`);
+ assert_equals(await receive(reply_token), 'Popup loaded');
+
+ // Make sure the popup will be closed once the test has run, keeping a clean
+ // state.
+ t.add_cleanup(() => {
+ send(popup_token, `close()`);
+ });
+
+ // Give some time for things to settle across processes etc. before
+ // proceeding with verifications.
+ await new Promise(resolve => { t.step_timeout(resolve, 500); });
+
+ // Verify that the opener is in the state we expect it to be in.
+ switch (expected_opener_state) {
+ case 'preserved': {
+ assert_false(popup.closed, 'Popup is closed from opener?');
+ assert_true(await getPopupHasOpener(popup_token) === "true",
+ 'Popup has nulled opener?');
+ assert_equals(canAccessProperty(popup, "document"),
+ origin === SAME_ORIGIN,
+ 'Main page has dom access to the popup?');
+ assert_true(canAccessProperty(popup, "frames"),
+ 'Main page has cross origin access to the popup?');
+ break;
+ }
+ case 'restricted': {
+ assert_false(popup.closed, 'Popup is closed from opener?');
+ assert_true(await getPopupHasOpener(popup_token) === "true",
+ 'Popup has nulled opener?');
+ assert_false(canAccessProperty(popup, "document"),
+ 'Main page has dom access to the popup?');
+ assert_false(canAccessProperty(popup, "frames"),
+ 'Main page has cross origin access to the popup?');
+ assert_true(canAccessProperty(popup, "closed"),
+ 'Main page has limited cross origin access to the popup?');
+ break;
+ }
+ case 'severed': {
+ assert_true(popup.closed, 'Popup is closed from opener?');
+ assert_false(await getPopupHasOpener(popup_token) === "true",
+ 'Popup has nulled opener?');
+ break;
+ }
+ default:
+ assert_unreached(true, "Unrecognized opener relationship: " + expected_opener_state);
+ }
+ }, description);
+}
+
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/resources/postback.html b/testing/web-platform/tests/html/cross-origin-opener-policy/resources/postback.html
new file mode 100644
index 0000000000..35b3be5c93
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/resources/postback.html
@@ -0,0 +1,45 @@
+<!doctype html>
+<meta charset=utf-8>
+<script src="/common/dispatcher/dispatcher.js"></script>
+<script>
+const params = new URL(location).searchParams;
+const channelName = params.get("channel");
+const responseToken = params.get("responseToken");
+const iframeToken = params.get("iframeToken");
+
+// If the channel parameter is set, use the BroadcastChannel-based communication
+// method. Otherwise, use the dispatcher (useful in cases where this is embedded
+// in a third-party iframe that doesn't share a partition with the top-level
+// site).
+if (channelName != "null") {
+ const bc = new BroadcastChannel(channelName);
+ // Handle the close message from the test-cleanup, forwarding it to the
+ // top level document, as this iframe and the opening document might not
+ // be able to close the popup.
+ bc.onmessage = event => {
+ if (event.data == "close") {
+ top.postMessage("close", "*");
+ }
+ };
+
+ window.addEventListener("message", event => {
+ bc.postMessage(event.data);
+ });
+
+} else {
+ window.addEventListener("message", event => {
+ send(responseToken, JSON.stringify(event.data));
+ });
+
+ async function waitToClose() {
+ response = await receive(iframeToken);
+ // Handle the close message from the test-cleanup, forwarding it to the
+ // top level document, as this iframe and the opening document might not
+ // be able to close the popup.
+ if (response == "close") {
+ top.postMessage("close", "*");
+ }
+ }
+ waitToClose();
+}
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/resources/postback.html.headers b/testing/web-platform/tests/html/cross-origin-opener-policy/resources/postback.html.headers
new file mode 100644
index 0000000000..4e798cd9f5
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/resources/postback.html.headers
@@ -0,0 +1,2 @@
+Cross-Origin-Embedder-Policy: require-corp
+Cross-Origin-Resource-Policy: cross-origin
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/resources/redirect.py b/testing/web-platform/tests/html/cross-origin-opener-policy/resources/redirect.py
new file mode 100644
index 0000000000..88dbd60fae
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/resources/redirect.py
@@ -0,0 +1,5 @@
+from wptserve.utils import isomorphic_encode
+
+def main(request, response):
+ response.status = 302
+ response.headers.set(b"Location", isomorphic_encode(request.url[request.url.find(u'?')+1:]))
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/resources/resource-cleanup.html b/testing/web-platform/tests/html/cross-origin-opener-policy/resources/resource-cleanup.html
new file mode 100644
index 0000000000..3ae5587c7d
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/resources/resource-cleanup.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html lang="en">
+<meta charset="utf-8">
+<title>Redirect destination for non-HTML documents to close themselves</title>
+<script>
+'use strict';
+const channel = new URL(location).searchParams.get('channel');
+const bc = new BroadcastChannel(channel);
+bc.onmessage = () => close();
+bc.postMessage({name: 'FAIL', closed: 'FAIL' });
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/resources/resource-popup.html b/testing/web-platform/tests/html/cross-origin-opener-policy/resources/resource-popup.html
new file mode 100644
index 0000000000..2957e35f59
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/resources/resource-popup.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html lang="en">
+<meta charset="utf-8">
+<title></title>
+<script>
+'use strict';
+const params = new URL(location).searchParams;
+const bc = new BroadcastChannel(params.get('channel_name'));
+const win = open(params.get('resource'), params.get('resource_name'));
+
+bc.onmessage = () => {
+ win.close();
+ close();
+};
+const id = setInterval(() => {
+ if (win.closed || win.location.href !== 'about:blank') {
+ clearInterval(id);
+ bc.postMessage({name: win.name || null, closed: win.closed});
+ }
+}, 100);
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/resources/universal-worker.js b/testing/web-platform/tests/html/cross-origin-opener-policy/resources/universal-worker.js
new file mode 100644
index 0000000000..2441679372
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/resources/universal-worker.js
@@ -0,0 +1,2 @@
+onmessage = message => eval(message.data);
+onfetch = event => fetchHandler(event);
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/README.md b/testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/README.md
new file mode 100644
index 0000000000..b3c24c3f82
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/README.md
@@ -0,0 +1,9 @@
+Because this test suite is run as a virtual suite and it's quite deep in the
+folders, we have to use abbreviations for the test names to not run over 200
+characters, which is problematic on Windows.
+
+* unspecified -> "u"
+* unsafe-none -> "un"
+* same-origin -> "so"
+* same-origin-allow-popups -> "soap"
+* restrict-properties -> omitted
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/coop-rp-in-navigation-chain.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/coop-rp-in-navigation-chain.https.html
new file mode 100644
index 0000000000..e5c8775174
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/coop-rp-in-navigation-chain.https.html
@@ -0,0 +1,65 @@
+<!doctype html>
+<meta charset=utf-8>
+<meta name=timeout content=long>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src="/common/dispatcher/dispatcher.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="/common/utils.js"></script>
+<script src="../../resources/common.js"></script>
+<script src="../../resources/popup-test.js"></script>
+<script>
+
+promise_test(async t => {
+ const popup_token = token();
+ const second_popup_token = token();
+ const reply_token = token();
+
+ const unsafe_none_url = getExecutorPath(
+ popup_token,
+ SAME_ORIGIN.origin,
+ { coop: "unsafe-none"});
+
+ const restrict_properties_url = getExecutorPath(
+ second_popup_token,
+ SAME_ORIGIN.origin,
+ { coop: "restrict-properties"});
+
+ // We open popup and then ping it, it will respond after loading.
+ const popup = window.open(unsafe_none_url);
+ send(popup_token, `send('${reply_token}', 'Popup loaded');`);
+ assert_equals(await receive(reply_token), 'Popup loaded');
+
+ // Make sure the popup will be closed once the test has run, keeping a clean
+ // state.
+ t.add_cleanup(() => {
+ send(popup_token, `close()`);
+ });
+
+ // Now navigate this popup to a restrict-properties page.
+ send(popup_token, `document.location = '${restrict_properties_url}'`);
+ send(second_popup_token, `send('${reply_token}', 'Popup loaded');`);
+ assert_equals(await receive(reply_token), 'Popup loaded');
+
+ // Navigate again to the original page.
+ send(second_popup_token, `document.location = '${unsafe_none_url}'`);
+ send(popup_token, `send('${reply_token}', 'Popup loaded');`);
+ assert_equals(await receive(reply_token), 'Popup loaded');
+
+ // Give some time for things to settle across processes etc. before
+ // proceeding with verifications.
+ await new Promise(resolve => { t.step_timeout(resolve, 500); });
+
+ // Verify that we have full access to the popup.
+ assert_false(popup.closed, 'Popup is closed from opener?');
+ assert_true(await getPopupHasOpener(popup_token) === "true",
+ 'Popup has nulled opener?');
+ assert_true(canAccessProperty(popup, "document"),
+ 'Main page has dom access to the popup?');
+ assert_true(canAccessProperty(popup, "frames"),
+ 'Main page has cross origin access to the popup?');
+
+}, "COOP: restrict-properties has no impact in a navigation chain between " +
+ "multiple unsafe-none pages.");
+
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/coop-rp-in-navigation-chain.https.html.headers b/testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/coop-rp-in-navigation-chain.https.html.headers
new file mode 100644
index 0000000000..073ce7adfb
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/coop-rp-in-navigation-chain.https.html.headers
@@ -0,0 +1 @@
+Cross-Origin-Opener-Policy: unsafe-none
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/iframe-popup-to-so.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/iframe-popup-to-so.https.html
new file mode 100644
index 0000000000..740ff2595a
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/iframe-popup-to-so.https.html
@@ -0,0 +1,90 @@
+<!doctype html>
+<meta charset=utf-8>
+<meta name=timeout content=long>
+<meta name="variant" content="?1-2">
+<meta name="variant" content="?3-4">
+<meta name="variant" content="?5-6">
+<meta name="variant" content="?7-8">
+<meta name="variant" content="?9-last">
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src=/common/dispatcher/dispatcher.js></script>
+<script src=/common/get-host-info.sub.js></script>
+<script src=/common/subset-tests.js></script>
+<script src=/common/utils.js></script>
+<script src="../../resources/common.js"></script>
+<script src="../../resources/iframe-test.js"></script>
+
+<body>
+<script>
+
+// This document has COOP: restrict-properties. The popup has COOP: same-origin.
+// Opening from an iframe should not be different from opening from the main
+// frame and the opener should be severed.
+[
+ {
+ "title": "same origin iframe, same origin popup",
+ "iframeOrigin": SAME_ORIGIN,
+ "popupOrigin": SAME_ORIGIN,
+ "opener": "severed"
+ },
+ {
+ "title": "same site iframe, same origin popup",
+ "iframeOrigin": SAME_SITE,
+ "popupOrigin": SAME_ORIGIN,
+ "opener": "severed"
+ },
+ {
+ "title": "cross origin iframe, same origin popup",
+ "iframeOrigin": CROSS_ORIGIN,
+ "popupOrigin": SAME_ORIGIN,
+ "opener": "severed"
+ },
+ {
+ "title": "same origin iframe, same site popup",
+ "iframeOrigin": SAME_ORIGIN,
+ "popupOrigin": SAME_SITE,
+ "opener": "severed"
+ },
+ {
+ "title": "same site iframe, same site popup",
+ "iframeOrigin": SAME_SITE,
+ "popupOrigin": SAME_SITE,
+ "opener": "severed"
+ },
+ {
+ "title": "cross origin iframe, same site popup",
+ "iframeOrigin": CROSS_ORIGIN,
+ "popupOrigin": SAME_SITE,
+ "opener": "severed"
+ },
+ {
+ "title": "same origin iframe, cross origin popup",
+ "iframeOrigin": SAME_ORIGIN,
+ "popupOrigin": CROSS_ORIGIN,
+ "opener": "severed"
+ },
+ {
+ "title": "same site iframe, cross origin popup",
+ "iframeOrigin": SAME_SITE,
+ "popupOrigin": CROSS_ORIGIN,
+ "opener": "severed"
+ },
+ {
+ "title": "cross origin iframe, cross origin popup",
+ "iframeOrigin": CROSS_ORIGIN,
+ "popupOrigin": CROSS_ORIGIN,
+ "opener": "severed"
+ }
+].forEach(variant => {
+ subsetTest(
+ iframe_test,
+ `COOP: restrict-properties to popup COOP: same-origin via an iframe, ` +
+ `with ${variant.title}`,
+ variant.iframeOrigin,
+ variant.popupOrigin,
+ { coop: 'same-origin' },
+ variant.opener);
+});
+</script>
+</body>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/iframe-popup-to-so.https.html.headers b/testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/iframe-popup-to-so.https.html.headers
new file mode 100644
index 0000000000..d5c99062d2
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/iframe-popup-to-so.https.html.headers
@@ -0,0 +1 @@
+Cross-Origin-Opener-Policy: restrict-properties
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/iframe-popup-to-soap.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/iframe-popup-to-soap.https.html
new file mode 100644
index 0000000000..f3af3ca7db
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/iframe-popup-to-soap.https.html
@@ -0,0 +1,91 @@
+<!doctype html>
+<meta charset=utf-8>
+<meta name=timeout content=long>
+<meta name="variant" content="?1-2">
+<meta name="variant" content="?3-4">
+<meta name="variant" content="?5-6">
+<meta name="variant" content="?7-8">
+<meta name="variant" content="?9-last">
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src=/common/dispatcher/dispatcher.js></script>
+<script src=/common/get-host-info.sub.js></script>
+<script src=/common/subset-tests.js></script>
+<script src=/common/utils.js></script>
+<script src="../../resources/common.js"></script>
+<script src="../../resources/iframe-test.js"></script>
+
+<body>
+<script>
+
+
+// This document has COOP: restrict-properties. The popup has COOP:
+// same-origin-allow-popups. Opening from an iframe should not be different from
+// opening from the main frame and the opener should be severed.
+[
+ {
+ "title": "same origin iframe, same origin popup",
+ "iframeOrigin": SAME_ORIGIN,
+ "popupOrigin": SAME_ORIGIN,
+ "opener": "severed"
+ },
+ {
+ "title": "same site iframe, same origin popup",
+ "iframeOrigin": SAME_SITE,
+ "popupOrigin": SAME_ORIGIN,
+ "opener": "severed"
+ },
+ {
+ "title": "cross origin iframe, same origin popup",
+ "iframeOrigin": CROSS_ORIGIN,
+ "popupOrigin": SAME_ORIGIN,
+ "opener": "severed"
+ },
+ {
+ "title": "same origin iframe, same site popup",
+ "iframeOrigin": SAME_ORIGIN,
+ "popupOrigin": SAME_SITE,
+ "opener": "severed"
+ },
+ {
+ "title": "same site iframe, same site popup",
+ "iframeOrigin": SAME_SITE,
+ "popupOrigin": SAME_SITE,
+ "opener": "severed"
+ },
+ {
+ "title": "cross origin iframe, same site popup",
+ "iframeOrigin": CROSS_ORIGIN,
+ "popupOrigin": SAME_SITE,
+ "opener": "severed"
+ },
+ {
+ "title": "same origin iframe, cross origin popup",
+ "iframeOrigin": SAME_ORIGIN,
+ "popupOrigin": CROSS_ORIGIN,
+ "opener": "severed"
+ },
+ {
+ "title": "same site iframe, cross origin popup",
+ "iframeOrigin": SAME_SITE,
+ "popupOrigin": CROSS_ORIGIN,
+ "opener": "severed"
+ },
+ {
+ "title": "cross origin iframe, cross origin popup",
+ "iframeOrigin": CROSS_ORIGIN,
+ "popupOrigin": CROSS_ORIGIN,
+ "opener": "severed"
+ }
+].forEach(variant => {
+ subsetTest(
+ iframe_test,
+ `COOP: restrict-properties to popup COOP: same-origin-allow-popups ` +
+ `via an iframe, with ${variant.title}`,
+ variant.iframeOrigin,
+ variant.popupOrigin,
+ { coop: 'same-origin-allow-popups' },
+ variant.opener);
+});
+</script>
+</body>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/iframe-popup-to-soap.https.html.headers b/testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/iframe-popup-to-soap.https.html.headers
new file mode 100644
index 0000000000..d5c99062d2
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/iframe-popup-to-soap.https.html.headers
@@ -0,0 +1 @@
+Cross-Origin-Opener-Policy: restrict-properties
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/iframe-popup-to-un.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/iframe-popup-to-un.https.html
new file mode 100644
index 0000000000..560dfd9051
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/iframe-popup-to-un.https.html
@@ -0,0 +1,90 @@
+<!doctype html>
+<meta charset=utf-8>
+<meta name=timeout content=long>
+<meta name="variant" content="?1-2">
+<meta name="variant" content="?3-4">
+<meta name="variant" content="?5-6">
+<meta name="variant" content="?7-8">
+<meta name="variant" content="?9-last">
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src=/common/dispatcher/dispatcher.js></script>
+<script src=/common/get-host-info.sub.js></script>
+<script src=/common/subset-tests.js></script>
+<script src=/common/utils.js></script>
+<script src="../../resources/common.js"></script>
+<script src="../../resources/iframe-test.js"></script>
+
+<body>
+<script>
+
+// This document has COOP: restrict-properties. The popup has COOP: unsafe-none.
+// Opening from an iframe should not be different from opening from the main
+// frame and the opener should be severed.
+[
+ {
+ "title": "same origin iframe, same origin popup",
+ "iframeOrigin": SAME_ORIGIN,
+ "popupOrigin": SAME_ORIGIN,
+ "opener": "restricted"
+ },
+ {
+ "title": "same site iframe, same origin popup",
+ "iframeOrigin": SAME_SITE,
+ "popupOrigin": SAME_ORIGIN,
+ "opener": "restricted"
+ },
+ {
+ "title": "cross origin iframe, same origin popup",
+ "iframeOrigin": CROSS_ORIGIN,
+ "popupOrigin": SAME_ORIGIN,
+ "opener": "restricted"
+ },
+ {
+ "title": "same origin iframe, same site popup",
+ "iframeOrigin": SAME_ORIGIN,
+ "popupOrigin": SAME_SITE,
+ "opener": "restricted"
+ },
+ {
+ "title": "same site iframe, same site popup",
+ "iframeOrigin": SAME_SITE,
+ "popupOrigin": SAME_SITE,
+ "opener": "restricted"
+ },
+ {
+ "title": "cross origin iframe, same site popup",
+ "iframeOrigin": CROSS_ORIGIN,
+ "popupOrigin": SAME_SITE,
+ "opener": "restricted"
+ },
+ {
+ "title": "same origin iframe, cross origin popup",
+ "iframeOrigin": SAME_ORIGIN,
+ "popupOrigin": CROSS_ORIGIN,
+ "opener": "restricted"
+ },
+ {
+ "title": "same site iframe, cross origin popup",
+ "iframeOrigin": SAME_SITE,
+ "popupOrigin": CROSS_ORIGIN,
+ "opener": "restricted"
+ },
+ {
+ "title": "cross origin iframe, cross origin popup",
+ "iframeOrigin": CROSS_ORIGIN,
+ "popupOrigin": CROSS_ORIGIN,
+ "opener": "restricted"
+ }
+].forEach(variant => {
+ subsetTest(
+ iframe_test,
+ `COOP: restrict-properties to popup COOP: unsafe-none via an iframe, ` +
+ `with ${variant.title}`,
+ variant.iframeOrigin,
+ variant.popupOrigin,
+ { coop: 'unsafe-none' },
+ variant.opener);
+});
+</script>
+</body>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/iframe-popup-to-un.https.html.headers b/testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/iframe-popup-to-un.https.html.headers
new file mode 100644
index 0000000000..d5c99062d2
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/iframe-popup-to-un.https.html.headers
@@ -0,0 +1 @@
+Cross-Origin-Opener-Policy: restrict-properties
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/iframe-popup.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/iframe-popup.https.html
new file mode 100644
index 0000000000..2c6f0b6282
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/iframe-popup.https.html
@@ -0,0 +1,90 @@
+<!doctype html>
+<meta charset=utf-8>
+<meta name=timeout content=long>
+<meta name="variant" content="?1-2">
+<meta name="variant" content="?3-4">
+<meta name="variant" content="?5-6">
+<meta name="variant" content="?7-8">
+<meta name="variant" content="?9-last">
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src=/common/dispatcher/dispatcher.js></script>
+<script src=/common/get-host-info.sub.js></script>
+<script src=/common/subset-tests.js></script>
+<script src=/common/utils.js></script>
+<script src="../../resources/common.js"></script>
+<script src="../../resources/iframe-test.js"></script>
+
+<body>
+<script>
+
+// This document has COOP: restrict-properties. The popup has COOP:
+// restrict-properties. Opening from an iframe should not be different from
+// opening from the main frame and the opener should be severed.
+[
+ {
+ "title": "same origin iframe, same origin popup",
+ "iframeOrigin": SAME_ORIGIN,
+ "popupOrigin": SAME_ORIGIN,
+ "opener": "restricted"
+ },
+ {
+ "title": "same site iframe, same origin popup",
+ "iframeOrigin": SAME_SITE,
+ "popupOrigin": SAME_ORIGIN,
+ "opener": "restricted"
+ },
+ {
+ "title": "cross origin iframe, same origin popup",
+ "iframeOrigin": CROSS_ORIGIN,
+ "popupOrigin": SAME_ORIGIN,
+ "opener": "restricted"
+ },
+ {
+ "title": "same origin iframe, same site popup",
+ "iframeOrigin": SAME_ORIGIN,
+ "popupOrigin": SAME_SITE,
+ "opener": "restricted"
+ },
+ {
+ "title": "same site iframe, same site popup",
+ "iframeOrigin": SAME_SITE,
+ "popupOrigin": SAME_SITE,
+ "opener": "restricted"
+ },
+ {
+ "title": "cross origin iframe, same site popup",
+ "iframeOrigin": CROSS_ORIGIN,
+ "popupOrigin": SAME_SITE,
+ "opener": "restricted"
+ },
+ {
+ "title": "same origin iframe, cross origin popup",
+ "iframeOrigin": SAME_ORIGIN,
+ "popupOrigin": CROSS_ORIGIN,
+ "opener": "restricted"
+ },
+ {
+ "title": "same site iframe, cross origin popup",
+ "iframeOrigin": SAME_SITE,
+ "popupOrigin": CROSS_ORIGIN,
+ "opener": "restricted"
+ },
+ {
+ "title": "cross origin iframe, cross origin popup",
+ "iframeOrigin": CROSS_ORIGIN,
+ "popupOrigin": CROSS_ORIGIN,
+ "opener": "restricted"
+ }
+].forEach(variant => {
+ subsetTest(
+ iframe_test,
+ `COOP: restrict-properties to popup COOP: restrict-properties via an ` +
+ `iframe, with ${variant.title}`,
+ variant.iframeOrigin,
+ variant.popupOrigin,
+ { coop: 'restrict-properties' },
+ variant.opener);
+});
+</script>
+</body>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/iframe-popup.https.html.headers b/testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/iframe-popup.https.html.headers
new file mode 100644
index 0000000000..d5c99062d2
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/iframe-popup.https.html.headers
@@ -0,0 +1 @@
+Cross-Origin-Opener-Policy: restrict-properties
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/named_targeting.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/named_targeting.https.html
new file mode 100644
index 0000000000..00eb6506e9
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/named_targeting.https.html
@@ -0,0 +1,40 @@
+<!doctype html>
+<meta charset=utf-8>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src="/common/dispatcher/dispatcher.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="/common/utils.js"></script>
+<script src="../../resources/common.js"></script>
+
+<script>
+
+async function createCoopRestrictPropertiesPopup(name) {
+ const popupToken = token();
+ const url = SAME_ORIGIN.origin + '/common/dispatcher/executor.html' +
+ `?uuid=${popupToken}` +
+ '&pipe=|header(Cross-Origin-Opener-Policy, restrict-properties)';
+ const popup = window.open(url, name);
+ add_completion_callback(() => popup.close());
+
+ // Wait for the popup to be loaded.
+ const replyToken = token();
+ send(popupToken, `send('${replyToken}', 'Done loading')`);
+ assert_equals(await receive(replyToken), 'Done loading');
+
+ return popup;
+}
+
+promise_test(async t => {
+ // Open two COOP: restrict-properties popups with the same name.
+ const name = token();
+ const popup1 = await createCoopRestrictPropertiesPopup(name);
+ const popup2 = await createCoopRestrictPropertiesPopup(name);
+
+ // Check that named targeting did not cross isolation boundaries. Two popups
+ // should have been created.
+ assert_not_equals(popup1, popup2,
+ 'Named targeting resolved across isolation boundaries');
+}, 'Verify that named targeting does not work across isolation boundaries.');
+
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/named_targeting.https.html.headers b/testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/named_targeting.https.html.headers
new file mode 100644
index 0000000000..d5c99062d2
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/named_targeting.https.html.headers
@@ -0,0 +1 @@
+Cross-Origin-Opener-Policy: restrict-properties
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/popup-so.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/popup-so.https.html
new file mode 100644
index 0000000000..e5313a6e22
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/popup-so.https.html
@@ -0,0 +1,37 @@
+<!doctype html>
+<meta charset=utf-8>
+<meta name=timeout content=long>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src="/common/dispatcher/dispatcher.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="/common/utils.js"></script>
+<script src="../../resources/common.js"></script>
+<script src="../../resources/popup-test.js"></script>
+<script>
+
+[
+ {
+ "title": "popup with coop restrict-properties",
+ "coop": "restrict-properties",
+ "opener": "severed",
+ "origin": SAME_ORIGIN
+ },
+ {
+ "title": "popup with coop restrict-properties",
+ "coop": "restrict-properties",
+ "opener": "severed",
+ "origin": SAME_SITE
+ },
+ {
+ "title": "popup with coop restrict-properties",
+ "coop": "restrict-properties",
+ "opener": "severed",
+ "origin": CROSS_ORIGIN
+ }
+].forEach(variant => {
+ popup_test(`${variant.origin.name} ${variant.title}`, variant.origin,
+ { coop: variant.coop }, variant.opener);
+});
+
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/popup-so.https.html.headers b/testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/popup-so.https.html.headers
new file mode 100644
index 0000000000..46ad58d83b
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/popup-so.https.html.headers
@@ -0,0 +1 @@
+Cross-Origin-Opener-Policy: same-origin
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/popup-soap.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/popup-soap.https.html
new file mode 100644
index 0000000000..595a10a84b
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/popup-soap.https.html
@@ -0,0 +1,37 @@
+<!doctype html>
+<meta charset=utf-8>
+<meta name=timeout content=long>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src="/common/dispatcher/dispatcher.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="/common/utils.js"></script>
+<script src="../../resources/common.js"></script>
+<script src="../../resources/popup-test.js"></script>
+<script>
+
+[
+ {
+ "title": "popup with coop restrict-properties",
+ "coop": "restrict-properties",
+ "opener": "restricted",
+ "origin": SAME_ORIGIN
+ },
+ {
+ "title": "popup with coop restrict-properties",
+ "coop": "restrict-properties",
+ "opener": "restricted",
+ "origin": SAME_SITE
+ },
+ {
+ "title": "popup with coop restrict-properties",
+ "coop": "restrict-properties",
+ "opener": "restricted",
+ "origin": CROSS_ORIGIN
+ }
+].forEach(variant => {
+ popup_test(`${variant.origin.name} ${variant.title}`, variant.origin,
+ { coop: variant.coop }, variant.opener);
+});
+
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/popup-soap.https.html.headers b/testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/popup-soap.https.html.headers
new file mode 100644
index 0000000000..d83ed86fb9
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/popup-soap.https.html.headers
@@ -0,0 +1 @@
+Cross-Origin-Opener-Policy: same-origin-allow-popups
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/popup-u.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/popup-u.https.html
new file mode 100644
index 0000000000..595a10a84b
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/popup-u.https.html
@@ -0,0 +1,37 @@
+<!doctype html>
+<meta charset=utf-8>
+<meta name=timeout content=long>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src="/common/dispatcher/dispatcher.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="/common/utils.js"></script>
+<script src="../../resources/common.js"></script>
+<script src="../../resources/popup-test.js"></script>
+<script>
+
+[
+ {
+ "title": "popup with coop restrict-properties",
+ "coop": "restrict-properties",
+ "opener": "restricted",
+ "origin": SAME_ORIGIN
+ },
+ {
+ "title": "popup with coop restrict-properties",
+ "coop": "restrict-properties",
+ "opener": "restricted",
+ "origin": SAME_SITE
+ },
+ {
+ "title": "popup with coop restrict-properties",
+ "coop": "restrict-properties",
+ "opener": "restricted",
+ "origin": CROSS_ORIGIN
+ }
+].forEach(variant => {
+ popup_test(`${variant.origin.name} ${variant.title}`, variant.origin,
+ { coop: variant.coop }, variant.opener);
+});
+
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/popup-un.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/popup-un.https.html
new file mode 100644
index 0000000000..595a10a84b
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/popup-un.https.html
@@ -0,0 +1,37 @@
+<!doctype html>
+<meta charset=utf-8>
+<meta name=timeout content=long>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src="/common/dispatcher/dispatcher.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="/common/utils.js"></script>
+<script src="../../resources/common.js"></script>
+<script src="../../resources/popup-test.js"></script>
+<script>
+
+[
+ {
+ "title": "popup with coop restrict-properties",
+ "coop": "restrict-properties",
+ "opener": "restricted",
+ "origin": SAME_ORIGIN
+ },
+ {
+ "title": "popup with coop restrict-properties",
+ "coop": "restrict-properties",
+ "opener": "restricted",
+ "origin": SAME_SITE
+ },
+ {
+ "title": "popup with coop restrict-properties",
+ "coop": "restrict-properties",
+ "opener": "restricted",
+ "origin": CROSS_ORIGIN
+ }
+].forEach(variant => {
+ popup_test(`${variant.origin.name} ${variant.title}`, variant.origin,
+ { coop: variant.coop }, variant.opener);
+});
+
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/popup-un.https.html.headers b/testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/popup-un.https.html.headers
new file mode 100644
index 0000000000..073ce7adfb
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/popup-un.https.html.headers
@@ -0,0 +1 @@
+Cross-Origin-Opener-Policy: unsafe-none
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/popup-with-cross-origin.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/popup-with-cross-origin.https.html
new file mode 100644
index 0000000000..a84d52584e
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/popup-with-cross-origin.https.html
@@ -0,0 +1,44 @@
+<!doctype html>
+<meta charset=utf-8>
+<meta name=timeout content=long>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src="/common/dispatcher/dispatcher.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="/common/utils.js"></script>
+<script src="../../resources/common.js"></script>
+<script src="../../resources/popup-test.js"></script>
+<script>
+
+[
+ {
+ "title": "popup with empty coop",
+ "coop": "",
+ "opener": "restricted"
+ },
+ {
+ "title": "popup with coop unsafe-none",
+ "coop": "unsafe-none",
+ "opener": "restricted"
+ },
+ {
+ "title": "popup with coop same-origin",
+ "coop": "same-origin",
+ "opener": "severed"
+ },
+ {
+ "title": "popup with coop same-origin-allow-popups",
+ "coop": "same-origin-allow-popups",
+ "opener": "severed"
+ },
+ {
+ "title": "popup with coop restrict-properties",
+ "coop": "restrict-properties",
+ "opener": "restricted"
+ }
+].forEach(variant => {
+ popup_test(`Cross-origin ${variant.title}`, CROSS_ORIGIN,
+ { coop: variant.coop }, variant.opener);
+});
+
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/popup-with-cross-origin.https.html.headers b/testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/popup-with-cross-origin.https.html.headers
new file mode 100644
index 0000000000..d5c99062d2
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/popup-with-cross-origin.https.html.headers
@@ -0,0 +1 @@
+Cross-Origin-Opener-Policy: restrict-properties
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/popup-with-same-origin.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/popup-with-same-origin.https.html
new file mode 100644
index 0000000000..491cbc3b9d
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/popup-with-same-origin.https.html
@@ -0,0 +1,44 @@
+<!doctype html>
+<meta charset=utf-8>
+<meta name=timeout content=long>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src="/common/dispatcher/dispatcher.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="/common/utils.js"></script>
+<script src="../../resources/common.js"></script>
+<script src="../../resources/popup-test.js"></script>
+<script>
+
+[
+ {
+ "title": "popup with empty coop",
+ "coop": "",
+ "opener": "restricted"
+ },
+ {
+ "title": "popup with coop unsafe-none",
+ "coop": "unsafe-none",
+ "opener": "restricted"
+ },
+ {
+ "title": "popup with coop same-origin",
+ "coop": "same-origin",
+ "opener": "severed"
+ },
+ {
+ "title": "popup with coop same-origin-allow-popups",
+ "coop": "same-origin-allow-popups",
+ "opener": "severed"
+ },
+ {
+ "title": "popup with coop restrict-properties",
+ "coop": "restrict-properties",
+ "opener": "restricted"
+ }
+].forEach(variant => {
+ popup_test(`Same-origin ${variant.title}`, SAME_ORIGIN,
+ { coop: variant.coop }, variant.opener);
+});
+
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/popup-with-same-origin.https.html.headers b/testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/popup-with-same-origin.https.html.headers
new file mode 100644
index 0000000000..d5c99062d2
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/popup-with-same-origin.https.html.headers
@@ -0,0 +1 @@
+Cross-Origin-Opener-Policy: restrict-properties
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/popup-with-same-site.https.html b/testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/popup-with-same-site.https.html
new file mode 100644
index 0000000000..7d115ac7e6
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/popup-with-same-site.https.html
@@ -0,0 +1,44 @@
+<!doctype html>
+<meta charset=utf-8>
+<meta name=timeout content=long>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src="/common/dispatcher/dispatcher.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="/common/utils.js"></script>
+<script src="../../resources/common.js"></script>
+<script src="../../resources/popup-test.js"></script>
+<script>
+
+[
+ {
+ "title": "popup with empty coop",
+ "coop": "",
+ "opener": "restricted"
+ },
+ {
+ "title": "popup with coop unsafe-none",
+ "coop": "unsafe-none",
+ "opener": "restricted"
+ },
+ {
+ "title": "popup with coop same-origin",
+ "coop": "same-origin",
+ "opener": "severed"
+ },
+ {
+ "title": "popup with coop same-origin-allow-popups",
+ "coop": "same-origin-allow-popups",
+ "opener": "severed"
+ },
+ {
+ "title": "popup with coop restrict-properties",
+ "coop": "restrict-properties",
+ "opener": "restricted"
+ }
+].forEach(variant => {
+ popup_test(`Same-site ${variant.title}`, SAME_SITE,
+ { coop: variant.coop }, variant.opener);
+});
+
+</script>
diff --git a/testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/popup-with-same-site.https.html.headers b/testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/popup-with-same-site.https.html.headers
new file mode 100644
index 0000000000..d5c99062d2
--- /dev/null
+++ b/testing/web-platform/tests/html/cross-origin-opener-policy/tentative/restrict-properties/popup-with-same-site.https.html.headers
@@ -0,0 +1 @@
+Cross-Origin-Opener-Policy: restrict-properties