summaryrefslogtreecommitdiffstats
path: root/dom/security/test/csp
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
commit36d22d82aa202bb199967e9512281e9a53db42c9 (patch)
tree105e8c98ddea1c1e4784a60a5a6410fa416be2de /dom/security/test/csp
parentInitial commit. (diff)
downloadfirefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz
firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'dom/security/test/csp')
-rw-r--r--dom/security/test/csp/Ahem.ttfbin0 -> 12480 bytes
-rw-r--r--dom/security/test/csp/File0
-rw-r--r--dom/security/test/csp/browser.ini23
-rw-r--r--dom/security/test/csp/browser_manifest-src-override-default-src.js125
-rw-r--r--dom/security/test/csp/browser_pdfjs_not_subject_to_csp.js48
-rw-r--r--dom/security/test/csp/browser_test_bookmarklets.js82
-rw-r--r--dom/security/test/csp/browser_test_uir_optional_clicks.js36
-rw-r--r--dom/security/test/csp/browser_test_web_manifest.js239
-rw-r--r--dom/security/test/csp/browser_test_web_manifest_mixed_content.js57
-rw-r--r--dom/security/test/csp/dummy.pdfbin0 -> 150611 bytes
-rw-r--r--dom/security/test/csp/file_CSP.css20
-rw-r--r--dom/security/test/csp/file_CSP.sjs24
-rw-r--r--dom/security/test/csp/file_allow_https_schemes.html14
-rw-r--r--dom/security/test/csp/file_base_uri_server.sjs59
-rw-r--r--dom/security/test/csp/file_blob_data_schemes.html49
-rw-r--r--dom/security/test/csp/file_blob_top_nav_block_modals.html18
-rw-r--r--dom/security/test/csp/file_blob_top_nav_block_modals.html^headers^1
-rw-r--r--dom/security/test/csp/file_blob_uri_blocks_modals.html27
-rw-r--r--dom/security/test/csp/file_blob_uri_blocks_modals.html^headers^1
-rw-r--r--dom/security/test/csp/file_block_all_mcb.sjs78
-rw-r--r--dom/security/test/csp/file_block_all_mixed_content_frame_navigation1.html19
-rw-r--r--dom/security/test/csp/file_block_all_mixed_content_frame_navigation2.html15
-rw-r--r--dom/security/test/csp/file_blocked_uri_in_violation_event_after_redirects.html39
-rw-r--r--dom/security/test/csp/file_blocked_uri_in_violation_event_after_redirects.sjs52
-rw-r--r--dom/security/test/csp/file_blocked_uri_redirect_frame_src.html10
-rw-r--r--dom/security/test/csp/file_blocked_uri_redirect_frame_src.html^headers^1
-rw-r--r--dom/security/test/csp/file_blocked_uri_redirect_frame_src_server.sjs14
-rw-r--r--dom/security/test/csp/file_bug1229639.html7
-rw-r--r--dom/security/test/csp/file_bug1229639.html^headers^1
-rw-r--r--dom/security/test/csp/file_bug1312272.html13
-rw-r--r--dom/security/test/csp/file_bug1312272.html^headers^1
-rw-r--r--dom/security/test/csp/file_bug1312272.js8
-rw-r--r--dom/security/test/csp/file_bug1452037.html9
-rw-r--r--dom/security/test/csp/file_bug1505412.sjs36
-rw-r--r--dom/security/test/csp/file_bug1505412_frame.html14
-rw-r--r--dom/security/test/csp/file_bug1505412_frame.html^headers^1
-rw-r--r--dom/security/test/csp/file_bug1505412_reporter.sjs18
-rw-r--r--dom/security/test/csp/file_bug1738418_child.html11
-rw-r--r--dom/security/test/csp/file_bug1738418_parent.html11
-rw-r--r--dom/security/test/csp/file_bug1738418_parent.html^headers^1
-rw-r--r--dom/security/test/csp/file_bug1764343.html11
-rw-r--r--dom/security/test/csp/file_bug1777572.html43
-rw-r--r--dom/security/test/csp/file_bug663567.xsl27
-rw-r--r--dom/security/test/csp/file_bug663567_allows.xml28
-rw-r--r--dom/security/test/csp/file_bug663567_allows.xml^headers^1
-rw-r--r--dom/security/test/csp/file_bug663567_blocks.xml28
-rw-r--r--dom/security/test/csp/file_bug663567_blocks.xml^headers^1
-rw-r--r--dom/security/test/csp/file_bug802872.html12
-rw-r--r--dom/security/test/csp/file_bug802872.html^headers^1
-rw-r--r--dom/security/test/csp/file_bug802872.js47
-rw-r--r--dom/security/test/csp/file_bug802872.sjs6
-rw-r--r--dom/security/test/csp/file_bug836922_npolicies.html12
-rw-r--r--dom/security/test/csp/file_bug836922_npolicies.html^headers^2
-rw-r--r--dom/security/test/csp/file_bug836922_npolicies_ro_violation.sjs53
-rw-r--r--dom/security/test/csp/file_bug836922_npolicies_violation.sjs64
-rw-r--r--dom/security/test/csp/file_bug885433_allows.html38
-rw-r--r--dom/security/test/csp/file_bug885433_allows.html^headers^1
-rw-r--r--dom/security/test/csp/file_bug885433_blocks.html37
-rw-r--r--dom/security/test/csp/file_bug885433_blocks.html^headers^1
-rw-r--r--dom/security/test/csp/file_bug886164.html15
-rw-r--r--dom/security/test/csp/file_bug886164.html^headers^1
-rw-r--r--dom/security/test/csp/file_bug886164_2.html14
-rw-r--r--dom/security/test/csp/file_bug886164_2.html^headers^1
-rw-r--r--dom/security/test/csp/file_bug886164_3.html12
-rw-r--r--dom/security/test/csp/file_bug886164_3.html^headers^1
-rw-r--r--dom/security/test/csp/file_bug886164_4.html12
-rw-r--r--dom/security/test/csp/file_bug886164_4.html^headers^1
-rw-r--r--dom/security/test/csp/file_bug886164_5.html26
-rw-r--r--dom/security/test/csp/file_bug886164_5.html^headers^1
-rw-r--r--dom/security/test/csp/file_bug886164_6.html35
-rw-r--r--dom/security/test/csp/file_bug886164_6.html^headers^1
-rw-r--r--dom/security/test/csp/file_bug888172.html28
-rw-r--r--dom/security/test/csp/file_bug888172.sjs47
-rw-r--r--dom/security/test/csp/file_bug909029_none.html20
-rw-r--r--dom/security/test/csp/file_bug909029_none.html^headers^1
-rw-r--r--dom/security/test/csp/file_bug909029_star.html19
-rw-r--r--dom/security/test/csp/file_bug909029_star.html^headers^1
-rw-r--r--dom/security/test/csp/file_bug910139.sjs54
-rw-r--r--dom/security/test/csp/file_bug910139.xml28
-rw-r--r--dom/security/test/csp/file_bug910139.xsl27
-rw-r--r--dom/security/test/csp/file_bug941404.html27
-rw-r--r--dom/security/test/csp/file_bug941404_xhr.html5
-rw-r--r--dom/security/test/csp/file_bug941404_xhr.html^headers^1
-rw-r--r--dom/security/test/csp/file_child-src_iframe.html61
-rw-r--r--dom/security/test/csp/file_child-src_inner_frame.html21
-rw-r--r--dom/security/test/csp/file_child-src_service_worker.html30
-rw-r--r--dom/security/test/csp/file_child-src_service_worker.js3
-rw-r--r--dom/security/test/csp/file_child-src_shared_worker-redirect.html47
-rw-r--r--dom/security/test/csp/file_child-src_shared_worker.html35
-rw-r--r--dom/security/test/csp/file_child-src_shared_worker.js8
-rw-r--r--dom/security/test/csp/file_child-src_shared_worker_data.html37
-rw-r--r--dom/security/test/csp/file_child-src_worker-redirect.html47
-rw-r--r--dom/security/test/csp/file_child-src_worker.html34
-rw-r--r--dom/security/test/csp/file_child-src_worker.js3
-rw-r--r--dom/security/test/csp/file_child-src_worker_data.html33
-rw-r--r--dom/security/test/csp/file_connect-src-fetch.html16
-rw-r--r--dom/security/test/csp/file_connect-src.html21
-rw-r--r--dom/security/test/csp/file_csp_frame_ancestors_about_blank.html9
-rw-r--r--dom/security/test/csp/file_csp_frame_ancestors_about_blank.html^headers^2
-rw-r--r--dom/security/test/csp/file_csp_meta_uir.html13
-rw-r--r--dom/security/test/csp/file_data-uri_blocked.html15
-rw-r--r--dom/security/test/csp/file_data-uri_blocked.html^headers^1
-rw-r--r--dom/security/test/csp/file_data_csp_inheritance.html24
-rw-r--r--dom/security/test/csp/file_data_csp_merge.html26
-rw-r--r--dom/security/test/csp/file_data_doc_ignore_meta_csp.html22
-rw-r--r--dom/security/test/csp/file_doccomment_meta.html28
-rw-r--r--dom/security/test/csp/file_docwrite_meta.css3
-rw-r--r--dom/security/test/csp/file_docwrite_meta.html26
-rw-r--r--dom/security/test/csp/file_docwrite_meta.js3
-rw-r--r--dom/security/test/csp/file_dual_header_testserver.sjs45
-rw-r--r--dom/security/test/csp/file_dummy_pixel.pngbin0 -> 70 bytes
-rw-r--r--dom/security/test/csp/file_empty_directive.html11
-rw-r--r--dom/security/test/csp/file_empty_directive.html^headers^1
-rw-r--r--dom/security/test/csp/file_evalscript_main.html12
-rw-r--r--dom/security/test/csp/file_evalscript_main.html^headers^2
-rw-r--r--dom/security/test/csp/file_evalscript_main.js240
-rw-r--r--dom/security/test/csp/file_evalscript_main_allowed.html12
-rw-r--r--dom/security/test/csp/file_evalscript_main_allowed.html^headers^2
-rw-r--r--dom/security/test/csp/file_evalscript_main_allowed.js193
-rw-r--r--dom/security/test/csp/file_fontloader.sjs57
-rw-r--r--dom/security/test/csp/file_fontloader.woffbin0 -> 11140 bytes
-rw-r--r--dom/security/test/csp/file_form-action.html15
-rw-r--r--dom/security/test/csp/file_form_action_server.sjs32
-rw-r--r--dom/security/test/csp/file_frame_ancestors_ro.html1
-rw-r--r--dom/security/test/csp/file_frame_ancestors_ro.html^headers^1
-rw-r--r--dom/security/test/csp/file_frame_src.js20
-rw-r--r--dom/security/test/csp/file_frame_src_child_governs.html10
-rw-r--r--dom/security/test/csp/file_frame_src_frame_governs.html10
-rw-r--r--dom/security/test/csp/file_frame_src_inner.html5
-rw-r--r--dom/security/test/csp/file_frameancestors.sjs69
-rw-r--r--dom/security/test/csp/file_frameancestors_main.html44
-rw-r--r--dom/security/test/csp/file_frameancestors_main.js134
-rw-r--r--dom/security/test/csp/file_frameancestors_userpass.html10
-rw-r--r--dom/security/test/csp/file_frameancestors_userpass_frame_a.html12
-rw-r--r--dom/security/test/csp/file_frameancestors_userpass_frame_b.html12
-rw-r--r--dom/security/test/csp/file_frameancestors_userpass_frame_c.html8
-rw-r--r--dom/security/test/csp/file_frameancestors_userpass_frame_c.html^headers^1
-rw-r--r--dom/security/test/csp/file_frameancestors_userpass_frame_d.html8
-rw-r--r--dom/security/test/csp/file_frameancestors_userpass_frame_d.html^headers^1
-rw-r--r--dom/security/test/csp/file_hash_source.html65
-rw-r--r--dom/security/test/csp/file_hash_source.html^headers^2
-rw-r--r--dom/security/test/csp/file_iframe_parent_location_js.html10
-rw-r--r--dom/security/test/csp/file_iframe_sandbox_document_write.html21
-rw-r--r--dom/security/test/csp/file_iframe_sandbox_srcdoc.html11
-rw-r--r--dom/security/test/csp/file_iframe_sandbox_srcdoc.html^headers^1
-rw-r--r--dom/security/test/csp/file_iframe_srcdoc.sjs87
-rw-r--r--dom/security/test/csp/file_ignore_unsafe_inline.html26
-rw-r--r--dom/security/test/csp/file_ignore_unsafe_inline_multiple_policies_server.sjs56
-rw-r--r--dom/security/test/csp/file_ignore_xfo.html10
-rw-r--r--dom/security/test/csp/file_ignore_xfo.html^headers^3
-rw-r--r--dom/security/test/csp/file_image_document_pixel.pngbin0 -> 70 bytes
-rw-r--r--dom/security/test/csp/file_image_document_pixel.png^headers^2
-rw-r--r--dom/security/test/csp/file_image_nonce.html39
-rw-r--r--dom/security/test/csp/file_image_nonce.html^headers^2
-rw-r--r--dom/security/test/csp/file_independent_iframe_csp.html43
-rw-r--r--dom/security/test/csp/file_inlinescript.html15
-rw-r--r--dom/security/test/csp/file_inlinestyle_main.html79
-rw-r--r--dom/security/test/csp/file_inlinestyle_main.html^headers^2
-rw-r--r--dom/security/test/csp/file_inlinestyle_main_allowed.html84
-rw-r--r--dom/security/test/csp/file_inlinestyle_main_allowed.html^headers^2
-rw-r--r--dom/security/test/csp/file_invalid_source_expression.html11
-rw-r--r--dom/security/test/csp/file_leading_wildcard.html11
-rw-r--r--dom/security/test/csp/file_link_rel_preload.html19
-rw-r--r--dom/security/test/csp/file_main.html55
-rw-r--r--dom/security/test/csp/file_main.html^headers^1
-rw-r--r--dom/security/test/csp/file_main.js26
-rw-r--r--dom/security/test/csp/file_meta_element.html27
-rw-r--r--dom/security/test/csp/file_meta_header_dual.sjs101
-rw-r--r--dom/security/test/csp/file_meta_whitespace_skipping.html31
-rw-r--r--dom/security/test/csp/file_multi_policy_injection_bypass.html15
-rw-r--r--dom/security/test/csp/file_multi_policy_injection_bypass.html^headers^1
-rw-r--r--dom/security/test/csp/file_multi_policy_injection_bypass_2.html15
-rw-r--r--dom/security/test/csp/file_multi_policy_injection_bypass_2.html^headers^1
-rw-r--r--dom/security/test/csp/file_multipart_testserver.sjs160
-rw-r--r--dom/security/test/csp/file_navigate_to.html11
-rw-r--r--dom/security/test/csp/file_navigate_to.sjs58
-rw-r--r--dom/security/test/csp/file_navigate_to_request.html17
-rw-r--r--dom/security/test/csp/file_no_log_ignore_xfo.html10
-rw-r--r--dom/security/test/csp/file_no_log_ignore_xfo.html^headers^2
-rw-r--r--dom/security/test/csp/file_nonce_redirector.sjs28
-rw-r--r--dom/security/test/csp/file_nonce_redirects.html23
-rw-r--r--dom/security/test/csp/file_nonce_snapshot.sjs54
-rw-r--r--dom/security/test/csp/file_nonce_source.html73
-rw-r--r--dom/security/test/csp/file_nonce_source.html^headers^2
-rw-r--r--dom/security/test/csp/file_null_baseuri.html21
-rw-r--r--dom/security/test/csp/file_object_inherit.html21
-rw-r--r--dom/security/test/csp/file_parent_location_js.html18
-rw-r--r--dom/security/test/csp/file_path_matching.html10
-rw-r--r--dom/security/test/csp/file_path_matching.js1
-rw-r--r--dom/security/test/csp/file_path_matching_incl_query.html10
-rw-r--r--dom/security/test/csp/file_path_matching_redirect.html10
-rw-r--r--dom/security/test/csp/file_path_matching_redirect_server.sjs12
-rw-r--r--dom/security/test/csp/file_pdfjs_not_subject_to_csp.html21
-rw-r--r--dom/security/test/csp/file_ping.html19
-rw-r--r--dom/security/test/csp/file_policyuri_regression_from_multipolicy.html9
-rw-r--r--dom/security/test/csp/file_policyuri_regression_from_multipolicy.html^headers^1
-rw-r--r--dom/security/test/csp/file_policyuri_regression_from_multipolicy_policy1
-rw-r--r--dom/security/test/csp/file_punycode_host_src.js2
-rw-r--r--dom/security/test/csp/file_punycode_host_src.sjs47
-rw-r--r--dom/security/test/csp/file_redirect_content.sjs41
-rw-r--r--dom/security/test/csp/file_redirect_report.sjs17
-rw-r--r--dom/security/test/csp/file_redirect_worker.sjs35
-rw-r--r--dom/security/test/csp/file_redirects_main.html37
-rw-r--r--dom/security/test/csp/file_redirects_page.sjs141
-rw-r--r--dom/security/test/csp/file_redirects_resource.sjs172
-rw-r--r--dom/security/test/csp/file_report.html13
-rw-r--r--dom/security/test/csp/file_report_chromescript.js65
-rw-r--r--dom/security/test/csp/file_report_font_cache-1.html26
-rw-r--r--dom/security/test/csp/file_report_font_cache-2.html25
-rw-r--r--dom/security/test/csp/file_report_font_cache-2.html^headers^1
-rw-r--r--dom/security/test/csp/file_report_for_import.css1
-rw-r--r--dom/security/test/csp/file_report_for_import.html10
-rw-r--r--dom/security/test/csp/file_report_for_import_server.sjs50
-rw-r--r--dom/security/test/csp/file_report_uri_missing_in_report_only_header.html0
-rw-r--r--dom/security/test/csp/file_report_uri_missing_in_report_only_header.html^headers^1
-rw-r--r--dom/security/test/csp/file_ro_ignore_xfo.html10
-rw-r--r--dom/security/test/csp/file_ro_ignore_xfo.html^headers^3
-rw-r--r--dom/security/test/csp/file_sandbox_1.html16
-rw-r--r--dom/security/test/csp/file_sandbox_10.html12
-rw-r--r--dom/security/test/csp/file_sandbox_11.html25
-rw-r--r--dom/security/test/csp/file_sandbox_12.html40
-rw-r--r--dom/security/test/csp/file_sandbox_13.html25
-rw-r--r--dom/security/test/csp/file_sandbox_2.html16
-rw-r--r--dom/security/test/csp/file_sandbox_3.html13
-rw-r--r--dom/security/test/csp/file_sandbox_4.html13
-rw-r--r--dom/security/test/csp/file_sandbox_5.html26
-rw-r--r--dom/security/test/csp/file_sandbox_6.html35
-rw-r--r--dom/security/test/csp/file_sandbox_7.html15
-rw-r--r--dom/security/test/csp/file_sandbox_8.html15
-rw-r--r--dom/security/test/csp/file_sandbox_9.html12
-rw-r--r--dom/security/test/csp/file_sandbox_allow_scripts.html12
-rw-r--r--dom/security/test/csp/file_sandbox_allow_scripts.html^headers^1
-rw-r--r--dom/security/test/csp/file_sandbox_fail.js7
-rw-r--r--dom/security/test/csp/file_sandbox_pass.js7
-rw-r--r--dom/security/test/csp/file_scheme_relative_sources.js1
-rw-r--r--dom/security/test/csp/file_scheme_relative_sources.sjs45
-rw-r--r--dom/security/test/csp/file_script_template.html16
-rw-r--r--dom/security/test/csp/file_script_template.js1
-rw-r--r--dom/security/test/csp/file_self_none_as_hostname_confusion.html11
-rw-r--r--dom/security/test/csp/file_self_none_as_hostname_confusion.html^headers^1
-rw-r--r--dom/security/test/csp/file_sendbeacon.html21
-rw-r--r--dom/security/test/csp/file_service_worker.html21
-rw-r--r--dom/security/test/csp/file_service_worker.js1
-rw-r--r--dom/security/test/csp/file_spawn_service_worker.js1
-rw-r--r--dom/security/test/csp/file_spawn_shared_worker.js7
-rw-r--r--dom/security/test/csp/file_spawn_worker.js1
-rw-r--r--dom/security/test/csp/file_strict_dynamic.js1
-rw-r--r--dom/security/test/csp/file_strict_dynamic_default_src.html20
-rw-r--r--dom/security/test/csp/file_strict_dynamic_default_src.js1
-rw-r--r--dom/security/test/csp/file_strict_dynamic_js_url.html15
-rw-r--r--dom/security/test/csp/file_strict_dynamic_non_parser_inserted.html17
-rw-r--r--dom/security/test/csp/file_strict_dynamic_non_parser_inserted_inline.html16
-rw-r--r--dom/security/test/csp/file_strict_dynamic_parser_inserted_doc_write.html15
-rw-r--r--dom/security/test/csp/file_strict_dynamic_parser_inserted_doc_write_correct_nonce.html15
-rw-r--r--dom/security/test/csp/file_strict_dynamic_script_events.html14
-rw-r--r--dom/security/test/csp/file_strict_dynamic_script_events_marquee.html14
-rw-r--r--dom/security/test/csp/file_strict_dynamic_script_extern.html10
-rw-r--r--dom/security/test/csp/file_strict_dynamic_script_inline.html14
-rw-r--r--dom/security/test/csp/file_strict_dynamic_unsafe_eval.html14
-rw-r--r--dom/security/test/csp/file_subframe_run_js_if_allowed.html13
-rw-r--r--dom/security/test/csp/file_subframe_run_js_if_allowed.html^headers^1
-rw-r--r--dom/security/test/csp/file_svg_inline_style_base.html9
-rw-r--r--dom/security/test/csp/file_svg_inline_style_csp.html10
-rw-r--r--dom/security/test/csp/file_svg_inline_style_server.sjs43
-rw-r--r--dom/security/test/csp/file_svg_srcset_inline_style_base.html9
-rw-r--r--dom/security/test/csp/file_svg_srcset_inline_style_csp.html10
-rw-r--r--dom/security/test/csp/file_test_browser_bookmarklets.html12
-rw-r--r--dom/security/test/csp/file_test_browser_bookmarklets.html^headers^2
-rw-r--r--dom/security/test/csp/file_testserver.sjs67
-rw-r--r--dom/security/test/csp/file_uir_top_nav.html17
-rw-r--r--dom/security/test/csp/file_uir_top_nav_dummy.html12
-rw-r--r--dom/security/test/csp/file_upgrade_insecure.html90
-rw-r--r--dom/security/test/csp/file_upgrade_insecure_cors.html49
-rw-r--r--dom/security/test/csp/file_upgrade_insecure_cors_server.sjs61
-rw-r--r--dom/security/test/csp/file_upgrade_insecure_docwrite_iframe.sjs55
-rw-r--r--dom/security/test/csp/file_upgrade_insecure_loopback.html25
-rw-r--r--dom/security/test/csp/file_upgrade_insecure_loopback_form.html17
-rw-r--r--dom/security/test/csp/file_upgrade_insecure_loopback_server.sjs22
-rw-r--r--dom/security/test/csp/file_upgrade_insecure_meta.html86
-rw-r--r--dom/security/test/csp/file_upgrade_insecure_navigation.sjs79
-rw-r--r--dom/security/test/csp/file_upgrade_insecure_navigation_redirect.sjs50
-rw-r--r--dom/security/test/csp/file_upgrade_insecure_navigation_redirect_cross_origin.html10
-rw-r--r--dom/security/test/csp/file_upgrade_insecure_navigation_redirect_same_origin.html10
-rw-r--r--dom/security/test/csp/file_upgrade_insecure_reporting.html23
-rw-r--r--dom/security/test/csp/file_upgrade_insecure_reporting_server.sjs87
-rw-r--r--dom/security/test/csp/file_upgrade_insecure_server.sjs112
-rw-r--r--dom/security/test/csp/file_upgrade_insecure_wsh.py6
-rw-r--r--dom/security/test/csp/file_web_manifest.html6
-rw-r--r--dom/security/test/csp/file_web_manifest.json1
-rw-r--r--dom/security/test/csp/file_web_manifest.json^headers^1
-rw-r--r--dom/security/test/csp/file_web_manifest_https.html4
-rw-r--r--dom/security/test/csp/file_web_manifest_https.json1
-rw-r--r--dom/security/test/csp/file_web_manifest_mixed_content.html9
-rw-r--r--dom/security/test/csp/file_web_manifest_remote.html8
-rw-r--r--dom/security/test/csp/file_websocket_csp_upgrade.html20
-rw-r--r--dom/security/test/csp/file_websocket_explicit.html31
-rw-r--r--dom/security/test/csp/file_websocket_self.html31
-rw-r--r--dom/security/test/csp/file_websocket_self_wsh.py6
-rw-r--r--dom/security/test/csp/file_win_open_blocked.html3
-rw-r--r--dom/security/test/csp/file_windowwatcher_frameA.html17
-rw-r--r--dom/security/test/csp/file_windowwatcher_subframeB.html12
-rw-r--r--dom/security/test/csp/file_windowwatcher_subframeC.html9
-rw-r--r--dom/security/test/csp/file_windowwatcher_subframeD.html6
-rw-r--r--dom/security/test/csp/file_windowwatcher_win_open.html15
-rw-r--r--dom/security/test/csp/file_worker_src.js73
-rw-r--r--dom/security/test/csp/file_worker_src_child_governs.html9
-rw-r--r--dom/security/test/csp/file_worker_src_script_governs.html9
-rw-r--r--dom/security/test/csp/file_worker_src_worker_governs.html9
-rw-r--r--dom/security/test/csp/file_xslt_inherits_csp.xml6
-rw-r--r--dom/security/test/csp/file_xslt_inherits_csp.xml^headers^2
-rw-r--r--dom/security/test/csp/file_xslt_inherits_csp.xsl26
-rw-r--r--dom/security/test/csp/main_csp_worker.html439
-rw-r--r--dom/security/test/csp/main_csp_worker.html^headers^1
-rw-r--r--dom/security/test/csp/mochitest.ini755
-rw-r--r--dom/security/test/csp/referrerdirective.sjs40
-rw-r--r--dom/security/test/csp/test_301_redirect.html74
-rw-r--r--dom/security/test/csp/test_302_redirect.html74
-rw-r--r--dom/security/test/csp/test_303_redirect.html74
-rw-r--r--dom/security/test/csp/test_307_redirect.html75
-rw-r--r--dom/security/test/csp/test_CSP.html130
-rw-r--r--dom/security/test/csp/test_allow_https_schemes.html76
-rw-r--r--dom/security/test/csp/test_base-uri.html124
-rw-r--r--dom/security/test/csp/test_blob_data_schemes.html89
-rw-r--r--dom/security/test/csp/test_blob_uri_blocks_modals.html79
-rw-r--r--dom/security/test/csp/test_block_all_mixed_content.html99
-rw-r--r--dom/security/test/csp/test_block_all_mixed_content_frame_navigation.html46
-rw-r--r--dom/security/test/csp/test_blocked_uri_in_reports.html80
-rw-r--r--dom/security/test/csp/test_blocked_uri_in_violation_event_after_redirects.html56
-rw-r--r--dom/security/test/csp/test_blocked_uri_redirect_frame_src.html60
-rw-r--r--dom/security/test/csp/test_bug1229639.html51
-rw-r--r--dom/security/test/csp/test_bug1242019.html51
-rw-r--r--dom/security/test/csp/test_bug1312272.html32
-rw-r--r--dom/security/test/csp/test_bug1388015.html46
-rw-r--r--dom/security/test/csp/test_bug1452037.html41
-rw-r--r--dom/security/test/csp/test_bug1505412.html50
-rw-r--r--dom/security/test/csp/test_bug1579094.html31
-rw-r--r--dom/security/test/csp/test_bug1738418.html28
-rw-r--r--dom/security/test/csp/test_bug1764343.html116
-rw-r--r--dom/security/test/csp/test_bug1777572.html40
-rw-r--r--dom/security/test/csp/test_bug663567.html76
-rw-r--r--dom/security/test/csp/test_bug802872.html53
-rw-r--r--dom/security/test/csp/test_bug836922_npolicies.html235
-rw-r--r--dom/security/test/csp/test_bug885433.html61
-rw-r--r--dom/security/test/csp/test_bug886164.html172
-rw-r--r--dom/security/test/csp/test_bug888172.html73
-rw-r--r--dom/security/test/csp/test_bug909029.html129
-rw-r--r--dom/security/test/csp/test_bug910139.html66
-rw-r--r--dom/security/test/csp/test_bug941404.html107
-rw-r--r--dom/security/test/csp/test_child-src_iframe.html113
-rw-r--r--dom/security/test/csp/test_child-src_worker-redirect.html125
-rw-r--r--dom/security/test/csp/test_child-src_worker.html148
-rw-r--r--dom/security/test/csp/test_child-src_worker_data.html126
-rw-r--r--dom/security/test/csp/test_connect-src.html129
-rw-r--r--dom/security/test/csp/test_csp_frame_ancestors_about_blank.html59
-rw-r--r--dom/security/test/csp/test_csp_style_src_empty_hash.html32
-rw-r--r--dom/security/test/csp/test_csp_worker_inheritance.html20
-rw-r--r--dom/security/test/csp/test_data_csp_inheritance.html36
-rw-r--r--dom/security/test/csp/test_data_csp_merge.html36
-rw-r--r--dom/security/test/csp/test_data_doc_ignore_meta_csp.html39
-rw-r--r--dom/security/test/csp/test_docwrite_meta.html86
-rw-r--r--dom/security/test/csp/test_dual_header.html66
-rw-r--r--dom/security/test/csp/test_empty_directive.html51
-rw-r--r--dom/security/test/csp/test_evalscript.html59
-rw-r--r--dom/security/test/csp/test_evalscript_allowed_by_strict_dynamic.html36
-rw-r--r--dom/security/test/csp/test_evalscript_blocked_by_strict_dynamic.html36
-rw-r--r--dom/security/test/csp/test_fontloader.html98
-rw-r--r--dom/security/test/csp/test_form-action.html105
-rw-r--r--dom/security/test/csp/test_form_action_blocks_url.html76
-rw-r--r--dom/security/test/csp/test_frame_ancestors_ro.html69
-rw-r--r--dom/security/test/csp/test_frame_src.html84
-rw-r--r--dom/security/test/csp/test_frameancestors.html160
-rw-r--r--dom/security/test/csp/test_frameancestors_userpass.html148
-rw-r--r--dom/security/test/csp/test_hash_source.html135
-rw-r--r--dom/security/test/csp/test_iframe_sandbox.html240
-rw-r--r--dom/security/test/csp/test_iframe_sandbox_srcdoc.html62
-rw-r--r--dom/security/test/csp/test_iframe_sandbox_top_1.html80
-rw-r--r--dom/security/test/csp/test_iframe_sandbox_top_1.html^headers^1
-rw-r--r--dom/security/test/csp/test_iframe_srcdoc.html140
-rw-r--r--dom/security/test/csp/test_ignore_unsafe_inline.html122
-rw-r--r--dom/security/test/csp/test_ignore_xfo.html120
-rw-r--r--dom/security/test/csp/test_image_document.html35
-rw-r--r--dom/security/test/csp/test_image_nonce.html60
-rw-r--r--dom/security/test/csp/test_independent_iframe_csp.html79
-rw-r--r--dom/security/test/csp/test_inlinescript.html123
-rw-r--r--dom/security/test/csp/test_inlinestyle.html107
-rw-r--r--dom/security/test/csp/test_invalid_source_expression.html57
-rw-r--r--dom/security/test/csp/test_leading_wildcard.html101
-rw-r--r--dom/security/test/csp/test_link_rel_preload.html80
-rw-r--r--dom/security/test/csp/test_meta_csp_self.html63
-rw-r--r--dom/security/test/csp/test_meta_element.html91
-rw-r--r--dom/security/test/csp/test_meta_header_dual.html135
-rw-r--r--dom/security/test/csp/test_meta_whitespace_skipping.html81
-rw-r--r--dom/security/test/csp/test_multi_policy_injection_bypass.html119
-rw-r--r--dom/security/test/csp/test_multipartchannel.html68
-rw-r--r--dom/security/test/csp/test_navigate_to.html158
-rw-r--r--dom/security/test/csp/test_nonce_redirects.html47
-rw-r--r--dom/security/test/csp/test_nonce_snapshot.html35
-rw-r--r--dom/security/test/csp/test_nonce_source.html122
-rw-r--r--dom/security/test/csp/test_null_baseuri.html67
-rw-r--r--dom/security/test/csp/test_object_inherit.html30
-rw-r--r--dom/security/test/csp/test_parent_location_js.html38
-rw-r--r--dom/security/test/csp/test_path_matching.html115
-rw-r--r--dom/security/test/csp/test_path_matching_redirect.html89
-rw-r--r--dom/security/test/csp/test_ping.html103
-rw-r--r--dom/security/test/csp/test_policyuri_regression_from_multipolicy.html27
-rw-r--r--dom/security/test/csp/test_punycode_host_src.html81
-rw-r--r--dom/security/test/csp/test_redirects.html143
-rw-r--r--dom/security/test/csp/test_report.html113
-rw-r--r--dom/security/test/csp/test_report_font_cache.html56
-rw-r--r--dom/security/test/csp/test_report_for_import.html109
-rw-r--r--dom/security/test/csp/test_report_uri_missing_in_report_only_header.html57
-rw-r--r--dom/security/test/csp/test_sandbox.html249
-rw-r--r--dom/security/test/csp/test_sandbox_allow_scripts.html31
-rw-r--r--dom/security/test/csp/test_scheme_relative_sources.html91
-rw-r--r--dom/security/test/csp/test_script_template.html60
-rw-r--r--dom/security/test/csp/test_security_policy_violation_event.html15
-rw-r--r--dom/security/test/csp/test_self_none_as_hostname_confusion.html55
-rw-r--r--dom/security/test/csp/test_sendbeacon.html34
-rw-r--r--dom/security/test/csp/test_service_worker.html62
-rw-r--r--dom/security/test/csp/test_strict_dynamic.html133
-rw-r--r--dom/security/test/csp/test_strict_dynamic_default_src.html136
-rw-r--r--dom/security/test/csp/test_strict_dynamic_parser_inserted.html94
-rw-r--r--dom/security/test/csp/test_subframe_run_js_if_allowed.html33
-rw-r--r--dom/security/test/csp/test_svg_inline_style.html135
-rw-r--r--dom/security/test/csp/test_uir_top_nav.html53
-rw-r--r--dom/security/test/csp/test_uir_windowwatcher.html31
-rw-r--r--dom/security/test/csp/test_upgrade_insecure.html192
-rw-r--r--dom/security/test/csp/test_upgrade_insecure_cors.html86
-rw-r--r--dom/security/test/csp/test_upgrade_insecure_docwrite_iframe.html54
-rw-r--r--dom/security/test/csp/test_upgrade_insecure_loopback.html91
-rw-r--r--dom/security/test/csp/test_upgrade_insecure_navigation.html105
-rw-r--r--dom/security/test/csp/test_upgrade_insecure_navigation_redirect.html67
-rw-r--r--dom/security/test/csp/test_upgrade_insecure_reporting.html69
-rw-r--r--dom/security/test/csp/test_websocket_localhost.html40
-rw-r--r--dom/security/test/csp/test_websocket_self.html61
-rw-r--r--dom/security/test/csp/test_win_open_blocked.html52
-rw-r--r--dom/security/test/csp/test_worker_src.html105
-rw-r--r--dom/security/test/csp/test_xslt_inherits_csp.html33
-rw-r--r--dom/security/test/csp/worker.sjs114
-rw-r--r--dom/security/test/csp/worker_helper.js91
440 files changed, 19183 insertions, 0 deletions
diff --git a/dom/security/test/csp/Ahem.ttf b/dom/security/test/csp/Ahem.ttf
new file mode 100644
index 0000000000..ac81cb0316
--- /dev/null
+++ b/dom/security/test/csp/Ahem.ttf
Binary files differ
diff --git a/dom/security/test/csp/File b/dom/security/test/csp/File
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/dom/security/test/csp/File
diff --git a/dom/security/test/csp/browser.ini b/dom/security/test/csp/browser.ini
new file mode 100644
index 0000000000..f2273f0180
--- /dev/null
+++ b/dom/security/test/csp/browser.ini
@@ -0,0 +1,23 @@
+[DEFAULT]
+support-files =
+ !/dom/security/test/csp/file_testserver.sjs
+ !/dom/security/test/csp/file_web_manifest.html
+ !/dom/security/test/csp/file_web_manifest.json
+ !/dom/security/test/csp/file_web_manifest.json^headers^
+ !/dom/security/test/csp/file_web_manifest_https.html
+ !/dom/security/test/csp/file_web_manifest_https.json
+ !/dom/security/test/csp/file_web_manifest_mixed_content.html
+ !/dom/security/test/csp/file_web_manifest_remote.html
+ file_test_browser_bookmarklets.html
+ file_test_browser_bookmarklets.html^headers^
+[browser_test_web_manifest.js]
+[browser_test_web_manifest_mixed_content.js]
+[browser_test_bookmarklets.js]
+[browser_test_uir_optional_clicks.js]
+support-files =
+ file_csp_meta_uir.html
+[browser_manifest-src-override-default-src.js]
+[browser_pdfjs_not_subject_to_csp.js]
+support-files =
+ dummy.pdf
+ file_pdfjs_not_subject_to_csp.html
diff --git a/dom/security/test/csp/browser_manifest-src-override-default-src.js b/dom/security/test/csp/browser_manifest-src-override-default-src.js
new file mode 100644
index 0000000000..3f274d8c30
--- /dev/null
+++ b/dom/security/test/csp/browser_manifest-src-override-default-src.js
@@ -0,0 +1,125 @@
+/*
+ * Description of the tests:
+ * Tests check that default-src can be overridden by manifest-src.
+ */
+/*globals Cu, is, ok*/
+"use strict";
+const { ManifestObtainer } = ChromeUtils.importESModule(
+ "resource://gre/modules/ManifestObtainer.sys.mjs"
+);
+const path = "/tests/dom/security/test/csp/";
+const testFile = `${path}file_web_manifest.html`;
+const mixedContentFile = `${path}file_web_manifest_mixed_content.html`;
+const server = `${path}file_testserver.sjs`;
+const defaultURL = new URL(`https://example.org${server}`);
+const mixedURL = new URL(`http://mochi.test:8888${server}`);
+
+// Enable web manifest processing.
+Services.prefs.setBoolPref("dom.manifest.enabled", true);
+
+const tests = [
+ // Check interaction with default-src and another origin,
+ // CSP allows fetching from example.org, so manifest should load.
+ {
+ expected: `CSP manifest-src overrides default-src of elsewhere.com`,
+ get tabURL() {
+ const url = new URL(defaultURL);
+ url.searchParams.append("file", testFile);
+ url.searchParams.append("cors", "*");
+ url.searchParams.append(
+ "csp",
+ "default-src http://elsewhere.com; manifest-src http://example.org"
+ );
+ return url.href;
+ },
+ run(manifest) {
+ is(manifest.name, "loaded", this.expected);
+ },
+ },
+ // Check interaction with default-src none,
+ // CSP allows fetching manifest from example.org, so manifest should load.
+ {
+ expected: `CSP manifest-src overrides default-src`,
+ get tabURL() {
+ const url = new URL(mixedURL);
+ url.searchParams.append("file", mixedContentFile);
+ url.searchParams.append("cors", "http://test:80");
+ url.searchParams.append(
+ "csp",
+ "default-src 'self'; manifest-src http://test:80"
+ );
+ return url.href;
+ },
+ run(manifest) {
+ is(manifest.name, "loaded", this.expected);
+ },
+ },
+];
+
+//jscs:disable
+add_task(async function () {
+ //jscs:enable
+ const testPromises = tests.map(test => {
+ const tabOptions = {
+ gBrowser,
+ url: test.tabURL,
+ skipAnimation: true,
+ };
+ return BrowserTestUtils.withNewTab(tabOptions, browser =>
+ testObtainingManifest(browser, test)
+ );
+ });
+ await Promise.all(testPromises);
+});
+
+async function testObtainingManifest(aBrowser, aTest) {
+ const expectsBlocked = aTest.expected.includes("block");
+ const observer = expectsBlocked ? createNetObserver(aTest) : null;
+ // Expect an exception (from promise rejection) if there a content policy
+ // that is violated.
+ try {
+ const manifest = await ManifestObtainer.browserObtainManifest(aBrowser);
+ aTest.run(manifest);
+ } catch (e) {
+ const wasBlocked = e.message.includes(
+ "NetworkError when attempting to fetch resource"
+ );
+ ok(
+ wasBlocked,
+ `Expected promise rejection obtaining ${aTest.tabURL}: ${e.message}`
+ );
+ if (observer) {
+ await observer.untilFinished;
+ }
+ }
+}
+
+// Helper object used to observe policy violations. It waits 1 seconds
+// for a response, and then times out causing its associated test to fail.
+function createNetObserver(test) {
+ let finishedTest;
+ let success = false;
+ const finished = new Promise(resolver => {
+ finishedTest = resolver;
+ });
+ const timeoutId = setTimeout(() => {
+ if (!success) {
+ test.run("This test timed out.");
+ finishedTest();
+ }
+ }, 1000);
+ var observer = {
+ get untilFinished() {
+ return finished;
+ },
+ observe(subject, topic) {
+ SpecialPowers.removeObserver(observer, "csp-on-violate-policy");
+ test.run(topic);
+ finishedTest();
+ clearTimeout(timeoutId);
+ success = true;
+ },
+ };
+ SpecialPowers.addObserver(observer, "csp-on-violate-policy");
+ return observer;
+}
diff --git a/dom/security/test/csp/browser_pdfjs_not_subject_to_csp.js b/dom/security/test/csp/browser_pdfjs_not_subject_to_csp.js
new file mode 100644
index 0000000000..a765f5bcff
--- /dev/null
+++ b/dom/security/test/csp/browser_pdfjs_not_subject_to_csp.js
@@ -0,0 +1,48 @@
+"use strict";
+
+const TEST_PATH = getRootDirectory(gTestPath).replace(
+ "chrome://mochitests/content",
+ "https://example.com"
+);
+
+add_task(async function () {
+ await SpecialPowers.pushPrefEnv({
+ set: [["pdfjs.eventBusDispatchToDOM", true]],
+ });
+ await BrowserTestUtils.withNewTab(
+ TEST_PATH + "file_pdfjs_not_subject_to_csp.html",
+ async function (browser) {
+ let pdfPromise = BrowserTestUtils.waitForContentEvent(
+ browser,
+ "documentloaded",
+ false,
+ null,
+ true
+ );
+
+ await ContentTask.spawn(browser, {}, async function () {
+ let pdfButton = content.document.getElementById("pdfButton");
+ pdfButton.click();
+ });
+
+ await pdfPromise;
+
+ await ContentTask.spawn(browser, {}, async function () {
+ let pdfFrame = content.document.getElementById("pdfFrame");
+ // 1) Sanity that we have loaded the PDF using a blob
+ ok(pdfFrame.src.startsWith("blob:"), "it's a blob URL");
+
+ // 2) Ensure that the PDF has actually loaded
+ ok(
+ pdfFrame.contentDocument.querySelector("div#viewer"),
+ "document content has viewer UI"
+ );
+
+ // 3) Ensure we have the correct CSP attached
+ let cspJSON = pdfFrame.contentDocument.cspJSON;
+ ok(cspJSON.includes("script-src"), "found script-src directive");
+ ok(cspJSON.includes("allowPDF"), "found script-src nonce value");
+ });
+ }
+ );
+});
diff --git a/dom/security/test/csp/browser_test_bookmarklets.js b/dom/security/test/csp/browser_test_bookmarklets.js
new file mode 100644
index 0000000000..08b5ab0758
--- /dev/null
+++ b/dom/security/test/csp/browser_test_bookmarklets.js
@@ -0,0 +1,82 @@
+"use strict";
+
+let BASE_URL = getRootDirectory(gTestPath).replace(
+ "chrome://mochitests/content/",
+ "https://example.com/"
+);
+const DUMMY_URL = BASE_URL + "file_test_browser_bookmarklets.html";
+
+function makeBookmarkFor(url, keyword) {
+ return Promise.all([
+ PlacesUtils.bookmarks.insert({
+ parentGuid: PlacesUtils.bookmarks.unfiledGuid,
+ title: "bookmarklet",
+ url,
+ }),
+ PlacesUtils.keywords.insert({ url, keyword }),
+ ]);
+}
+/* Test Description:
+ * 1 - Load a Page with CSP script-src: none
+ * 2 - Create a bookmarklet with javascript:window.open('about:blank')
+ * 3 - Select and enter the bookmarklet
+ * A new tab with about:blank should be opened
+ */
+add_task(async function openKeywordBookmarkWithWindowOpen() {
+ // This is the current default, but let's not assume that...
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ ["browser.link.open_newwindow", 3],
+ ["dom.disable_open_during_load", true],
+ ],
+ });
+
+ let moztab;
+ let tabOpened = BrowserTestUtils.openNewForegroundTab(
+ gBrowser,
+ DUMMY_URL
+ ).then(tab => {
+ moztab = tab;
+ });
+ let keywordForBM = "openNewWindowBookmarklet";
+
+ let bookmarkInfo;
+ let bookmarkCreated = makeBookmarkFor(
+ `javascript: window.open("about:blank")`,
+ keywordForBM
+ ).then(values => {
+ bookmarkInfo = values[0];
+ });
+ await Promise.all([tabOpened, bookmarkCreated]);
+
+ registerCleanupFunction(function () {
+ return Promise.all([
+ PlacesUtils.bookmarks.remove(bookmarkInfo),
+ PlacesUtils.keywords.remove(keywordForBM),
+ ]);
+ });
+ gURLBar.value = keywordForBM;
+ gURLBar.focus();
+
+ let tabCreatedPromise = BrowserTestUtils.waitForEvent(
+ gBrowser.tabContainer,
+ "TabOpen"
+ );
+ EventUtils.synthesizeKey("KEY_Enter");
+ info("Waiting for tab being created");
+ let { target: tab } = await tabCreatedPromise;
+ info("Got tab");
+ let browser = tab.linkedBrowser;
+ if (!browser.currentURI || browser.currentURI.spec != "about:blank") {
+ info("Waiting for browser load");
+ await BrowserTestUtils.browserLoaded(browser, false, "about:blank");
+ }
+ is(
+ browser.currentURI && browser.currentURI.spec,
+ "about:blank",
+ "Tab with expected URL loaded."
+ );
+ info("Waiting to remove tab");
+ BrowserTestUtils.removeTab(tab);
+ BrowserTestUtils.removeTab(moztab);
+});
diff --git a/dom/security/test/csp/browser_test_uir_optional_clicks.js b/dom/security/test/csp/browser_test_uir_optional_clicks.js
new file mode 100644
index 0000000000..57e1f64f1a
--- /dev/null
+++ b/dom/security/test/csp/browser_test_uir_optional_clicks.js
@@ -0,0 +1,36 @@
+"use strict";
+
+const TEST_PATH_HTTP = getRootDirectory(gTestPath).replace(
+ "chrome://mochitests/content",
+ "http://example.com"
+);
+const TEST_PATH_HTTPS = getRootDirectory(gTestPath).replace(
+ "chrome://mochitests/content",
+ "https://example.com"
+);
+
+add_task(async function () {
+ await SpecialPowers.pushPrefEnv({
+ set: [["dom.security.https_first", false]],
+ });
+ await BrowserTestUtils.withNewTab(
+ TEST_PATH_HTTPS + "file_csp_meta_uir.html",
+ async function (browser) {
+ let newTabPromise = BrowserTestUtils.waitForNewTab(gBrowser, null, true);
+ BrowserTestUtils.synthesizeMouse(
+ "#mylink",
+ 2,
+ 2,
+ { accelKey: true },
+ browser
+ );
+ let tab = await newTabPromise;
+ is(
+ tab.linkedBrowser.currentURI.scheme,
+ "https",
+ "Should have opened https page."
+ );
+ BrowserTestUtils.removeTab(tab);
+ }
+ );
+});
diff --git a/dom/security/test/csp/browser_test_web_manifest.js b/dom/security/test/csp/browser_test_web_manifest.js
new file mode 100644
index 0000000000..bdf62ab397
--- /dev/null
+++ b/dom/security/test/csp/browser_test_web_manifest.js
@@ -0,0 +1,239 @@
+/*
+ * Description of the tests:
+ * These tests check for conformance to the CSP spec as they relate to Web Manifests.
+ *
+ * In particular, the tests check that default-src and manifest-src directives are
+ * are respected by the ManifestObtainer.
+ */
+/*globals Cu, is, ok*/
+"use strict";
+const { ManifestObtainer } = ChromeUtils.importESModule(
+ "resource://gre/modules/ManifestObtainer.sys.mjs"
+);
+const path = "/tests/dom/security/test/csp/";
+const testFile = `${path}file_web_manifest.html`;
+const remoteFile = `${path}file_web_manifest_remote.html`;
+const httpsManifest = `${path}file_web_manifest_https.html`;
+const server = `${path}file_testserver.sjs`;
+const defaultURL = new URL(`http://example.org${server}`);
+const secureURL = new URL(`https://example.com:443${server}`);
+
+// Enable web manifest processing.
+Services.prefs.setBoolPref("dom.manifest.enabled", true);
+
+const tests = [
+ // CSP block everything, so trying to load a manifest
+ // will result in a policy violation.
+ {
+ expected: "default-src 'none' blocks fetching manifest.",
+ get tabURL() {
+ const url = new URL(defaultURL);
+ url.searchParams.append("file", testFile);
+ url.searchParams.append("csp", "default-src 'none'");
+ return url.href;
+ },
+ run(topic) {
+ is(topic, "csp-on-violate-policy", this.expected);
+ },
+ },
+ // CSP allows fetching only from mochi.test:8888,
+ // so trying to load a manifest from same origin
+ // triggers a CSP violation.
+ {
+ expected: "default-src mochi.test:8888 blocks manifest fetching.",
+ get tabURL() {
+ const url = new URL(defaultURL);
+ url.searchParams.append("file", testFile);
+ url.searchParams.append("csp", "default-src mochi.test:8888");
+ return url.href;
+ },
+ run(topic) {
+ is(topic, "csp-on-violate-policy", this.expected);
+ },
+ },
+ // CSP restricts fetching to 'self', so allowing the manifest
+ // to load. The name of the manifest is then checked.
+ {
+ expected: "CSP default-src 'self' allows fetch of manifest.",
+ get tabURL() {
+ const url = new URL(defaultURL);
+ url.searchParams.append("file", testFile);
+ url.searchParams.append("csp", "default-src 'self'");
+ return url.href;
+ },
+ run(manifest) {
+ is(manifest.name, "loaded", this.expected);
+ },
+ },
+ // CSP only allows fetching from mochi.test:8888 and remoteFile
+ // requests a manifest from that origin, so manifest should load.
+ {
+ expected: "CSP default-src mochi.test:8888 allows fetching manifest.",
+ get tabURL() {
+ const url = new URL(defaultURL);
+ url.searchParams.append("file", remoteFile);
+ url.searchParams.append("csp", "default-src http://mochi.test:8888");
+ return url.href;
+ },
+ run(manifest) {
+ is(manifest.name, "loaded", this.expected);
+ },
+ },
+ // default-src blocks everything, so any attempt to
+ // fetch a manifest from another origin will trigger a
+ // policy violation.
+ {
+ expected: "default-src 'none' blocks mochi.test:8888",
+ get tabURL() {
+ const url = new URL(defaultURL);
+ url.searchParams.append("file", remoteFile);
+ url.searchParams.append("csp", "default-src 'none'");
+ return url.href;
+ },
+ run(topic) {
+ is(topic, "csp-on-violate-policy", this.expected);
+ },
+ },
+ // CSP allows fetching from self, so manifest should load.
+ {
+ expected: "CSP manifest-src allows self",
+ get tabURL() {
+ const url = new URL(defaultURL);
+ url.searchParams.append("file", testFile);
+ url.searchParams.append("csp", "manifest-src 'self'");
+ return url.href;
+ },
+ run(manifest) {
+ is(manifest.name, "loaded", this.expected);
+ },
+ },
+ // CSP allows fetching from example.org, so manifest should load.
+ {
+ expected: "CSP manifest-src allows http://example.org",
+ get tabURL() {
+ const url = new URL(defaultURL);
+ url.searchParams.append("file", testFile);
+ url.searchParams.append("csp", "manifest-src http://example.org");
+ return url.href;
+ },
+ run(manifest) {
+ is(manifest.name, "loaded", this.expected);
+ },
+ },
+ {
+ expected: "CSP manifest-src allows mochi.test:8888",
+ get tabURL() {
+ const url = new URL(defaultURL);
+ url.searchParams.append("file", remoteFile);
+ url.searchParams.append("cors", "*");
+ url.searchParams.append(
+ "csp",
+ "default-src *; manifest-src http://mochi.test:8888"
+ );
+ return url.href;
+ },
+ run(manifest) {
+ is(manifest.name, "loaded", this.expected);
+ },
+ },
+ // CSP restricts fetching to mochi.test:8888, but the test
+ // file is at example.org. Hence, a policy violation is
+ // triggered.
+ {
+ expected: "CSP blocks manifest fetching from example.org.",
+ get tabURL() {
+ const url = new URL(defaultURL);
+ url.searchParams.append("file", testFile);
+ url.searchParams.append("csp", "manifest-src mochi.test:8888");
+ return url.href;
+ },
+ run(topic) {
+ is(topic, "csp-on-violate-policy", this.expected);
+ },
+ },
+ // CSP is set to only allow manifest to be loaded from same origin,
+ // but the remote file attempts to load from a different origin. Thus
+ // this causes a CSP violation.
+ {
+ expected: "CSP manifest-src 'self' blocks cross-origin fetch.",
+ get tabURL() {
+ const url = new URL(defaultURL);
+ url.searchParams.append("file", remoteFile);
+ url.searchParams.append("csp", "manifest-src 'self'");
+ return url.href;
+ },
+ run(topic) {
+ is(topic, "csp-on-violate-policy", this.expected);
+ },
+ },
+ // CSP allows fetching over TLS from example.org, so manifest should load.
+ {
+ expected: "CSP manifest-src allows example.com over TLS",
+ get tabURL() {
+ // secureURL loads https://example.com:443
+ // and gets manifest from https://example.org:443
+ const url = new URL(secureURL);
+ url.searchParams.append("file", httpsManifest);
+ url.searchParams.append("cors", "*");
+ url.searchParams.append("csp", "manifest-src https://example.com:443");
+ return url.href;
+ },
+ run(manifest) {
+ is(manifest.name, "loaded", this.expected);
+ },
+ },
+];
+
+//jscs:disable
+add_task(async function () {
+ //jscs:enable
+ const testPromises = tests.map(test => {
+ const tabOptions = {
+ gBrowser,
+ url: test.tabURL,
+ skipAnimation: true,
+ };
+ return BrowserTestUtils.withNewTab(tabOptions, browser =>
+ testObtainingManifest(browser, test)
+ );
+ });
+ await Promise.all(testPromises);
+});
+
+async function testObtainingManifest(aBrowser, aTest) {
+ const waitForObserver = waitForNetObserver(aBrowser, aTest);
+ // Expect an exception (from promise rejection) if there a content policy
+ // that is violated.
+ try {
+ const manifest = await ManifestObtainer.browserObtainManifest(aBrowser);
+ aTest.run(manifest);
+ } catch (e) {
+ const wasBlocked = e.message.includes(
+ "NetworkError when attempting to fetch resource"
+ );
+ ok(
+ wasBlocked,
+ `Expected promise rejection obtaining ${aTest.tabURL}: ${e.message}`
+ );
+ } finally {
+ await waitForObserver;
+ }
+}
+
+// Helper object used to observe policy violations when blocking is expected.
+function waitForNetObserver(aBrowser, aTest) {
+ // We don't need to wait for violation, so just resolve
+ if (!aTest.expected.includes("block")) {
+ return Promise.resolve();
+ }
+
+ return ContentTask.spawn(aBrowser, [], () => {
+ return new Promise(resolve => {
+ function observe(subject, topic) {
+ Services.obs.removeObserver(observe, "csp-on-violate-policy");
+ resolve();
+ }
+ Services.obs.addObserver(observe, "csp-on-violate-policy");
+ });
+ }).then(() => aTest.run("csp-on-violate-policy"));
+}
diff --git a/dom/security/test/csp/browser_test_web_manifest_mixed_content.js b/dom/security/test/csp/browser_test_web_manifest_mixed_content.js
new file mode 100644
index 0000000000..0cf55b80e3
--- /dev/null
+++ b/dom/security/test/csp/browser_test_web_manifest_mixed_content.js
@@ -0,0 +1,57 @@
+/*
+ * Description of the test:
+ * Check that mixed content blocker works prevents fetches of
+ * mixed content manifests.
+ */
+/*globals Cu, ok*/
+"use strict";
+const { ManifestObtainer } = ChromeUtils.importESModule(
+ "resource://gre/modules/ManifestObtainer.sys.mjs"
+);
+const path = "/tests/dom/security/test/csp/";
+const mixedContent = `${path}file_web_manifest_mixed_content.html`;
+const server = `${path}file_testserver.sjs`;
+const secureURL = new URL(`https://example.com${server}`);
+const tests = [
+ // Trying to load mixed content in file_web_manifest_mixed_content.html
+ // needs to result in an error.
+ {
+ expected: "Mixed Content Blocker prevents fetching manifest.",
+ get tabURL() {
+ const url = new URL(secureURL);
+ url.searchParams.append("file", mixedContent);
+ return url.href;
+ },
+ run(error) {
+ // Check reason for error.
+ const check = /NetworkError when attempting to fetch resource/.test(
+ error.message
+ );
+ ok(check, this.expected);
+ },
+ },
+];
+
+//jscs:disable
+add_task(async function () {
+ //jscs:enable
+ const testPromises = tests.map(test => {
+ const tabOptions = {
+ gBrowser,
+ url: test.tabURL,
+ skipAnimation: true,
+ };
+ return BrowserTestUtils.withNewTab(tabOptions, browser =>
+ testObtainingManifest(browser, test)
+ );
+ });
+ await Promise.all(testPromises);
+});
+
+async function testObtainingManifest(aBrowser, aTest) {
+ try {
+ await ManifestObtainer.browserObtainManifest(aBrowser);
+ } catch (e) {
+ aTest.run(e);
+ }
+}
diff --git a/dom/security/test/csp/dummy.pdf b/dom/security/test/csp/dummy.pdf
new file mode 100644
index 0000000000..7ad87e3c2e
--- /dev/null
+++ b/dom/security/test/csp/dummy.pdf
Binary files differ
diff --git a/dom/security/test/csp/file_CSP.css b/dom/security/test/csp/file_CSP.css
new file mode 100644
index 0000000000..6835c4d4ad
--- /dev/null
+++ b/dom/security/test/csp/file_CSP.css
@@ -0,0 +1,20 @@
+/*
+ * Moved this CSS from an inline stylesheet to an external file when we added
+ * inline-style blocking in bug 763879.
+ * This test may hang if the load for this .css file is blocked due to a
+ * malfunction of CSP, but should pass if the style_good test passes.
+ */
+
+/* CSS font embedding tests */
+@font-face {
+ font-family: "arbitrary_good";
+ src: url('file_CSP.sjs?testid=font_good&type=application/octet-stream');
+}
+@font-face {
+ font-family: "arbitrary_bad";
+ src: url('http://example.org/tests/dom/security/test/csp/file_CSP.sjs?testid=font_bad&type=application/octet-stream');
+}
+
+.div_arbitrary_good { font-family: "arbitrary_good"; }
+.div_arbitrary_bad { font-family: "arbitrary_bad"; }
+
diff --git a/dom/security/test/csp/file_CSP.sjs b/dom/security/test/csp/file_CSP.sjs
new file mode 100644
index 0000000000..ff41690078
--- /dev/null
+++ b/dom/security/test/csp/file_CSP.sjs
@@ -0,0 +1,24 @@
+// SJS file for CSP mochitests
+
+function handleRequest(request, response) {
+ var query = {};
+ request.queryString.split("&").forEach(function (val) {
+ var [name, value] = val.split("=");
+ query[name] = unescape(value);
+ });
+
+ var isPreflight = request.method == "OPTIONS";
+
+ //avoid confusing cache behaviors
+ response.setHeader("Cache-Control", "no-cache", false);
+
+ if ("type" in query) {
+ response.setHeader("Content-Type", unescape(query.type), false);
+ } else {
+ response.setHeader("Content-Type", "text/html", false);
+ }
+
+ if ("content" in query) {
+ response.write(unescape(query.content));
+ }
+}
diff --git a/dom/security/test/csp/file_allow_https_schemes.html b/dom/security/test/csp/file_allow_https_schemes.html
new file mode 100644
index 0000000000..787e683e87
--- /dev/null
+++ b/dom/security/test/csp/file_allow_https_schemes.html
@@ -0,0 +1,14 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title>Bug 826805 - CSP: Allow http and https for scheme-less sources</title>
+ </head>
+ <body>
+ <div id="testdiv">blocked</div>
+ <!--
+ We resue file_path_matching.js which just updates the contents of 'testdiv' to contain allowed.
+ Note, that we are loading the file_path_matchting.js using a scheme of 'https'.
+ -->
+ <script src="https://example.com/tests/dom/security/test/csp/file_path_matching.js#foo"></script>
+</body>
+</html>
diff --git a/dom/security/test/csp/file_base_uri_server.sjs b/dom/security/test/csp/file_base_uri_server.sjs
new file mode 100644
index 0000000000..ba130e99e4
--- /dev/null
+++ b/dom/security/test/csp/file_base_uri_server.sjs
@@ -0,0 +1,59 @@
+// Custom *.sjs file specifically for the needs of
+// https://bugzilla.mozilla.org/show_bug.cgi?id=1263286
+
+"use strict";
+Components.utils.importGlobalProperties(["URLSearchParams"]);
+
+const PRE_BASE = `
+ <!DOCTYPE HTML>
+ <html>
+ <head>
+ <title>Bug 1045897 - Test CSP base-uri directive</title>`;
+
+const REGULAR_POST_BASE = `
+ </head>
+ <body onload='window.parent.postMessage({result: document.baseURI}, "*");'>
+ <!-- just making use of the 'base' tag for this test -->
+ </body>
+ </html>`;
+
+const SCRIPT_POST_BASE = `
+ </head>
+ <body>
+ <script>
+ document.getElementById("base1").removeAttribute("href");
+ window.parent.postMessage({result: document.baseURI}, "*");
+ </script>
+ </body>
+ </html>`;
+
+function handleRequest(request, response) {
+ const query = new URLSearchParams(request.queryString);
+
+ // avoid confusing cache behaviors
+ response.setHeader("Cache-Control", "no-cache", false);
+
+ // Deliver the CSP policy encoded in the URL
+ response.setHeader("Content-Security-Policy", query.get("csp"), false);
+
+ // Send HTML to test allowed/blocked behaviors
+ response.setHeader("Content-Type", "text/html", false);
+ response.write(PRE_BASE);
+ var base1 = '<base id="base1" href="' + query.get("base1") + '">';
+ var base2 = '<base id="base2" href="' + query.get("base2") + '">';
+ response.write(base1 + base2);
+
+ if (query.get("action") === "enforce-csp") {
+ response.write(REGULAR_POST_BASE);
+ return;
+ }
+
+ if (query.get("action") === "remove-base1") {
+ response.write(SCRIPT_POST_BASE);
+ return;
+ }
+
+ // we should never get here, but just in case
+ // return something unexpected
+ response.write("do'h");
+}
diff --git a/dom/security/test/csp/file_blob_data_schemes.html b/dom/security/test/csp/file_blob_data_schemes.html
new file mode 100644
index 0000000000..0a4a491606
--- /dev/null
+++ b/dom/security/test/csp/file_blob_data_schemes.html
@@ -0,0 +1,49 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 1086999 - Wildcard should not match blob:, data:</title>
+</head>
+<body>
+<script type="text/javascript">
+
+var base64data =
+"iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12" +
+"P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==";
+
+
+// construct an image element using *data:*
+var data_src = "data:image/png;base64," + base64data;
+var data_img = document.createElement('img');
+data_img.onload = function() {
+ window.parent.postMessage({scheme: "data", result: "allowed"}, "*");
+}
+data_img.onerror = function() {
+ window.parent.postMessage({scheme: "data", result: "blocked"}, "*");
+}
+data_img.src = data_src;
+document.body.appendChild(data_img);
+
+
+// construct an image element using *blob:*
+var byteCharacters = atob(base64data);
+var byteNumbers = new Array(byteCharacters.length);
+for (var i = 0; i < byteCharacters.length; i++) {
+ byteNumbers[i] = byteCharacters.charCodeAt(i);
+}
+var byteArray = new Uint8Array(byteNumbers);
+var blob = new Blob([byteArray], {type: "image/png"});
+var imageUrl = URL.createObjectURL( blob );
+
+var blob_img = document.createElement('img');
+blob_img.onload = function() {
+ window.parent.postMessage({scheme: "blob", result: "allowed"}, "*");
+}
+blob_img.onerror = function() {
+ window.parent.postMessage({scheme: "blob", result: "blocked"}, "*");
+}
+blob_img.src = imageUrl;
+document.body.appendChild(blob_img);
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/file_blob_top_nav_block_modals.html b/dom/security/test/csp/file_blob_top_nav_block_modals.html
new file mode 100644
index 0000000000..545f6cffff
--- /dev/null
+++ b/dom/security/test/csp/file_blob_top_nav_block_modals.html
@@ -0,0 +1,18 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+</head>
+<body>
+<script>
+ // If the alert box is blocked correctly by the CSP then postMessage will
+ // send the message and test passes.
+ var text = "<script>alert(document.domain);window.opener.postMessage("+
+ "{\"test\": \"block_top_nav_alert_test\", \"msg\": "+
+ "\"blob top nav alert blocked by CSP\"}, \"*\")<\/script>";
+ var blob = new Blob([text], {type : 'text/html'});
+ var url = URL.createObjectURL(blob);
+ location.href=url;
+</script>
+</body>
+</html> \ No newline at end of file
diff --git a/dom/security/test/csp/file_blob_top_nav_block_modals.html^headers^ b/dom/security/test/csp/file_blob_top_nav_block_modals.html^headers^
new file mode 100644
index 0000000000..e2d945d556
--- /dev/null
+++ b/dom/security/test/csp/file_blob_top_nav_block_modals.html^headers^
@@ -0,0 +1 @@
+Content-Security-Policy: sandbox allow-scripts; \ No newline at end of file
diff --git a/dom/security/test/csp/file_blob_uri_blocks_modals.html b/dom/security/test/csp/file_blob_uri_blocks_modals.html
new file mode 100644
index 0000000000..caf2a5de41
--- /dev/null
+++ b/dom/security/test/csp/file_blob_uri_blocks_modals.html
@@ -0,0 +1,27 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+</head>
+<body>
+<!-- iframe loading the blob url with null origin -->
+<iframe id="blobFrame"></iframe>
+<script>
+ // If the alert box is blocked correctly by the CSP then postMessage will
+ // send the message and test passes.
+ var alertScriptText = "data:text/html,<script>location=URL.createObjectURL(" +
+ "new Blob(['<script>alert(document.URL);parent.parent.postMessage(" +
+ "{\"test\": \"block_alert_test\", \"msg\": \"alert blocked by" +
+ " CSP\"}, \"*\");<\\/script>'], {type:\"text/html\"}));<\/script>";
+ document.getElementById("blobFrame").src=alertScriptText;
+ try {
+ var w = window.open("http://www.example.com","newwindow");
+ parent.postMessage({"test": "block_window_open_test",
+ "msg": "new window not blocked by CSP"},"*");
+ } catch(err) {
+ parent.postMessage({"test": "block_window_open_test",
+ "msg": "window blocked by CSP"},"*");
+ }
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/file_blob_uri_blocks_modals.html^headers^ b/dom/security/test/csp/file_blob_uri_blocks_modals.html^headers^
new file mode 100644
index 0000000000..e2d945d556
--- /dev/null
+++ b/dom/security/test/csp/file_blob_uri_blocks_modals.html^headers^
@@ -0,0 +1 @@
+Content-Security-Policy: sandbox allow-scripts; \ No newline at end of file
diff --git a/dom/security/test/csp/file_block_all_mcb.sjs b/dom/security/test/csp/file_block_all_mcb.sjs
new file mode 100644
index 0000000000..003c9df57c
--- /dev/null
+++ b/dom/security/test/csp/file_block_all_mcb.sjs
@@ -0,0 +1,78 @@
+// custom *.sjs for Bug 1122236
+// CSP: 'block-all-mixed-content'
+
+const HEAD =
+ "<!DOCTYPE HTML>" +
+ '<html><head><meta charset="utf-8">' +
+ "<title>Bug 1122236 - CSP: Implement block-all-mixed-content</title>" +
+ "</head>";
+
+const CSP_ALLOW =
+ '<meta http-equiv="Content-Security-Policy" content="img-src *">';
+
+const CSP_BLOCK =
+ '<meta http-equiv="Content-Security-Policy" content="block-all-mixed-content">';
+
+const BODY =
+ "<body>" +
+ '<img id="testimage" src="http://mochi.test:8888/tests/image/test/mochitest/blue.png"></img>' +
+ '<script type="application/javascript">' +
+ ' var myImg = document.getElementById("testimage");' +
+ " myImg.onload = function(e) {" +
+ ' window.parent.postMessage({result: "img-loaded"}, "*");' +
+ " };" +
+ " myImg.onerror = function(e) {" +
+ ' window.parent.postMessage({result: "img-blocked"}, "*");' +
+ " };" +
+ "</script>" +
+ "</body>" +
+ "</html>";
+
+// We have to use this special code fragment, in particular '?nocache' to trigger an
+// actual network load rather than loading the image from the cache.
+const BODY_CSPRO =
+ "<body>" +
+ '<img id="testimage" src="http://mochi.test:8888/tests/image/test/mochitest/blue.png?nocache"></img>' +
+ '<script type="application/javascript">' +
+ ' var myImg = document.getElementById("testimage");' +
+ " myImg.onload = function(e) {" +
+ ' window.parent.postMessage({result: "img-loaded"}, "*");' +
+ " };" +
+ " myImg.onerror = function(e) {" +
+ ' window.parent.postMessage({result: "img-blocked"}, "*");' +
+ " };" +
+ "</script>" +
+ "</body>" +
+ "</html>";
+
+function handleRequest(request, response) {
+ // avoid confusing cache behaviors
+ response.setHeader("Cache-Control", "no-cache", false);
+
+ var queryString = request.queryString;
+
+ if (queryString === "csp-block") {
+ response.write(HEAD + CSP_BLOCK + BODY);
+ return;
+ }
+ if (queryString === "csp-allow") {
+ response.write(HEAD + CSP_ALLOW + BODY);
+ return;
+ }
+ if (queryString === "no-csp") {
+ response.write(HEAD + BODY);
+ return;
+ }
+ if (queryString === "cspro-block") {
+ // CSP RO is not supported in meta tag, let's use the header
+ response.setHeader(
+ "Content-Security-Policy-Report-Only",
+ "block-all-mixed-content",
+ false
+ );
+ response.write(HEAD + BODY_CSPRO);
+ return;
+ }
+ // we should never get here but just in case return something unexpected
+ response.write("do'h");
+}
diff --git a/dom/security/test/csp/file_block_all_mixed_content_frame_navigation1.html b/dom/security/test/csp/file_block_all_mixed_content_frame_navigation1.html
new file mode 100644
index 0000000000..fdc1ae87ac
--- /dev/null
+++ b/dom/security/test/csp/file_block_all_mixed_content_frame_navigation1.html
@@ -0,0 +1,19 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <meta http-equiv="Content-Security-Policy" content="block-all-mixed-content">
+ <title>Bug 1122236 - CSP: Implement block-all-mixed-content</title>
+</head>
+<body>
+<b>user clicks and navigates from https://b.com to http://c.com</b>
+
+<a id="navlink" href="http://example.com/tests/dom/security/test/csp/file_block_all_mixed_content_frame_navigation2.html">foo</a>
+
+<script class="testbody" type="text/javascript">
+ // click the link to start the frame navigation
+ document.getElementById("navlink").click();
+</script>
+
+</body>
+</html>
diff --git a/dom/security/test/csp/file_block_all_mixed_content_frame_navigation2.html b/dom/security/test/csp/file_block_all_mixed_content_frame_navigation2.html
new file mode 100644
index 0000000000..4c4084e9ed
--- /dev/null
+++ b/dom/security/test/csp/file_block_all_mixed_content_frame_navigation2.html
@@ -0,0 +1,15 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Bug 1122236 - CSP: Implement block-all-mixed-content</title>
+</head>
+<body>
+<b>http://c.com loaded, let's tell the parent</b>
+
+<script class="testbody" type="text/javascript">
+ window.parent.postMessage({result: "frame-navigated"}, "*");
+</script>
+
+</body>
+</html>
diff --git a/dom/security/test/csp/file_blocked_uri_in_violation_event_after_redirects.html b/dom/security/test/csp/file_blocked_uri_in_violation_event_after_redirects.html
new file mode 100644
index 0000000000..74af0ff767
--- /dev/null
+++ b/dom/security/test/csp/file_blocked_uri_in_violation_event_after_redirects.html
@@ -0,0 +1,39 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 1542194 - Check blockedURI in violation reports after redirects</title>
+ <meta http-equiv="Content-Security-Policy" content="default-src 'unsafe-inline' http://example.com">
+</head>
+<body>
+<button id="test1" onclick="createAndNavFrame('?test1a#ref1a')">Test 1: 302 redirect</button>
+<button id="test2" onclick="createAndNavFrame('?test2a#ref2a')">Test 2: JS redirect</button>
+<button id="test3" onclick="createAndNavFrame('?test3a#ref3a')">Test 3: Link navigation</button>
+<div id="div"></div>
+<script>
+ const SERVER_LOCATION =
+ "http://example.com/tests/dom/security/test/csp/file_blocked_uri_in_violation_event_after_redirects.sjs";
+
+ document.addEventListener('securitypolicyviolation', e => {
+ // just forward the blockedURI to the parent
+ window.parent.postMessage({blockedURI: e.blockedURI}, '*');
+ });
+
+ function createAndNavFrame(aTest) {
+ let myFrame = document.createElement('iframe');
+ myFrame.src = SERVER_LOCATION + aTest;
+ div.appendChild(myFrame);
+ }
+
+ window.onload = function() {
+ let button1 = document.getElementById("test1");
+ button1.click();
+
+ let button2 = document.getElementById("test2");
+ button2.click();
+
+ let button3 = document.getElementById("test3");
+ button3.click();
+ }
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/file_blocked_uri_in_violation_event_after_redirects.sjs b/dom/security/test/csp/file_blocked_uri_in_violation_event_after_redirects.sjs
new file mode 100644
index 0000000000..faf400d6d6
--- /dev/null
+++ b/dom/security/test/csp/file_blocked_uri_in_violation_event_after_redirects.sjs
@@ -0,0 +1,52 @@
+// Redirect server specifically for the needs of Bug 1542194
+
+"use strict";
+
+let REDIRECT_302_URI =
+ "http://test1.example.com/tests/dom/security/test/csp/file_blocked_uri_in_violation_event_after_redirects.sjs?test1b#ref1b";
+
+let JS_REDIRECT = `<html>
+ <body>
+ <script>
+ var url= "http://test2.example.com/tests/dom/security/test/csp/file_blocked_uri_in_violation_event_after_redirects.sjs?test2b#ref2b";
+ window.location = url;
+ </script>
+ </body>
+ </html>`;
+
+let LINK_CLICK_NAVIGATION = `<html>
+ <body>
+ <a id="navlink" href="http://test3.example.com/tests/dom/security/test/csp/file_blocked_uri_in_violation_event_after_redirects.sjs?test3b#ref3b">click me</a>
+ <script>
+ window.onload = function() { document.getElementById('navlink').click(); }
+ </script>
+ </body>
+ </html>`;
+
+function handleRequest(request, response) {
+ response.setHeader("Cache-Control", "no-cache", false);
+
+ let query = request.queryString;
+
+ // Test 1: 302 redirect
+ if (query === "test1a") {
+ var newLocation = REDIRECT_302_URI;
+ response.setStatusLine("1.1", 302, "Found");
+ response.setHeader("Location", newLocation, false);
+ return;
+ }
+
+ // Test 2: JS redirect
+ if (query === "test2a") {
+ response.setHeader("Content-Type", "text/html", false);
+ response.write(JS_REDIRECT);
+ return;
+ }
+
+ // Test 3: Link navigation
+ if (query === "test3a") {
+ response.setHeader("Content-Type", "text/html", false);
+ response.write(LINK_CLICK_NAVIGATION);
+ return;
+ }
+}
diff --git a/dom/security/test/csp/file_blocked_uri_redirect_frame_src.html b/dom/security/test/csp/file_blocked_uri_redirect_frame_src.html
new file mode 100644
index 0000000000..c3af4d5a09
--- /dev/null
+++ b/dom/security/test/csp/file_blocked_uri_redirect_frame_src.html
@@ -0,0 +1,10 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 1687342 - Check blocked-uri in csp-reports after frame redirect</title>
+</head>
+<body>
+ Contents of the following iframe will be blocked<br/>
+ <iframe src="http://example.com/tests/dom/security/test/csp/file_blocked_uri_redirect_frame_src_server.sjs?doredirect#ref1"></iframe>
+</body>
+</html>
diff --git a/dom/security/test/csp/file_blocked_uri_redirect_frame_src.html^headers^ b/dom/security/test/csp/file_blocked_uri_redirect_frame_src.html^headers^
new file mode 100644
index 0000000000..b69131f8eb
--- /dev/null
+++ b/dom/security/test/csp/file_blocked_uri_redirect_frame_src.html^headers^
@@ -0,0 +1 @@
+Content-Security-Policy: frame-src http://example.com; report-uri http://mochi.test:8888/foo.sjs;
diff --git a/dom/security/test/csp/file_blocked_uri_redirect_frame_src_server.sjs b/dom/security/test/csp/file_blocked_uri_redirect_frame_src_server.sjs
new file mode 100644
index 0000000000..5e5dbdafdf
--- /dev/null
+++ b/dom/security/test/csp/file_blocked_uri_redirect_frame_src_server.sjs
@@ -0,0 +1,14 @@
+// Redirect server specifically for the needs of Bug 1687342
+
+function handleRequest(request, response) {
+ response.setHeader("Cache-Control", "no-cache", false);
+
+ let query = request.queryString;
+ if (query === "doredirect") {
+ var newLocation =
+ "http://test1.example.com/tests/dom/security/test/csp/file_blocked_uri_redirect_frame_src_server.sjs?query#ref2";
+ response.setStatusLine("1.1", 302, "Found");
+ response.setHeader("Location", newLocation, false);
+ return;
+ }
+}
diff --git a/dom/security/test/csp/file_bug1229639.html b/dom/security/test/csp/file_bug1229639.html
new file mode 100644
index 0000000000..1e6152ead0
--- /dev/null
+++ b/dom/security/test/csp/file_bug1229639.html
@@ -0,0 +1,7 @@
+<html>
+<head> <meta charset="utf-8"> </head>
+ <body>
+ <!-- this should be allowed -->
+ <script src="http://mochi.test:8888/tests/dom/security/test/csp/%24.js"> </script>
+ </body>
+</html>
diff --git a/dom/security/test/csp/file_bug1229639.html^headers^ b/dom/security/test/csp/file_bug1229639.html^headers^
new file mode 100644
index 0000000000..0177de7a38
--- /dev/null
+++ b/dom/security/test/csp/file_bug1229639.html^headers^
@@ -0,0 +1 @@
+Content-Security-Policy: "default-src 'self'; script-src http://mochi.test:8888/tests/dom/security/test/csp/%24.js \ No newline at end of file
diff --git a/dom/security/test/csp/file_bug1312272.html b/dom/security/test/csp/file_bug1312272.html
new file mode 100644
index 0000000000..18e0e5589e
--- /dev/null
+++ b/dom/security/test/csp/file_bug1312272.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<!-- Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ -->
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>marquee inline script tests for Bug 1312272</title>
+</head>
+<body>
+<marquee id="m" onstart="parent.postMessage('csp-violation-marquee-onstart', '*')">bug 1312272</marquee>
+<script src="file_bug1312272.js"></script>
+</body>
+</html>
diff --git a/dom/security/test/csp/file_bug1312272.html^headers^ b/dom/security/test/csp/file_bug1312272.html^headers^
new file mode 100644
index 0000000000..25a9483ea9
--- /dev/null
+++ b/dom/security/test/csp/file_bug1312272.html^headers^
@@ -0,0 +1 @@
+Content-Security-Policy: default-src *; script-src * 'unsafe-eval'
diff --git a/dom/security/test/csp/file_bug1312272.js b/dom/security/test/csp/file_bug1312272.js
new file mode 100644
index 0000000000..450013bec1
--- /dev/null
+++ b/dom/security/test/csp/file_bug1312272.js
@@ -0,0 +1,8 @@
+var m = document.getElementById("m");
+m.addEventListener("click", function () {
+ // this will trigger after onstart, obviously.
+ parent.postMessage("finish", "*");
+});
+console.log("finish-handler setup");
+m.click();
+console.log("clicked");
diff --git a/dom/security/test/csp/file_bug1452037.html b/dom/security/test/csp/file_bug1452037.html
new file mode 100644
index 0000000000..0fb41d6654
--- /dev/null
+++ b/dom/security/test/csp/file_bug1452037.html
@@ -0,0 +1,9 @@
+<html>
+<head>
+ <meta charset="utf-8">
+ <meta http-equiv="Content-Security-Policy" content="script-src 'sha256-47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU='">
+</head>
+<body>
+ <a href="javascript:window.parent.postMessage({}, '*');">Click here</a>
+</body>
+</html>
diff --git a/dom/security/test/csp/file_bug1505412.sjs b/dom/security/test/csp/file_bug1505412.sjs
new file mode 100644
index 0000000000..dc7fa48b62
--- /dev/null
+++ b/dom/security/test/csp/file_bug1505412.sjs
@@ -0,0 +1,36 @@
+// https://bugzilla.mozilla.org/show_bug.cgi?id=650386
+// This SJS file serves file_redirect_content.html
+// with a CSP that will trigger a violation and that will report it
+// to file_redirect_report.sjs
+//
+// This handles 301, 302, 303 and 307 redirects. The HTTP status code
+// returned/type of redirect to do comes from the query string
+// parameter passed in from the test_bug650386_* files and then also
+// uses that value in the report-uri parameter of the CSP
+function handleRequest(request, response) {
+ response.setHeader("Cache-Control", "no-cache", false);
+
+ // this gets used in the CSP as part of the report URI.
+ var redirect = request.queryString;
+
+ if (!redirect) {
+ // if we somehow got some bogus redirect code here,
+ // do a 302 redirect to the same URL as the report URI
+ // redirects to - this will fail the test.
+ var loc =
+ "http://sub1.test1.example.org/tests/dom/security/test/csp/file_bug1505412.sjs?redirected";
+ response.setStatusLine("1.1", 302, "Found");
+ response.setHeader("Location", loc, false);
+ return;
+ }
+
+ // response.setHeader("content-type", "text/application", false);
+ // the actual file content.
+ // this image load will (intentionally) fail due to the CSP policy of default-src: 'self'
+ // specified by the CSP string above.
+ var content = "info('Script Loaded')";
+
+ response.write(content);
+
+ return;
+}
diff --git a/dom/security/test/csp/file_bug1505412_frame.html b/dom/security/test/csp/file_bug1505412_frame.html
new file mode 100644
index 0000000000..b58af55849
--- /dev/null
+++ b/dom/security/test/csp/file_bug1505412_frame.html
@@ -0,0 +1,14 @@
+<!DOCTYPE HTML>
+<html>
+
+<head>
+ <title> Bug 1505412 CSP-RO reports violations in inline-scripts with nonce</title>
+ <script src="/tests/SimpleTest/SimpleTest.js" nonce="foobar"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+
+
+<body>
+ <script src="file_bug1505412.sjs" nonce="foobar"></script>
+</body>
+
+</html>
diff --git a/dom/security/test/csp/file_bug1505412_frame.html^headers^ b/dom/security/test/csp/file_bug1505412_frame.html^headers^
new file mode 100644
index 0000000000..e60b63c29c
--- /dev/null
+++ b/dom/security/test/csp/file_bug1505412_frame.html^headers^
@@ -0,0 +1 @@
+Content-Security-Policy-Report-Only: script-src 'nonce-foobar'; report-uri file_bug1505412_reporter.sjs
diff --git a/dom/security/test/csp/file_bug1505412_reporter.sjs b/dom/security/test/csp/file_bug1505412_reporter.sjs
new file mode 100644
index 0000000000..323a4edb1c
--- /dev/null
+++ b/dom/security/test/csp/file_bug1505412_reporter.sjs
@@ -0,0 +1,18 @@
+function handleRequest(request, response) {
+ var receivedRequests = parseInt(getState("requests"));
+ if (isNaN(receivedRequests)) {
+ receivedRequests = 0;
+ }
+ if (request.queryString.includes("state")) {
+ response.write(receivedRequests);
+ return;
+ }
+ if (request.queryString.includes("flush")) {
+ setState("requests", "0");
+ response.write("OK");
+ return;
+ }
+ receivedRequests = receivedRequests + 1;
+ setState("requests", "" + receivedRequests);
+ response.write("OK");
+}
diff --git a/dom/security/test/csp/file_bug1738418_child.html b/dom/security/test/csp/file_bug1738418_child.html
new file mode 100644
index 0000000000..26e7f8f1f6
--- /dev/null
+++ b/dom/security/test/csp/file_bug1738418_child.html
@@ -0,0 +1,11 @@
+<!DOCTYPE HTML>
+<html>
+<body>
+<script type="text/javascript">
+ window.parent.parent.postMessage({
+ element: location.hash.substr(1),
+ domain: document.domain,
+ }, '*');
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/file_bug1738418_parent.html b/dom/security/test/csp/file_bug1738418_parent.html
new file mode 100644
index 0000000000..c8bdbb2c46
--- /dev/null
+++ b/dom/security/test/csp/file_bug1738418_parent.html
@@ -0,0 +1,11 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <base href="file_bug1738418_child.html">
+</head>
+<body>
+ <iframe src="#iframe"></iframe>
+ <embed src="#embed"></embed>
+ <object data="#object"></object>
+</body>
+</html>
diff --git a/dom/security/test/csp/file_bug1738418_parent.html^headers^ b/dom/security/test/csp/file_bug1738418_parent.html^headers^
new file mode 100644
index 0000000000..4705ce9ded
--- /dev/null
+++ b/dom/security/test/csp/file_bug1738418_parent.html^headers^
@@ -0,0 +1 @@
+Content-Security-Policy: sandbox allow-scripts;
diff --git a/dom/security/test/csp/file_bug1764343.html b/dom/security/test/csp/file_bug1764343.html
new file mode 100644
index 0000000000..09781cce89
--- /dev/null
+++ b/dom/security/test/csp/file_bug1764343.html
@@ -0,0 +1,11 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Bug 1764343 - CSP inheritance for same-origin iframes</title>
+ <meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src 'none'; script-src 'nonce-a' 'nonce-b'; img-src 'none'">
+</head>
+<body>
+ initial content
+</body>
+</html>
diff --git a/dom/security/test/csp/file_bug1777572.html b/dom/security/test/csp/file_bug1777572.html
new file mode 100644
index 0000000000..51f2a80d28
--- /dev/null
+++ b/dom/security/test/csp/file_bug1777572.html
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta http-equiv="Content-Security-Policy" content="img-src https://*;">
+ <script>
+ async function timeout (cmd) {
+ const timer = new Promise((resolve, reject) => {
+ const id = setTimeout(() => {
+ clearTimeout(id)
+ reject(new Error('Promise timed out!'))
+ }, 750)
+ })
+ return Promise.race([cmd, timer])
+ }
+
+ let ourOpener = window.opener;
+
+ if (location.search.includes("close")) {
+ window.close();
+ }
+
+ document.addEventListener('DOMContentLoaded', async () => {
+ const frame = document.createElementNS('http://www.w3.org/1999/xhtml', 'frame');
+ const image = document.createElementNS('http://www.w3.org/2000/svg', 'image');
+ document.documentElement.appendChild(frame)
+ image.setAttribute('href', 'a.png')
+ for (let i = 0; i < 5; ++i) {
+ try { await timeout(image.decode()) } catch (e) {}
+ }
+ let w = window.open();
+ // Need to run SpecialPowers in the newly opened window to avoid
+ // .wrap throwing because of dead objects.
+ let csp = w.eval("SpecialPowers.wrap(document).cspJSON;");
+ ourOpener.postMessage(csp, "*");
+ w.close();
+
+ if (!location.search.includes("close")) {
+ window.close();
+ }
+ })
+ </script>
+</head>
+</html>
diff --git a/dom/security/test/csp/file_bug663567.xsl b/dom/security/test/csp/file_bug663567.xsl
new file mode 100644
index 0000000000..b12b0d3b1d
--- /dev/null
+++ b/dom/security/test/csp/file_bug663567.xsl
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!-- Edited by XMLSpy® -->
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+
+<xsl:template match="/">
+ <html>
+ <body>
+ <h2 id="xsltheader">this xml file should be formatted using an xsl file(lower iframe should contain xml dump)!</h2>
+ <table border="1">
+ <tr bgcolor="#990099">
+ <th>Title</th>
+ <th>Artist</th>
+ <th>Price</th>
+ </tr>
+ <xsl:for-each select="catalog/cd">
+ <tr>
+ <td><xsl:value-of select="title"/></td>
+ <td><xsl:value-of select="artist"/></td>
+ <td><xsl:value-of select="price"/></td>
+ </tr>
+ </xsl:for-each>
+ </table>
+ </body>
+ </html>
+</xsl:template>
+</xsl:stylesheet>
+
diff --git a/dom/security/test/csp/file_bug663567_allows.xml b/dom/security/test/csp/file_bug663567_allows.xml
new file mode 100644
index 0000000000..93d3451038
--- /dev/null
+++ b/dom/security/test/csp/file_bug663567_allows.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<?xml-stylesheet type="text/xsl" href="file_bug663567.xsl"?>
+<catalog>
+ <cd>
+ <title>Empire Burlesque</title>
+ <artist>Bob Dylan</artist>
+ <country>USA</country>
+ <company>Columbia</company>
+ <price>10.90</price>
+ <year>1985</year>
+ </cd>
+ <cd>
+ <title>Hide your heart</title>
+ <artist>Bonnie Tyler</artist>
+ <country>UK</country>
+ <company>CBS Records</company>
+ <price>9.90</price>
+ <year>1988</year>
+ </cd>
+ <cd>
+ <title>Greatest Hits</title>
+ <artist>Dolly Parton</artist>
+ <country>USA</country>
+ <company>RCA</company>
+ <price>9.90</price>
+ <year>1982</year>
+ </cd>
+</catalog>
diff --git a/dom/security/test/csp/file_bug663567_allows.xml^headers^ b/dom/security/test/csp/file_bug663567_allows.xml^headers^
new file mode 100644
index 0000000000..4c6fa3c26a
--- /dev/null
+++ b/dom/security/test/csp/file_bug663567_allows.xml^headers^
@@ -0,0 +1 @@
+Content-Security-Policy: default-src 'self'
diff --git a/dom/security/test/csp/file_bug663567_blocks.xml b/dom/security/test/csp/file_bug663567_blocks.xml
new file mode 100644
index 0000000000..93d3451038
--- /dev/null
+++ b/dom/security/test/csp/file_bug663567_blocks.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<?xml-stylesheet type="text/xsl" href="file_bug663567.xsl"?>
+<catalog>
+ <cd>
+ <title>Empire Burlesque</title>
+ <artist>Bob Dylan</artist>
+ <country>USA</country>
+ <company>Columbia</company>
+ <price>10.90</price>
+ <year>1985</year>
+ </cd>
+ <cd>
+ <title>Hide your heart</title>
+ <artist>Bonnie Tyler</artist>
+ <country>UK</country>
+ <company>CBS Records</company>
+ <price>9.90</price>
+ <year>1988</year>
+ </cd>
+ <cd>
+ <title>Greatest Hits</title>
+ <artist>Dolly Parton</artist>
+ <country>USA</country>
+ <company>RCA</company>
+ <price>9.90</price>
+ <year>1982</year>
+ </cd>
+</catalog>
diff --git a/dom/security/test/csp/file_bug663567_blocks.xml^headers^ b/dom/security/test/csp/file_bug663567_blocks.xml^headers^
new file mode 100644
index 0000000000..baf7f3c6af
--- /dev/null
+++ b/dom/security/test/csp/file_bug663567_blocks.xml^headers^
@@ -0,0 +1 @@
+Content-Security-Policy: default-src *.example.com
diff --git a/dom/security/test/csp/file_bug802872.html b/dom/security/test/csp/file_bug802872.html
new file mode 100644
index 0000000000..dae040376b
--- /dev/null
+++ b/dom/security/test/csp/file_bug802872.html
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 802872</title>
+ <!-- Including SimpleTest.js so we can use AddLoadEvent !-->
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+ <script src='file_bug802872.js'></script>
+</body>
+</html>
diff --git a/dom/security/test/csp/file_bug802872.html^headers^ b/dom/security/test/csp/file_bug802872.html^headers^
new file mode 100644
index 0000000000..4c6fa3c26a
--- /dev/null
+++ b/dom/security/test/csp/file_bug802872.html^headers^
@@ -0,0 +1 @@
+Content-Security-Policy: default-src 'self'
diff --git a/dom/security/test/csp/file_bug802872.js b/dom/security/test/csp/file_bug802872.js
new file mode 100644
index 0000000000..042e190269
--- /dev/null
+++ b/dom/security/test/csp/file_bug802872.js
@@ -0,0 +1,47 @@
+/*
+ * The policy for this test is:
+ * Content-Security-Policy: default-src 'self'
+ */
+
+function createAllowedEvent() {
+ /*
+ * Creates a new EventSource using 'http://mochi.test:8888'. Since all mochitests run on
+ * 'http://mochi.test', a default-src of 'self' allows this request.
+ */
+ var src_event = new EventSource(
+ "http://mochi.test:8888/tests/dom/security/test/csp/file_bug802872.sjs"
+ );
+
+ src_event.onmessage = function (e) {
+ src_event.close();
+ parent.dispatchEvent(new Event("allowedEventSrcCallbackOK"));
+ };
+
+ src_event.onerror = function (e) {
+ src_event.close();
+ parent.dispatchEvent(new Event("allowedEventSrcCallbackFailed"));
+ };
+}
+
+function createBlockedEvent() {
+ /*
+ * creates a new EventSource using 'http://example.com'. This domain is not allowlisted by the
+ * CSP of this page, therefore the CSP blocks this request.
+ */
+ var src_event = new EventSource(
+ "http://example.com/tests/dom/security/test/csp/file_bug802872.sjs"
+ );
+
+ src_event.onmessage = function (e) {
+ src_event.close();
+ parent.dispatchEvent(new Event("blockedEventSrcCallbackOK"));
+ };
+
+ src_event.onerror = function (e) {
+ src_event.close();
+ parent.dispatchEvent(new Event("blockedEventSrcCallbackFailed"));
+ };
+}
+
+addLoadEvent(createAllowedEvent);
+addLoadEvent(createBlockedEvent);
diff --git a/dom/security/test/csp/file_bug802872.sjs b/dom/security/test/csp/file_bug802872.sjs
new file mode 100644
index 0000000000..6877bd5833
--- /dev/null
+++ b/dom/security/test/csp/file_bug802872.sjs
@@ -0,0 +1,6 @@
+function handleRequest(request, response) {
+ response.setHeader("Cache-Control", "no-cache", false);
+ response.setHeader("Content-Type", "text/event-stream", false);
+ response.write("data: eventsource response from server!");
+ response.write("\n\n");
+}
diff --git a/dom/security/test/csp/file_bug836922_npolicies.html b/dom/security/test/csp/file_bug836922_npolicies.html
new file mode 100644
index 0000000000..6a728813a7
--- /dev/null
+++ b/dom/security/test/csp/file_bug836922_npolicies.html
@@ -0,0 +1,12 @@
+<html>
+ <head>
+ <link rel='stylesheet' type='text/css'
+ href='/tests/dom/security/test/csp/file_CSP.sjs?testid=css_self&type=text/css' />
+
+ </head>
+ <body>
+ <img src="/tests/dom/security/test/csp/file_CSP.sjs?testid=img_self&type=img/png"> </img>
+ <script src='/tests/dom/security/test/csp/file_CSP.sjs?testid=script_self&type=text/javascript'></script>
+
+ </body>
+</html>
diff --git a/dom/security/test/csp/file_bug836922_npolicies.html^headers^ b/dom/security/test/csp/file_bug836922_npolicies.html^headers^
new file mode 100644
index 0000000000..ec6ba8c4ae
--- /dev/null
+++ b/dom/security/test/csp/file_bug836922_npolicies.html^headers^
@@ -0,0 +1,2 @@
+content-security-policy: default-src 'self'; img-src 'none'; report-uri http://mochi.test:8888/tests/dom/security/test/csp/file_bug836922_npolicies_violation.sjs
+content-security-policy-report-only: default-src *; img-src 'self'; script-src 'none'; report-uri http://mochi.test:8888/tests/dom/security/test/csp/file_bug836922_npolicies_ro_violation.sjs
diff --git a/dom/security/test/csp/file_bug836922_npolicies_ro_violation.sjs b/dom/security/test/csp/file_bug836922_npolicies_ro_violation.sjs
new file mode 100644
index 0000000000..0f5eb4b596
--- /dev/null
+++ b/dom/security/test/csp/file_bug836922_npolicies_ro_violation.sjs
@@ -0,0 +1,53 @@
+// SJS file that receives violation reports and then responds with nothing.
+
+const CC = Components.Constructor;
+const BinaryInputStream = CC(
+ "@mozilla.org/binaryinputstream;1",
+ "nsIBinaryInputStream",
+ "setInputStream"
+);
+
+const STATE_KEY = "bug836922_ro_violations";
+
+function handleRequest(request, response) {
+ var query = {};
+ request.queryString.split("&").forEach(function (val) {
+ var [name, value] = val.split("=");
+ query[name] = unescape(value);
+ });
+
+ if ("results" in query) {
+ // if asked for the received data, send it.
+ response.setHeader("Content-Type", "text/javascript", false);
+ if (getState(STATE_KEY)) {
+ response.write(getState(STATE_KEY));
+ } else {
+ // no state has been recorded.
+ response.write(JSON.stringify({}));
+ }
+ } else if ("reset" in query) {
+ //clear state
+ setState(STATE_KEY, JSON.stringify(null));
+ } else {
+ // ... otherwise, just respond "ok".
+ response.write("null");
+
+ var bodystream = new BinaryInputStream(request.bodyInputStream);
+ var avail;
+ var bytes = [];
+ while ((avail = bodystream.available()) > 0) {
+ Array.prototype.push.apply(bytes, bodystream.readByteArray(avail));
+ }
+
+ var data = String.fromCharCode.apply(null, bytes);
+
+ // figure out which test was violating a policy
+ var testpat = new RegExp("testid=([a-z0-9_]+)");
+ var testid = testpat.exec(data)[1];
+
+ // store the violation in the persistent state
+ var s = JSON.parse(getState(STATE_KEY) || "{}");
+ s[testid] ? s[testid]++ : (s[testid] = 1);
+ setState(STATE_KEY, JSON.stringify(s));
+ }
+}
diff --git a/dom/security/test/csp/file_bug836922_npolicies_violation.sjs b/dom/security/test/csp/file_bug836922_npolicies_violation.sjs
new file mode 100644
index 0000000000..dec8b4f081
--- /dev/null
+++ b/dom/security/test/csp/file_bug836922_npolicies_violation.sjs
@@ -0,0 +1,64 @@
+// SJS file that receives violation reports and then responds with nothing.
+
+const CC = Components.Constructor;
+const BinaryInputStream = CC(
+ "@mozilla.org/binaryinputstream;1",
+ "nsIBinaryInputStream",
+ "setInputStream"
+);
+
+const STATE = "bug836922_violations";
+
+function handleRequest(request, response) {
+ var query = {};
+ request.queryString.split("&").forEach(function (val) {
+ var [name, value] = val.split("=");
+ query[name] = unescape(value);
+ });
+
+ if ("results" in query) {
+ // if asked for the received data, send it.
+ response.setHeader("Content-Type", "text/javascript", false);
+ if (getState(STATE)) {
+ response.write(getState(STATE));
+ } else {
+ // no state has been recorded.
+ response.write(JSON.stringify({}));
+ }
+ } else if ("reset" in query) {
+ //clear state
+ setState(STATE, JSON.stringify(null));
+ } else {
+ // ... otherwise, just respond "ok".
+ response.write("null");
+
+ var bodystream = new BinaryInputStream(request.bodyInputStream);
+ var avail;
+ var bytes = [];
+ while ((avail = bodystream.available()) > 0) {
+ Array.prototype.push.apply(bytes, bodystream.readByteArray(avail));
+ }
+
+ var data = String.fromCharCode.apply(null, bytes);
+
+ // figure out which test was violating a policy
+ var testpat = new RegExp("testid=([a-z0-9_]+)");
+ var testid = testpat.exec(data)[1];
+
+ // store the violation in the persistent state
+ var s = getState(STATE);
+ if (!s) {
+ s = "{}";
+ }
+ s = JSON.parse(s);
+ if (!s) {
+ s = {};
+ }
+
+ if (!s[testid]) {
+ s[testid] = 0;
+ }
+ s[testid]++;
+ setState(STATE, JSON.stringify(s));
+ }
+}
diff --git a/dom/security/test/csp/file_bug885433_allows.html b/dom/security/test/csp/file_bug885433_allows.html
new file mode 100644
index 0000000000..5d7aacbda4
--- /dev/null
+++ b/dom/security/test/csp/file_bug885433_allows.html
@@ -0,0 +1,38 @@
+<!doctype html>
+<!--
+The Content-Security-Policy header for this file is:
+
+ Content-Security-Policy: img-src 'self';
+
+It does not include any of the default-src, script-src, or style-src
+directives. It should allow the use of unsafe-inline and unsafe-eval on
+scripts, and unsafe-inline on styles, because no directives related to scripts
+or styles are specified.
+-->
+<html>
+<body>
+ <ol>
+ <li id="unsafe-inline-script-allowed">Inline script allowed (this text should be green)</li>
+ <li id="unsafe-eval-script-allowed">Eval script allowed (this text should be green)</li>
+ <li id="unsafe-inline-style-allowed">Inline style allowed (this text should be green)</li>
+ </ol>
+
+ <script>
+ // Use inline script to set a style attribute
+ document.getElementById("unsafe-inline-script-allowed").style.color = "green";
+
+ // Use eval to set a style attribute
+ // try/catch is used because CSP causes eval to throw an exception when it
+ // is blocked, which would derail the rest of the tests in this file.
+ try {
+ eval('document.getElementById("unsafe-eval-script-allowed").style.color = "green";');
+ } catch (e) {}
+ </script>
+
+ <style>
+ li#unsafe-inline-style-allowed {
+ color: green;
+ }
+ </style>
+</body>
+</html>
diff --git a/dom/security/test/csp/file_bug885433_allows.html^headers^ b/dom/security/test/csp/file_bug885433_allows.html^headers^
new file mode 100644
index 0000000000..767b9ca926
--- /dev/null
+++ b/dom/security/test/csp/file_bug885433_allows.html^headers^
@@ -0,0 +1 @@
+Content-Security-Policy: img-src 'self';
diff --git a/dom/security/test/csp/file_bug885433_blocks.html b/dom/security/test/csp/file_bug885433_blocks.html
new file mode 100644
index 0000000000..2279b33e46
--- /dev/null
+++ b/dom/security/test/csp/file_bug885433_blocks.html
@@ -0,0 +1,37 @@
+<!doctype html>
+<!--
+The Content-Security-Policy header for this file is:
+
+ Content-Security-Policy: default-src 'self';
+
+The Content-Security-Policy header for this file includes the default-src
+directive, which triggers the default behavior of blocking unsafe-inline and
+unsafe-eval on scripts, and unsafe-inline on styles.
+-->
+<html>
+<body>
+ <ol>
+ <li id="unsafe-inline-script-blocked">Inline script blocked (this text should be black)</li>
+ <li id="unsafe-eval-script-blocked">Eval script blocked (this text should be black)</li>
+ <li id="unsafe-inline-style-blocked">Inline style blocked (this text should be black)</li>
+ </ol>
+
+ <script>
+ // Use inline script to set a style attribute
+ document.getElementById("unsafe-inline-script-blocked").style.color = "green";
+
+ // Use eval to set a style attribute
+ // try/catch is used because CSP causes eval to throw an exception when it
+ // is blocked, which would derail the rest of the tests in this file.
+ try {
+ eval('document.getElementById("unsafe-eval-script-blocked").style.color = "green";');
+ } catch (e) {}
+ </script>
+
+ <style>
+ li#unsafe-inline-style-blocked {
+ color: green;
+ }
+ </style>
+</body>
+</html>
diff --git a/dom/security/test/csp/file_bug885433_blocks.html^headers^ b/dom/security/test/csp/file_bug885433_blocks.html^headers^
new file mode 100644
index 0000000000..f82598b673
--- /dev/null
+++ b/dom/security/test/csp/file_bug885433_blocks.html^headers^
@@ -0,0 +1 @@
+Content-Security-Policy: default-src 'self';
diff --git a/dom/security/test/csp/file_bug886164.html b/dom/security/test/csp/file_bug886164.html
new file mode 100644
index 0000000000..ec8c9e7e92
--- /dev/null
+++ b/dom/security/test/csp/file_bug886164.html
@@ -0,0 +1,15 @@
+<html>
+<head> <meta charset="utf-8"> </head>
+ <body>
+ <!-- sandbox="allow-same-origin" -->
+ <!-- Content-Security-Policy: default-src 'self' -->
+
+ <!-- these should be stopped by CSP -->
+ <img src="http://example.org/tests/dom/security/test/csp/file_CSP.sjs?testid=img_bad&type=img/png"> </img>
+
+ <!-- these should load ok -->
+ <img src="/tests/dom/security/test/csp/file_CSP.sjs?testid=img_good&type=img/png" />
+ <script src='/tests/dom/security/test/csp/file_CSP.sjs?testid=scripta_bad&type=text/javascript'></script>
+
+ </body>
+</html>
diff --git a/dom/security/test/csp/file_bug886164.html^headers^ b/dom/security/test/csp/file_bug886164.html^headers^
new file mode 100644
index 0000000000..4c6fa3c26a
--- /dev/null
+++ b/dom/security/test/csp/file_bug886164.html^headers^
@@ -0,0 +1 @@
+Content-Security-Policy: default-src 'self'
diff --git a/dom/security/test/csp/file_bug886164_2.html b/dom/security/test/csp/file_bug886164_2.html
new file mode 100644
index 0000000000..83d36c55ae
--- /dev/null
+++ b/dom/security/test/csp/file_bug886164_2.html
@@ -0,0 +1,14 @@
+<html>
+<head> <meta charset="utf-8"> </head>
+ <body>
+ <!-- sandbox -->
+ <!-- Content-Security-Policy: default-src 'self' -->
+
+ <!-- these should be stopped by CSP -->
+ <img src="http://example.org/tests/dom/security/test/csp/file_CSP.sjs?testid=img2_bad&type=img/png"> </img>
+
+ <!-- these should load ok -->
+ <img src="/tests/dom/security/test/csp/file_CSP.sjs?testid=img2a_good&type=img/png" />
+
+ </body>
+</html>
diff --git a/dom/security/test/csp/file_bug886164_2.html^headers^ b/dom/security/test/csp/file_bug886164_2.html^headers^
new file mode 100644
index 0000000000..4c6fa3c26a
--- /dev/null
+++ b/dom/security/test/csp/file_bug886164_2.html^headers^
@@ -0,0 +1 @@
+Content-Security-Policy: default-src 'self'
diff --git a/dom/security/test/csp/file_bug886164_3.html b/dom/security/test/csp/file_bug886164_3.html
new file mode 100644
index 0000000000..8b4313000f
--- /dev/null
+++ b/dom/security/test/csp/file_bug886164_3.html
@@ -0,0 +1,12 @@
+<html>
+<head> <meta charset="utf-8"> </head>
+ <body>
+ <!-- sandbox -->
+ <!-- Content-Security-Policy: default-src 'none' -->
+
+ <!-- these should be stopped by CSP -->
+ <img src="http://example.org/tests/dom/security/test/csp/file_CSP.sjs?testid=img3_bad&type=img/png"> </img>
+ <img src="/tests/dom/security/test/csp/file_CSP.sjs?testid=img3a_bad&type=img/png" />
+
+ </body>
+</html>
diff --git a/dom/security/test/csp/file_bug886164_3.html^headers^ b/dom/security/test/csp/file_bug886164_3.html^headers^
new file mode 100644
index 0000000000..6581fd425e
--- /dev/null
+++ b/dom/security/test/csp/file_bug886164_3.html^headers^
@@ -0,0 +1 @@
+Content-Security-Policy: default-src 'none'
diff --git a/dom/security/test/csp/file_bug886164_4.html b/dom/security/test/csp/file_bug886164_4.html
new file mode 100644
index 0000000000..41137ea017
--- /dev/null
+++ b/dom/security/test/csp/file_bug886164_4.html
@@ -0,0 +1,12 @@
+<html>
+<head> <meta charset="utf-8"> </head>
+ <body>
+ <!-- sandbox -->
+ <!-- Content-Security-Policy: default-src 'none' -->
+
+ <!-- these should be stopped by CSP -->
+ <img src="http://example.org/tests/dom/security/test/csp/file_CSP.sjs?testid=img4_bad&type=img/png"> </img>
+ <img src="/tests/dom/security/test/csp/file_CSP.sjs?testid=img4a_bad&type=img/png" />
+
+ </body>
+</html>
diff --git a/dom/security/test/csp/file_bug886164_4.html^headers^ b/dom/security/test/csp/file_bug886164_4.html^headers^
new file mode 100644
index 0000000000..6581fd425e
--- /dev/null
+++ b/dom/security/test/csp/file_bug886164_4.html^headers^
@@ -0,0 +1 @@
+Content-Security-Policy: default-src 'none'
diff --git a/dom/security/test/csp/file_bug886164_5.html b/dom/security/test/csp/file_bug886164_5.html
new file mode 100644
index 0000000000..82c10f20c0
--- /dev/null
+++ b/dom/security/test/csp/file_bug886164_5.html
@@ -0,0 +1,26 @@
+<!DOCTYPE HTML>
+<html>
+<head> <meta charset="utf-8"> </head>
+<script type="text/javascript">
+ function ok(result, desc) {
+ window.parent.postMessage({ok: result, desc}, "*");
+ }
+
+ function doStuff() {
+ ok(true, "documents sandboxed with allow-scripts should be able to run inline scripts");
+ }
+</script>
+<script src='file_iframe_sandbox_pass.js'></script>
+<body onLoad='ok(true, "documents sandboxed with allow-scripts should be able to run script from event listeners");doStuff();'>
+ I am sandboxed but with only inline "allow-scripts"
+
+ <!-- sandbox="allow-scripts" -->
+ <!-- Content-Security-Policy: default-src 'none' 'unsafe-inline'-->
+
+ <!-- these should be stopped by CSP -->
+ <img src="/tests/dom/security/test/csp/file_CSP.sjs?testid=img5_bad&type=img/png" />
+ <img src="http://example.org/tests/dom/security/test/csp/file_CSP.sjs?testid=img5a_bad&type=img/png"> </img>
+ <script src='/tests/dom/security/test/csp/file_CSP.sjs?testid=script5_bad&type=text/javascript'></script>
+ <script src='http://example.org/tests/dom/security/test/csp/file_CSP.sjs?testid=script5a_bad&type=text/javascript'></script>
+</body>
+</html>
diff --git a/dom/security/test/csp/file_bug886164_5.html^headers^ b/dom/security/test/csp/file_bug886164_5.html^headers^
new file mode 100644
index 0000000000..3abc190552
--- /dev/null
+++ b/dom/security/test/csp/file_bug886164_5.html^headers^
@@ -0,0 +1 @@
+Content-Security-Policy: default-src 'none' 'unsafe-inline';
diff --git a/dom/security/test/csp/file_bug886164_6.html b/dom/security/test/csp/file_bug886164_6.html
new file mode 100644
index 0000000000..f6567b470e
--- /dev/null
+++ b/dom/security/test/csp/file_bug886164_6.html
@@ -0,0 +1,35 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+</head>
+<script type="text/javascript">
+ function ok(result, desc) {
+ window.parent.postMessage({ok: result, desc}, "*");
+ }
+
+ function doStuff() {
+ ok(true, "documents sandboxed with allow-scripts should be able to run inline scripts");
+
+ document.getElementById('a_form').submit();
+
+ // trigger the javascript: url test
+ sendMouseEvent({type:'click'}, 'a_link');
+ }
+</script>
+<script src='file_iframe_sandbox_pass.js'></script>
+<body onLoad='ok(true, "documents sandboxed with allow-scripts should be able to run script from event listeners");doStuff();'>
+ I am sandboxed but with "allow-scripts"
+ <img src="http://example.org/tests/dom/security/test/csp/file_CSP.sjs?testid=img6_bad&type=img/png"> </img>
+ <script src='http://example.org/tests/dom/security/test/csp/file_CSP.sjs?testid=script6_bad&type=text/javascript'></script>
+
+ <form method="get" action="file_iframe_sandbox_form_fail.html" id="a_form">
+ First name: <input type="text" name="firstname">
+ Last name: <input type="text" name="lastname">
+ <input type="submit" onclick="doSubmit()" id="a_button">
+ </form>
+
+ <a href = 'javascript:ok(true, "documents sandboxed with allow-scripts should be able to run script from javascript: URLs");' id='a_link'>click me</a>
+</body>
+</html>
diff --git a/dom/security/test/csp/file_bug886164_6.html^headers^ b/dom/security/test/csp/file_bug886164_6.html^headers^
new file mode 100644
index 0000000000..6f9fc3f25d
--- /dev/null
+++ b/dom/security/test/csp/file_bug886164_6.html^headers^
@@ -0,0 +1 @@
+Content-Security-Policy: default-src 'self' 'unsafe-inline';
diff --git a/dom/security/test/csp/file_bug888172.html b/dom/security/test/csp/file_bug888172.html
new file mode 100644
index 0000000000..27cf9b00ab
--- /dev/null
+++ b/dom/security/test/csp/file_bug888172.html
@@ -0,0 +1,28 @@
+<!doctype html>
+<html>
+ <body>
+ <ol>
+ <li id="unsafe-inline-script">Inline script (green if allowed, black if blocked)</li>
+ <li id="unsafe-eval-script">Eval script (green if allowed, black if blocked)</li>
+ <li id="unsafe-inline-style">Inline style (green if allowed, black if blocked)</li>
+ </ol>
+
+ <script>
+ // Use inline script to set a style attribute
+ document.getElementById("unsafe-inline-script").style.color = "green";
+
+ // Use eval to set a style attribute
+ // try/catch is used because CSP causes eval to throw an exception when it
+ // is blocked, which would derail the rest of the tests in this file.
+ try {
+ eval('document.getElementById("unsafe-eval-script").style.color = "green";');
+ } catch (e) {}
+ </script>
+
+ <style>
+ li#unsafe-inline-style {
+ color: green;
+ }
+ </style>
+ </body>
+</html>
diff --git a/dom/security/test/csp/file_bug888172.sjs b/dom/security/test/csp/file_bug888172.sjs
new file mode 100644
index 0000000000..adc0f7740c
--- /dev/null
+++ b/dom/security/test/csp/file_bug888172.sjs
@@ -0,0 +1,47 @@
+// SJS file for CSP mochitests
+
+const { NetUtil } = ChromeUtils.import("resource://gre/modules/NetUtil.jsm");
+
+function loadHTMLFromFile(path) {
+ // Load the HTML to return in the response from file.
+ // Since it's relative to the cwd of the test runner, we start there and
+ // append to get to the actual path of the file.
+ var testHTMLFile = Components.classes["@mozilla.org/file/directory_service;1"]
+ .getService(Components.interfaces.nsIProperties)
+ .get("CurWorkD", Components.interfaces.nsIFile);
+ var dirs = path.split("/");
+ for (var i = 0; i < dirs.length; i++) {
+ testHTMLFile.append(dirs[i]);
+ }
+ var testHTMLFileStream = Components.classes[
+ "@mozilla.org/network/file-input-stream;1"
+ ].createInstance(Components.interfaces.nsIFileInputStream);
+ testHTMLFileStream.init(testHTMLFile, -1, 0, 0);
+ var testHTML = NetUtil.readInputStreamToString(
+ testHTMLFileStream,
+ testHTMLFileStream.available()
+ );
+ return testHTML;
+}
+
+function handleRequest(request, response) {
+ var query = {};
+ request.queryString.split("&").forEach(function (val) {
+ var [name, value] = val.split("=");
+ query[name] = unescape(value);
+ });
+
+ // avoid confusing cache behaviors
+ response.setHeader("Cache-Control", "no-cache", false);
+
+ // Deliver the CSP policy encoded in the URI
+ if (query.csp) {
+ response.setHeader("Content-Security-Policy", unescape(query.csp), false);
+ }
+
+ // Send HTML to test allowed/blocked behaviors
+ response.setHeader("Content-Type", "text/html", false);
+ response.write(
+ loadHTMLFromFile("tests/dom/security/test/csp/file_bug888172.html")
+ );
+}
diff --git a/dom/security/test/csp/file_bug909029_none.html b/dom/security/test/csp/file_bug909029_none.html
new file mode 100644
index 0000000000..0d4934a4a3
--- /dev/null
+++ b/dom/security/test/csp/file_bug909029_none.html
@@ -0,0 +1,20 @@
+<!doctype html>
+<html>
+ <head>
+ <!-- file_CSP.sjs mocks a resource load -->
+ <link rel='stylesheet' type='text/css'
+ href='file_CSP.sjs?testid=noneExternalStylesBlocked&type=text/css' />
+ </head>
+ <body>
+ <p id="inline-style">This should be green</p>
+ <p id="inline-script">This should be black</p>
+ <style>
+ p#inline-style { color:rgb(0, 128, 0); }
+ </style>
+ <script>
+ // Use inline script to set a style attribute
+ document.getElementById("inline-script").style.color = "rgb(0, 128, 0)";
+ </script>
+ <img src="file_CSP.sjs?testid=noneExternalImgLoaded&type=img/png" />
+ </body>
+</html>
diff --git a/dom/security/test/csp/file_bug909029_none.html^headers^ b/dom/security/test/csp/file_bug909029_none.html^headers^
new file mode 100644
index 0000000000..ecb3458750
--- /dev/null
+++ b/dom/security/test/csp/file_bug909029_none.html^headers^
@@ -0,0 +1 @@
+Content-Security-Policy: default-src * ; style-src 'none' 'unsafe-inline';
diff --git a/dom/security/test/csp/file_bug909029_star.html b/dom/security/test/csp/file_bug909029_star.html
new file mode 100644
index 0000000000..bcb907a965
--- /dev/null
+++ b/dom/security/test/csp/file_bug909029_star.html
@@ -0,0 +1,19 @@
+<!doctype html>
+<html>
+ <head>
+ <link rel='stylesheet' type='text/css'
+ href='file_CSP.sjs?testid=starExternalStylesLoaded&type=text/css' />
+ </head>
+ <body>
+ <p id="inline-style">This should be green</p>
+ <p id="inline-script">This should be black</p>
+ <style>
+ p#inline-style { color:rgb(0, 128, 0); }
+ </style>
+ <script>
+ // Use inline script to set a style attribute
+ document.getElementById("inline-script").style.color = "rgb(0, 128, 0)";
+ </script>
+ <img src="file_CSP.sjs?testid=starExternalImgLoaded&type=img/png" />
+ </body>
+</html>
diff --git a/dom/security/test/csp/file_bug909029_star.html^headers^ b/dom/security/test/csp/file_bug909029_star.html^headers^
new file mode 100644
index 0000000000..eccc1c0110
--- /dev/null
+++ b/dom/security/test/csp/file_bug909029_star.html^headers^
@@ -0,0 +1 @@
+Content-Security-Policy: default-src *; style-src * 'unsafe-inline';
diff --git a/dom/security/test/csp/file_bug910139.sjs b/dom/security/test/csp/file_bug910139.sjs
new file mode 100644
index 0000000000..56647134f8
--- /dev/null
+++ b/dom/security/test/csp/file_bug910139.sjs
@@ -0,0 +1,54 @@
+// Server side js file for bug 910139, see file test_bug910139.html for details.
+
+const { NetUtil } = ChromeUtils.import("resource://gre/modules/NetUtil.jsm");
+
+function loadResponseFromFile(path) {
+ var testHTMLFile = Components.classes["@mozilla.org/file/directory_service;1"]
+ .getService(Components.interfaces.nsIProperties)
+ .get("CurWorkD", Components.interfaces.nsIFile);
+ var dirs = path.split("/");
+ for (var i = 0; i < dirs.length; i++) {
+ testHTMLFile.append(dirs[i]);
+ }
+ var testHTMLFileStream = Components.classes[
+ "@mozilla.org/network/file-input-stream;1"
+ ].createInstance(Components.interfaces.nsIFileInputStream);
+ testHTMLFileStream.init(testHTMLFile, -1, 0, 0);
+ var testHTML = NetUtil.readInputStreamToString(
+ testHTMLFileStream,
+ testHTMLFileStream.available()
+ );
+ return testHTML;
+}
+
+var policies = [
+ "default-src 'self'; script-src 'self'", // CSP for checkAllowed
+ "default-src 'self'; script-src *.example.com", // CSP for checkBlocked
+];
+
+function getPolicy() {
+ var index;
+ // setState only accepts strings as arguments
+ if (!getState("counter")) {
+ index = 0;
+ setState("counter", index.toString());
+ } else {
+ index = parseInt(getState("counter"));
+ ++index;
+ setState("counter", index.toString());
+ }
+ return policies[index];
+}
+
+function handleRequest(request, response) {
+ // avoid confusing cache behaviors
+ response.setHeader("Cache-Control", "no-cache", false);
+
+ // set the required CSP
+ response.setHeader("Content-Security-Policy", getPolicy(), false);
+
+ // return the requested XML file.
+ response.write(
+ loadResponseFromFile("tests/dom/security/test/csp/file_bug910139.xml")
+ );
+}
diff --git a/dom/security/test/csp/file_bug910139.xml b/dom/security/test/csp/file_bug910139.xml
new file mode 100644
index 0000000000..29feba9418
--- /dev/null
+++ b/dom/security/test/csp/file_bug910139.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<?xml-stylesheet type="text/xsl" href="file_bug910139.xsl"?>
+<catalog>
+ <cd>
+ <title>Empire Burlesque</title>
+ <artist>Bob Dylan</artist>
+ <country>USA</country>
+ <company>Columbia</company>
+ <price>10.90</price>
+ <year>1985</year>
+ </cd>
+ <cd>
+ <title>Hide your heart</title>
+ <artist>Bonnie Tyler</artist>
+ <country>UK</country>
+ <company>CBS Records</company>
+ <price>9.90</price>
+ <year>1988</year>
+ </cd>
+ <cd>
+ <title>Greatest Hits</title>
+ <artist>Dolly Parton</artist>
+ <country>USA</country>
+ <company>RCA</company>
+ <price>9.90</price>
+ <year>1982</year>
+ </cd>
+</catalog>
diff --git a/dom/security/test/csp/file_bug910139.xsl b/dom/security/test/csp/file_bug910139.xsl
new file mode 100644
index 0000000000..b99abca099
--- /dev/null
+++ b/dom/security/test/csp/file_bug910139.xsl
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!-- Edited by XMLSpy® -->
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+
+<xsl:template match="/">
+ <html>
+ <body>
+ <h2 id="xsltheader">this xml file should be formatted using an xsl file(lower iframe should contain xml dump)!</h2>
+ <table border="1">
+ <tr bgcolor="#990099">
+ <th>Title</th>
+ <th>Artist</th>
+ <th>Price</th>
+ </tr>
+ <xsl:for-each select="catalog/cd">
+ <tr>
+ <td><xsl:value-of select="title"/></td>
+ <td><xsl:value-of select="artist"/></td>
+ <td><xsl:value-of select="price"/></td>
+ </tr>
+ </xsl:for-each>
+ </table>
+ </body>
+ </html>
+</xsl:template>
+</xsl:stylesheet>
+
diff --git a/dom/security/test/csp/file_bug941404.html b/dom/security/test/csp/file_bug941404.html
new file mode 100644
index 0000000000..3a2e636e0b
--- /dev/null
+++ b/dom/security/test/csp/file_bug941404.html
@@ -0,0 +1,27 @@
+<html>
+<head> <meta charset="utf-8"> </head>
+ <body>
+
+ <!-- this should be allowed (no CSP)-->
+ <img src="http://example.org/tests/dom/security/test/csp/file_CSP.sjs?testid=img_good&type=img/png"> </img>
+
+
+ <script type="text/javascript">
+ var req = new XMLHttpRequest();
+ req.onload = function() {
+ //this should be allowed (no CSP)
+ try {
+ var img = document.createElement("img");
+ img.src="http://example.org/tests/dom/security/test/csp/file_CSP.sjs?testid=img2_good&type=img/png";
+ document.body.appendChild(img);
+ } catch(e) {
+ console.log("yo: "+e);
+ }
+ };
+ req.open("get", "file_bug941404_xhr.html", true);
+ req.responseType = "document";
+ req.send();
+ </script>
+
+ </body>
+</html>
diff --git a/dom/security/test/csp/file_bug941404_xhr.html b/dom/security/test/csp/file_bug941404_xhr.html
new file mode 100644
index 0000000000..22e176f208
--- /dev/null
+++ b/dom/security/test/csp/file_bug941404_xhr.html
@@ -0,0 +1,5 @@
+<html>
+<head> <meta charset="utf-8"> </head>
+ <body>
+ </body>
+</html>
diff --git a/dom/security/test/csp/file_bug941404_xhr.html^headers^ b/dom/security/test/csp/file_bug941404_xhr.html^headers^
new file mode 100644
index 0000000000..1e5f70cc37
--- /dev/null
+++ b/dom/security/test/csp/file_bug941404_xhr.html^headers^
@@ -0,0 +1 @@
+Content-Security-Policy: default-src 'none' 'unsafe-inline' 'unsafe-eval'
diff --git a/dom/security/test/csp/file_child-src_iframe.html b/dom/security/test/csp/file_child-src_iframe.html
new file mode 100644
index 0000000000..18749011b9
--- /dev/null
+++ b/dom/security/test/csp/file_child-src_iframe.html
@@ -0,0 +1,61 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title>Bug 1045891</title>
+ </head>
+ <body>
+ <iframe id="testframe"> </iframe>
+ <script type="text/javascript">
+ page_id = window.location.hash.substring(1);
+
+ function executeTest(ev) {
+ testframe = document.getElementById('testframe');
+ testframe.contentWindow.postMessage({id:page_id, message:"execute"}, 'http://mochi.test:8888');
+ }
+
+ function reportError(ev) {
+ window.parent.postMessage({id:page_id, message:"blocked"}, 'http://mochi.test:8888');
+ cleanup();
+ }
+
+ function recvMessage(ev) {
+ if (ev.data.id == page_id) {
+ window.parent.postMessage({id:ev.data.id, message:ev.data.message}, 'http://mochi.test:8888');
+ cleanup();
+ }
+ }
+
+ function cleanup() {
+ testframe = document.getElementById('testframe');
+ window.removeEventListener('message', recvMessage);
+ testframe.removeEventListener('load', executeTest);
+ testframe.removeEventListener('error', reportError);
+ }
+
+
+ window.addEventListener('message', recvMessage);
+
+ try {
+ // Please note that file_testserver.sjs?foo does not return a response.
+ // For testing purposes this is not necessary because we only want to check
+ // whether CSP allows or blocks the load.
+ src = "file_testserver.sjs";
+ src += "?file=" + escape("tests/dom/security/test/csp/file_child-src_inner_frame.html");
+ src += "#" + escape(page_id);
+ testframe = document.getElementById('testframe');
+
+ testframe.addEventListener('load', executeTest);
+ testframe.addEventListener('error', reportError);
+
+ testframe.src = src;
+ }
+ catch (e) {
+ if (e.message.match(/Failed to load script/)) {
+ window.parent.postMessage({id:page_id, message:"blocked"}, 'http://mochi.test:8888');
+ } else {
+ window.parent.postMessage({id:page_id, message:"exception"}, 'http://mochi.test:8888');
+ }
+ }
+ </script>
+ </body>
+</html>
diff --git a/dom/security/test/csp/file_child-src_inner_frame.html b/dom/security/test/csp/file_child-src_inner_frame.html
new file mode 100644
index 0000000000..f0c4e66fa0
--- /dev/null
+++ b/dom/security/test/csp/file_child-src_inner_frame.html
@@ -0,0 +1,21 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title>Bug 1045891</title>
+ </head>
+ <body>
+ <iframe id="innermosttestframe"> </iframe>
+ <script type="text/javascript">
+ page_id = window.location.hash.substring(1);
+
+ function recvMessage(ev) {
+ if (ev.data.id == page_id) {
+ window.parent.postMessage({id:ev.data.id, message:'allowed'}, 'http://mochi.test:8888');
+ window.removeEventListener('message', recvMessage);
+ }
+ }
+
+ window.addEventListener('message', recvMessage);
+ </script>
+ </body>
+</html>
diff --git a/dom/security/test/csp/file_child-src_service_worker.html b/dom/security/test/csp/file_child-src_service_worker.html
new file mode 100644
index 0000000000..b291a4a4e8
--- /dev/null
+++ b/dom/security/test/csp/file_child-src_service_worker.html
@@ -0,0 +1,30 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title>Bug 1045891</title>
+ </head>
+ <body>
+ <script type="text/javascript">
+ page_id = window.location.hash.substring(1);
+ try {
+ if ('serviceWorker' in navigator) {
+ navigator.serviceWorker.register(
+ 'file_child-src_service_worker.js',
+ { scope: './' + page_id + '/' }
+ ).then(function(reg)
+ {
+ // registration worked
+ reg.unregister().then(function() {
+ window.parent.postMessage({id:page_id, message:"allowed"}, 'http://mochi.test:8888');
+ });
+ }).catch(function(error) {
+ // registration failed
+ window.parent.postMessage({id:page_id, message:"blocked"}, 'http://mochi.test:8888');
+ });
+ };
+ } catch(ex) {
+ window.parent.postMessage({id:page_id, message:"exception"}, 'http://mochi.test:8888');
+ }
+ </script>
+ </body>
+</html>
diff --git a/dom/security/test/csp/file_child-src_service_worker.js b/dom/security/test/csp/file_child-src_service_worker.js
new file mode 100644
index 0000000000..b8445fb175
--- /dev/null
+++ b/dom/security/test/csp/file_child-src_service_worker.js
@@ -0,0 +1,3 @@
+this.addEventListener("install", function (event) {
+ close();
+});
diff --git a/dom/security/test/csp/file_child-src_shared_worker-redirect.html b/dom/security/test/csp/file_child-src_shared_worker-redirect.html
new file mode 100644
index 0000000000..313915302e
--- /dev/null
+++ b/dom/security/test/csp/file_child-src_shared_worker-redirect.html
@@ -0,0 +1,47 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title>Bug 1045891</title>
+ </head>
+ <body>
+ <script type="text/javascript">
+ page_id = window.location.hash.substring(1);
+ var redir = 'none';
+
+ page_id.split('_').forEach(function (val) {
+ var [name, value] = val.split('-');
+ if (name == 'redir') {
+ redir = unescape(value);
+ }
+ });
+
+ try {
+ worker = new SharedWorker('file_redirect_worker.sjs?path='
+ + escape("/tests/dom/security/test/csp/file_child-src_shared_worker.js")
+ + "&redir=" + redir
+ + "&page_id=" + page_id,
+ page_id);
+ worker.port.start();
+
+ worker.onerror = function(evt) {
+ evt.preventDefault();
+ window.parent.postMessage({id:page_id, message:"blocked"},
+ 'http://mochi.test:8888');
+ }
+
+ worker.port.onmessage = function(ev) {
+ window.parent.postMessage({id:page_id, message:"allowed"}, 'http://mochi.test:8888');
+ };
+
+ worker.onerror = function() {
+ window.parent.postMessage({id:page_id, message:"blocked"}, 'http://mochi.test:8888');
+ };
+
+ worker.port.postMessage('foo');
+ }
+ catch (e) {
+ window.parent.postMessage({id:page_id, message:"blocked"}, 'http://mochi.test:8888');
+ }
+ </script>
+ </body>
+</html>
diff --git a/dom/security/test/csp/file_child-src_shared_worker.html b/dom/security/test/csp/file_child-src_shared_worker.html
new file mode 100644
index 0000000000..ce0c0261ed
--- /dev/null
+++ b/dom/security/test/csp/file_child-src_shared_worker.html
@@ -0,0 +1,35 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title>Bug 1045891</title>
+ </head>
+ <body>
+ <script type="text/javascript">
+ page_id = window.location.hash.substring(1);
+ try {
+ worker = new SharedWorker(
+ 'file_testserver.sjs?file='+
+ escape("tests/dom/security/test/csp/file_child-src_shared_worker.js") +
+ "&type=text/javascript",
+ page_id);
+ worker.port.start();
+
+ worker.onerror = function(evt) {
+ evt.preventDefault();
+ window.parent.postMessage({id:page_id, message:"blocked"},
+ 'http://mochi.test:8888');
+ }
+
+ worker.port.onmessage = function(ev) {
+ window.parent.postMessage({id:page_id, message:"allowed"},
+ 'http://mochi.test:8888');
+ };
+ worker.port.postMessage('foo');
+ }
+ catch (e) {
+ window.parent.postMessage({id:page_id, message:"blocked"},
+ 'http://mochi.test:8888');
+ }
+ </script>
+ </body>
+</html>
diff --git a/dom/security/test/csp/file_child-src_shared_worker.js b/dom/security/test/csp/file_child-src_shared_worker.js
new file mode 100644
index 0000000000..dbcdf9c9d7
--- /dev/null
+++ b/dom/security/test/csp/file_child-src_shared_worker.js
@@ -0,0 +1,8 @@
+onconnect = function (e) {
+ var port = e.ports[0];
+ port.addEventListener("message", function (e) {
+ port.postMessage("success");
+ });
+
+ port.start();
+};
diff --git a/dom/security/test/csp/file_child-src_shared_worker_data.html b/dom/security/test/csp/file_child-src_shared_worker_data.html
new file mode 100644
index 0000000000..a4befe4ca3
--- /dev/null
+++ b/dom/security/test/csp/file_child-src_shared_worker_data.html
@@ -0,0 +1,37 @@
+
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title>Bug 1045891</title>
+ </head>
+ <body>
+ <script type="text/javascript">
+ var page_id = window.location.hash.substring(1);
+ var shared_worker = "onconnect = function(e) { " +
+ "var port = e.ports[0];" +
+ "port.addEventListener('message'," +
+ "function(e) { port.postMessage('success'); });" +
+ "port.start(); }";
+
+ try {
+ var worker = new SharedWorker('data:application/javascript;charset=UTF-8,'+
+ escape(shared_worker), page_id);
+ worker.port.start();
+
+ worker.onerror = function(evt) {
+ evt.preventDefault();
+ window.parent.postMessage({id:page_id, message:"blocked"}, 'http://mochi.test:8888');
+ }
+
+ worker.port.onmessage = function(ev) {
+ window.parent.postMessage({id:page_id, message:"allowed"}, 'http://mochi.test:8888');
+ };
+
+ worker.port.postMessage('foo');
+ }
+ catch (e) {
+ window.parent.postMessage({id:page_id, message:"blocked"}, 'http://mochi.test:8888');
+ }
+ </script>
+ </body>
+</html>
diff --git a/dom/security/test/csp/file_child-src_worker-redirect.html b/dom/security/test/csp/file_child-src_worker-redirect.html
new file mode 100644
index 0000000000..b0029935c2
--- /dev/null
+++ b/dom/security/test/csp/file_child-src_worker-redirect.html
@@ -0,0 +1,47 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title>Bug 1045891</title>
+ </head>
+ <body>
+ <script type="text/javascript">
+ var page_id = window.location.hash.substring(1);
+ var redir = 'none';
+
+ page_id.split('_').forEach(function (val) {
+ var [name, value] = val.split('-');
+ if (name == 'redir') {
+ redir = unescape(value);
+ }
+ });
+
+ try {
+ worker = new Worker('file_redirect_worker.sjs?path='
+ + escape("/tests/dom/security/test/csp/file_child-src_worker.js")
+ + "&redir=" + redir
+ + "&page_id=" + page_id
+ );
+
+ worker.onerror = function(error) {
+ // this means CSP blocked it
+ var msg = !("message" in error) ? "blocked" : e.message;
+ window.parent.postMessage({id:page_id, message:msg}, 'http://mochi.test:8888');
+ error.preventDefault();
+ };
+
+ worker.onmessage = function(ev) {
+ window.parent.postMessage({id:page_id, message:"allowed"}, 'http://mochi.test:8888');
+
+ };
+ worker.postMessage('foo');
+ }
+ catch (e) {
+ if (e.message.match(/Failed to load script/)) {
+ window.parent.postMessage({id:page_id, message:"blocked"}, 'http://mochi.test:8888');
+ } else {
+ window.parent.postMessage({id:page_id, message:"exception"}, 'http://mochi.test:8888');
+ }
+ }
+ </script>
+ </body>
+</html>
diff --git a/dom/security/test/csp/file_child-src_worker.html b/dom/security/test/csp/file_child-src_worker.html
new file mode 100644
index 0000000000..a9fdbb3282
--- /dev/null
+++ b/dom/security/test/csp/file_child-src_worker.html
@@ -0,0 +1,34 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title>Bug 1045891</title>
+ </head>
+ <body>
+ <script type="text/javascript">
+ page_id = window.location.hash.substring(1);
+ try {
+ worker = new Worker('file_testserver.sjs?file='+
+ escape("tests/dom/security/test/csp/file_child-src_worker.js")
+ +"&type=text/javascript");
+
+ worker.onerror = function(e) {
+ window.parent.postMessage({id:page_id, message:"blocked"}, 'http://mochi.test:8888');
+ e.preventDefault();
+ }
+
+ worker.onmessage = function(ev) {
+ window.parent.postMessage({id:page_id, message:"allowed"}, 'http://mochi.test:8888');
+ }
+
+ worker.postMessage('foo');
+ }
+ catch (e) {
+ if (e.message.match(/Failed to load script/)) {
+ window.parent.postMessage({id:page_id, message:"blocked"}, 'http://mochi.test:8888');
+ } else {
+ window.parent.postMessage({id:page_id, message:"exception"}, 'http://mochi.test:8888');
+ }
+ }
+ </script>
+ </body>
+</html>
diff --git a/dom/security/test/csp/file_child-src_worker.js b/dom/security/test/csp/file_child-src_worker.js
new file mode 100644
index 0000000000..a6bb5e8044
--- /dev/null
+++ b/dom/security/test/csp/file_child-src_worker.js
@@ -0,0 +1,3 @@
+onmessage = function (e) {
+ postMessage("worker");
+};
diff --git a/dom/security/test/csp/file_child-src_worker_data.html b/dom/security/test/csp/file_child-src_worker_data.html
new file mode 100644
index 0000000000..e9e22f01da
--- /dev/null
+++ b/dom/security/test/csp/file_child-src_worker_data.html
@@ -0,0 +1,33 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title>Bug 1045891</title>
+ </head>
+ <body>
+ <script type="text/javascript">
+ page_id = window.location.hash.substring(1);
+ try {
+ worker = new Worker('data:application/javascript;charset=UTF-8,'+escape('onmessage = function(e) { postMessage("worker"); };'));
+
+ worker.onerror = function(e) {
+ window.parent.postMessage({id:page_id, message:"blocked"}, 'http://mochi.test:8888');
+ e.preventDefault();
+ }
+
+ worker.onmessage = function(ev) {
+ window.parent.postMessage({id:page_id, message:"allowed"}, 'http://mochi.test:8888');
+ }
+
+ worker.postMessage('foo');
+ }
+ catch (e) {
+ if (e.message.match(/Failed to load script/)) {
+ window.parent.postMessage({id:page_id, message:"blocked"}, 'http://mochi.test:8888');
+ } else {
+ console.log(e);
+ window.parent.postMessage({id:page_id, message:"exception"}, 'http://mochi.test:8888');
+ }
+ }
+ </script>
+ </body>
+</html>
diff --git a/dom/security/test/csp/file_connect-src-fetch.html b/dom/security/test/csp/file_connect-src-fetch.html
new file mode 100644
index 0000000000..ff9b2f740b
--- /dev/null
+++ b/dom/security/test/csp/file_connect-src-fetch.html
@@ -0,0 +1,16 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title>Bug 1139667 - Test mapping of fetch() to connect-src</title>
+ </head>
+ <body>
+ <script type="text/javascript">
+
+ // Please note that file_testserver.sjs?foo does not return a response.
+ // For testing purposes this is not necessary because we only want to check
+ // whether CSP allows or blocks the load.
+ fetch( "file_testserver.sjs?foo");
+
+ </script>
+</body>
+</html>
diff --git a/dom/security/test/csp/file_connect-src.html b/dom/security/test/csp/file_connect-src.html
new file mode 100644
index 0000000000..17a940a0e0
--- /dev/null
+++ b/dom/security/test/csp/file_connect-src.html
@@ -0,0 +1,21 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title>Bug 1031530 - Test mapping of XMLHttpRequest to connect-src</title>
+ </head>
+ <body>
+ <script type="text/javascript">
+
+ try {
+ // Please note that file_testserver.sjs?foo does not return a response.
+ // For testing purposes this is not necessary because we only want to check
+ // whether CSP allows or blocks the load.
+ var xhr = new XMLHttpRequest();
+ xhr.open("GET", "file_testserver.sjs?foo", false);
+ xhr.send(null);
+ }
+ catch (e) { }
+
+ </script>
+</body>
+</html>
diff --git a/dom/security/test/csp/file_csp_frame_ancestors_about_blank.html b/dom/security/test/csp/file_csp_frame_ancestors_about_blank.html
new file mode 100644
index 0000000000..6ce361a438
--- /dev/null
+++ b/dom/security/test/csp/file_csp_frame_ancestors_about_blank.html
@@ -0,0 +1,9 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Helper file for Bug 1668071 - CSP frame-ancestors in about:blank</title>
+</head>
+<body>
+ CSP frame-ancestors in about:blank
+</body>
+</html>
diff --git a/dom/security/test/csp/file_csp_frame_ancestors_about_blank.html^headers^ b/dom/security/test/csp/file_csp_frame_ancestors_about_blank.html^headers^
new file mode 100644
index 0000000000..e5d129c3e8
--- /dev/null
+++ b/dom/security/test/csp/file_csp_frame_ancestors_about_blank.html^headers^
@@ -0,0 +1,2 @@
+Cache-Control: no-cache
+Content-Security-Policy: frame-ancestors http://mochi.test:8888 http://mochi.xorigin-test:8888
diff --git a/dom/security/test/csp/file_csp_meta_uir.html b/dom/security/test/csp/file_csp_meta_uir.html
new file mode 100644
index 0000000000..dba1030975
--- /dev/null
+++ b/dom/security/test/csp/file_csp_meta_uir.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="UTF-8">
+ <title>Hello World</title>
+ <meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">
+</head>
+<body>
+ <script>
+ document.write("<a href='" + document.location.href.replace(/^https/, "http") + "' id='mylink'>Click me</a>");
+ </script>
+</body>
+</html>
diff --git a/dom/security/test/csp/file_data-uri_blocked.html b/dom/security/test/csp/file_data-uri_blocked.html
new file mode 100644
index 0000000000..59b7b25902
--- /dev/null
+++ b/dom/security/test/csp/file_data-uri_blocked.html
@@ -0,0 +1,15 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1242019
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 587377</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+ <img width='1' height='1' title='' alt='' src='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAACXBIWXMAAAsTAAALEwEAmpwYAAAKTWlDQ1BQaG90b3Nob3AgSUNDIHByb2ZpbGUAAHjanVN3WJP3Fj7f92UPVkLY8LGXbIEAIiOsCMgQWaIQkgBhhBASQMWFiApWFBURnEhVxILVCkidiOKgKLhnQYqIWotVXDjuH9yntX167+3t+9f7vOec5/zOec8PgBESJpHmomoAOVKFPDrYH49PSMTJvYACFUjgBCAQ5svCZwXFAADwA3l4fnSwP/wBr28AAgBw1S4kEsfh/4O6UCZXACCRAOAiEucLAZBSAMguVMgUAMgYALBTs2QKAJQAAGx5fEIiAKoNAOz0ST4FANipk9wXANiiHKkIAI0BAJkoRyQCQLsAYFWBUiwCwMIAoKxAIi4EwK4BgFm2MkcCgL0FAHaOWJAPQGAAgJlCLMwAIDgCAEMeE80DIEwDoDDSv+CpX3CFuEgBAMDLlc2XS9IzFLiV0Bp38vDg4iHiwmyxQmEXKRBmCeQinJebIxNI5wNMzgwAABr50cH+OD+Q5+bk4eZm52zv9MWi/mvwbyI+IfHf/ryMAgQAEE7P79pf5eXWA3DHAbB1v2upWwDaVgBo3/ldM9sJoFoK0Hr5i3k4/EAenqFQyDwdHAoLC+0lYqG9MOOLPv8z4W/gi372/EAe/tt68ABxmkCZrcCjg/1xYW52rlKO58sEQjFu9+cj/seFf/2OKdHiNLFcLBWK8ViJuFAiTcd5uVKRRCHJleIS6X8y8R+W/QmTdw0ArIZPwE62B7XLbMB+7gECiw5Y0nYAQH7zLYwaC5EAEGc0Mnn3AACTv/mPQCsBAM2XpOMAALzoGFyolBdMxggAAESggSqwQQcMwRSswA6cwR28wBcCYQZEQAwkwDwQQgbkgBwKoRiWQRlUwDrYBLWwAxqgEZrhELTBMTgN5+ASXIHrcBcGYBiewhi8hgkEQcgIE2EhOogRYo7YIs4IF5mOBCJhSDSSgKQg6YgUUSLFyHKkAqlCapFdSCPyLXIUOY1cQPqQ28ggMor8irxHMZSBslED1AJ1QLmoHxqKxqBz0XQ0D12AlqJr0Rq0Hj2AtqKn0UvodXQAfYqOY4DRMQ5mjNlhXIyHRWCJWBomxxZj5Vg1Vo81Yx1YN3YVG8CeYe8IJAKLgBPsCF6EEMJsgpCQR1hMWEOoJewjtBK6CFcJg4Qxwicik6hPtCV6EvnEeGI6sZBYRqwm7iEeIZ4lXicOE1+TSCQOyZLkTgohJZAySQtJa0jbSC2kU6Q+0hBpnEwm65Btyd7kCLKArCCXkbeQD5BPkvvJw+S3FDrFiOJMCaIkUqSUEko1ZT/lBKWfMkKZoKpRzame1AiqiDqfWkltoHZQL1OHqRM0dZolzZsWQ8ukLaPV0JppZ2n3aC/pdLoJ3YMeRZfQl9Jr6Afp5+mD9HcMDYYNg8dIYigZaxl7GacYtxkvmUymBdOXmchUMNcyG5lnmA+Yb1VYKvYqfBWRyhKVOpVWlX6V56pUVXNVP9V5qgtUq1UPq15WfaZGVbNQ46kJ1Bar1akdVbupNq7OUndSj1DPUV+jvl/9gvpjDbKGhUaghkijVGO3xhmNIRbGMmXxWELWclYD6yxrmE1iW7L57Ex2Bfsbdi97TFNDc6pmrGaRZp3mcc0BDsax4PA52ZxKziHODc57LQMtPy2x1mqtZq1+rTfaetq+2mLtcu0W7eva73VwnUCdLJ31Om0693UJuja6UbqFutt1z+o+02PreekJ9cr1Dund0Uf1bfSj9Rfq79bv0R83MDQINpAZbDE4Y/DMkGPoa5hpuNHwhOGoEctoupHEaKPRSaMnuCbuh2fjNXgXPmasbxxirDTeZdxrPGFiaTLbpMSkxeS+Kc2Ua5pmutG003TMzMgs3KzYrMnsjjnVnGueYb7ZvNv8jYWlRZzFSos2i8eW2pZ8ywWWTZb3rJhWPlZ5VvVW16xJ1lzrLOtt1ldsUBtXmwybOpvLtqitm63Edptt3xTiFI8p0in1U27aMez87ArsmuwG7Tn2YfYl9m32zx3MHBId1jt0O3xydHXMdmxwvOuk4TTDqcSpw+lXZxtnoXOd8zUXpkuQyxKXdpcXU22niqdun3rLleUa7rrStdP1o5u7m9yt2W3U3cw9xX2r+00umxvJXcM970H08PdY4nHM452nm6fC85DnL152Xlle+70eT7OcJp7WMG3I28Rb4L3Le2A6Pj1l+s7pAz7GPgKfep+Hvqa+It89viN+1n6Zfgf8nvs7+sv9j/i/4XnyFvFOBWABwQHlAb2BGoGzA2sDHwSZBKUHNQWNBbsGLww+FUIMCQ1ZH3KTb8AX8hv5YzPcZyya0RXKCJ0VWhv6MMwmTB7WEY6GzwjfEH5vpvlM6cy2CIjgR2yIuB9pGZkX+X0UKSoyqi7qUbRTdHF09yzWrORZ+2e9jvGPqYy5O9tqtnJ2Z6xqbFJsY+ybuIC4qriBeIf4RfGXEnQTJAntieTE2MQ9ieNzAudsmjOc5JpUlnRjruXcorkX5unOy553PFk1WZB8OIWYEpeyP+WDIEJQLxhP5aduTR0T8oSbhU9FvqKNolGxt7hKPJLmnVaV9jjdO31D+miGT0Z1xjMJT1IreZEZkrkj801WRNberM/ZcdktOZSclJyjUg1plrQr1zC3KLdPZisrkw3keeZtyhuTh8r35CP5c/PbFWyFTNGjtFKuUA4WTC+oK3hbGFt4uEi9SFrUM99m/ur5IwuCFny9kLBQuLCz2Lh4WfHgIr9FuxYji1MXdy4xXVK6ZHhp8NJ9y2jLspb9UOJYUlXyannc8o5Sg9KlpUMrglc0lamUycturvRauWMVYZVkVe9ql9VbVn8qF5VfrHCsqK74sEa45uJXTl/VfPV5bdra3kq3yu3rSOuk626s91m/r0q9akHV0IbwDa0b8Y3lG19tSt50oXpq9Y7NtM3KzQM1YTXtW8y2rNvyoTaj9nqdf13LVv2tq7e+2Sba1r/dd3vzDoMdFTve75TsvLUreFdrvUV99W7S7oLdjxpiG7q/5n7duEd3T8Wej3ulewf2Re/ranRvbNyvv7+yCW1SNo0eSDpw5ZuAb9qb7Zp3tXBaKg7CQeXBJ9+mfHvjUOihzsPcw83fmX+39QjrSHkr0jq/dawto22gPaG97+iMo50dXh1Hvrf/fu8x42N1xzWPV56gnSg98fnkgpPjp2Snnp1OPz3Umdx590z8mWtdUV29Z0PPnj8XdO5Mt1/3yfPe549d8Lxw9CL3Ytslt0utPa49R35w/eFIr1tv62X3y+1XPK509E3rO9Hv03/6asDVc9f41y5dn3m978bsG7duJt0cuCW69fh29u0XdwruTNxdeo94r/y+2v3qB/oP6n+0/rFlwG3g+GDAYM/DWQ/vDgmHnv6U/9OH4dJHzEfVI0YjjY+dHx8bDRq98mTOk+GnsqcTz8p+Vv9563Or59/94vtLz1j82PAL+YvPv655qfNy76uprzrHI8cfvM55PfGm/K3O233vuO+638e9H5ko/ED+UPPR+mPHp9BP9z7nfP78L/eE8/sl0p8zAAA6NGlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4KPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS42LWMxMTEgNzkuMTU4MzI1LCAyMDE1LzA5LzEwLTAxOjEwOjIwICAgICAgICAiPgogICA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPgogICAgICA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIgogICAgICAgICAgICB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iCiAgICAgICAgICAgIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vIgogICAgICAgICAgICB4bWxuczpzdEV2dD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3NUeXBlL1Jlc291cmNlRXZlbnQjIgogICAgICAgICAgICB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iCiAgICAgICAgICAgIHhtbG5zOnBob3Rvc2hvcD0iaHR0cDovL25zLmFkb2JlLmNvbS9waG90b3Nob3AvMS4wLyIKICAgICAgICAgICAgeG1sbnM6dGlmZj0iaHR0cDovL25zLmFkb2JlLmNvbS90aWZmLzEuMC8iCiAgICAgICAgICAgIHhtbG5zOmV4aWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20vZXhpZi8xLjAvIj4KICAgICAgICAgPHhtcDpDcmVhdG9yVG9vbD5BZG9iZSBQaG90b3Nob3AgQ0MgMjAxNSAoTWFjaW50b3NoKTwveG1wOkNyZWF0b3JUb29sPgogICAgICAgICA8eG1wOkNyZWF0ZURhdGU+MjAxNi0wMi0wOFQxMzoyNjo1MSswOTowMDwveG1wOkNyZWF0ZURhdGU+CiAgICAgICAgIDx4bXA6TWV0YWRhdGFEYXRlPjIwMTYtMDItMDhUMTM6MjY6NTErMDk6MDA8L3htcDpNZXRhZGF0YURhdGU+CiAgICAgICAgIDx4bXA6TW9kaWZ5RGF0ZT4yMDE2LTAyLTA4VDEzOjI2OjUxKzA5OjAwPC94bXA6TW9kaWZ5RGF0ZT4KICAgICAgICAgPHhtcE1NOkluc3RhbmNlSUQ+eG1wLmlpZDplN2QyMjJjOS03Nzg2LTRhMjktOTlhMy0yYjRjNWI4YTA5MWY8L3htcE1NOkluc3RhbmNlSUQ+CiAgICAgICAgIDx4bXBNTTpEb2N1bWVudElEPmFkb2JlOmRvY2lkOnBob3Rvc2hvcDo5OWE3ZTJmOC0wZWFhLTExNzktYTE4NS05M2Y1MjZhZGU2ZDg8L3htcE1NOkRvY3VtZW50SUQ+CiAgICAgICAgIDx4bXBNTTpPcmlnaW5hbERvY3VtZW50SUQ+eG1wLmRpZDoyYmY3M2M3Ny03NzczLTQzNjAtYThiZS1kY2UyZTgzMWQ2YmM8L3htcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD4KICAgICAgICAgPHhtcE1NOkhpc3Rvcnk+CiAgICAgICAgICAgIDxyZGY6U2VxPgogICAgICAgICAgICAgICA8cmRmOmxpIHJkZjpwYXJzZVR5cGU9IlJlc291cmNlIj4KICAgICAgICAgICAgICAgICAgPHN0RXZ0OmFjdGlvbj5jcmVhdGVkPC9zdEV2dDphY3Rpb24+CiAgICAgICAgICAgICAgICAgIDxzdEV2dDppbnN0YW5jZUlEPnhtcC5paWQ6MmJmNzNjNzctNzc3My00MzYwLWE4YmUtZGNlMmU4MzFkNmJjPC9zdEV2dDppbnN0YW5jZUlEPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6d2hlbj4yMDE2LTAyLTA4VDEzOjI2OjUxKzA5OjAwPC9zdEV2dDp3aGVuPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6c29mdHdhcmVBZ2VudD5BZG9iZSBQaG90b3Nob3AgQ0MgMjAxNSAoTWFjaW50b3NoKTwvc3RFdnQ6c29mdHdhcmVBZ2VudD4KICAgICAgICAgICAgICAgPC9yZGY6bGk+CiAgICAgICAgICAgICAgIDxyZGY6bGkgcmRmOnBhcnNlVHlwZT0iUmVzb3VyY2UiPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6YWN0aW9uPnNhdmVkPC9zdEV2dDphY3Rpb24+CiAgICAgICAgICAgICAgICAgIDxzdEV2dDppbnN0YW5jZUlEPnhtcC5paWQ6ZTdkMjIyYzktNzc4Ni00YTI5LTk5YTMtMmI0YzViOGEwOTFmPC9zdEV2dDppbnN0YW5jZUlEPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6d2hlbj4yMDE2LTAyLTA4VDEzOjI2OjUxKzA5OjAwPC9zdEV2dDp3aGVuPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6c29mdHdhcmVBZ2VudD5BZG9iZSBQaG90b3Nob3AgQ0MgMjAxNSAoTWFjaW50b3NoKTwvc3RFdnQ6c29mdHdhcmVBZ2VudD4KICAgICAgICAgICAgICAgICAgPHN0RXZ0OmNoYW5nZWQ+Lzwvc3RFdnQ6Y2hhbmdlZD4KICAgICAgICAgICAgICAgPC9yZGY6bGk+CiAgICAgICAgICAgIDwvcmRmOlNlcT4KICAgICAgICAgPC94bXBNTTpIaXN0b3J5PgogICAgICAgICA8ZGM6Zm9ybWF0PmltYWdlL3BuZzwvZGM6Zm9ybWF0PgogICAgICAgICA8cGhvdG9zaG9wOkNvbG9yTW9kZT4zPC9waG90b3Nob3A6Q29sb3JNb2RlPgogICAgICAgICA8cGhvdG9zaG9wOklDQ1Byb2ZpbGU+c1JHQiBJRUM2MTk2Ni0yLjE8L3Bob3Rvc2hvcDpJQ0NQcm9maWxlPgogICAgICAgICA8dGlmZjpPcmllbnRhdGlvbj4xPC90aWZmOk9yaWVudGF0aW9uPgogICAgICAgICA8dGlmZjpYUmVzb2x1dGlvbj43MjAwMDAvMTAwMDA8L3RpZmY6WFJlc29sdXRpb24+CiAgICAgICAgIDx0aWZmOllSZXNvbHV0aW9uPjcyMDAwMC8xMDAwMDwvdGlmZjpZUmVzb2x1dGlvbj4KICAgICAgICAgPHRpZmY6UmVzb2x1dGlvblVuaXQ+MjwvdGlmZjpSZXNvbHV0aW9uVW5pdD4KICAgICAgICAgPGV4aWY6Q29sb3JTcGFjZT4xPC9leGlmOkNvbG9yU3BhY2U+CiAgICAgICAgIDxleGlmOlBpeGVsWERpbWVuc2lvbj4xPC9leGlmOlBpeGVsWERpbWVuc2lvbj4KICAgICAgICAgPGV4aWY6UGl4ZWxZRGltZW5zaW9uPjE8L2V4aWY6UGl4ZWxZRGltZW5zaW9uPgogICAgICA8L3JkZjpEZXNjcmlwdGlvbj4KICAgPC9yZGY6UkRGPgo8L3g6eG1wbWV0YT4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAKPD94cGFja2V0IGVuZD0idyI/PoAp5ZwAAAAgY0hSTQAAeiUAAICDAAD5/wAAgOkAAHUwAADqYAAAOpgAABdvkl/FRgAAABNJREFUeNpi+P//PwMAAAD//wMACPwC/tOldWEAAAAASUVORK5CYII='>
+</body>
+</html>
diff --git a/dom/security/test/csp/file_data-uri_blocked.html^headers^ b/dom/security/test/csp/file_data-uri_blocked.html^headers^
new file mode 100644
index 0000000000..4248cca188
--- /dev/null
+++ b/dom/security/test/csp/file_data-uri_blocked.html^headers^
@@ -0,0 +1 @@
+Content-Security-Policy: default-src 'self' 'report-sample'; img-src 'none' 'report-sample'
diff --git a/dom/security/test/csp/file_data_csp_inheritance.html b/dom/security/test/csp/file_data_csp_inheritance.html
new file mode 100644
index 0000000000..4ae2fedc69
--- /dev/null
+++ b/dom/security/test/csp/file_data_csp_inheritance.html
@@ -0,0 +1,24 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 1381761 - Treating 'data:' documents as unique, opaque origins should still inherit the CSP</title>
+ <meta charset="utf-8">
+ <meta http-equiv="Content-Security-Policy" content= "img-src 'none'"/>
+</head>
+<body>
+<iframe id="dataFrame" src="data:text/html,<body>should inherit csp</body>"></iframe>
+
+<script type="application/javascript">
+ // get the csp in JSON notation from the principal
+ var frame = document.getElementById("dataFrame");
+ frame.onload = function () {
+ var contentDoc = SpecialPowers.wrap(frame).contentDocument;
+ var cspOBJ = JSON.parse(contentDoc.cspJSON);
+ // make sure we got >>one<< policy
+ var policies = cspOBJ["csp-policies"];
+ window.parent.postMessage({result: policies.length}, "*");
+ }
+</script>
+
+</body>
+</html>
diff --git a/dom/security/test/csp/file_data_csp_merge.html b/dom/security/test/csp/file_data_csp_merge.html
new file mode 100644
index 0000000000..88ae8febe5
--- /dev/null
+++ b/dom/security/test/csp/file_data_csp_merge.html
@@ -0,0 +1,26 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 1386183 - Meta CSP on data: URI iframe should be merged with toplevel CSP</title>
+ <meta charset="utf-8">
+ <meta http-equiv="Content-Security-Policy" content= "img-src https:"/>
+</head>
+<body>
+<iframe id="dataFrame" onload="doCSPMergeCheck()"
+ src="data:text/html,<html><head><meta http-equiv='Content-Security-Policy' content='script-src https:'/></head><body>merge csp</body></html>">
+</iframe>
+
+<script type="application/javascript">
+ function doCSPMergeCheck() {
+ // get the csp in JSON notation from the principal
+ var frame = document.getElementById("dataFrame");
+ var contentDoc = SpecialPowers.wrap(frame).contentDocument;
+ var cspOBJ = JSON.parse(contentDoc.cspJSON);
+ // make sure we got >>two<< policies
+ var policies = cspOBJ["csp-policies"];
+ window.parent.postMessage({result: policies.length}, "*");
+ }
+</script>
+
+</body>
+</html>
diff --git a/dom/security/test/csp/file_data_doc_ignore_meta_csp.html b/dom/security/test/csp/file_data_doc_ignore_meta_csp.html
new file mode 100644
index 0000000000..9d6e9834dd
--- /dev/null
+++ b/dom/security/test/csp/file_data_doc_ignore_meta_csp.html
@@ -0,0 +1,22 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 1382869: data document should ignore meta csp</title>
+ <meta charset="utf-8">
+</head>
+<body>
+<script type="application/javascript">
+ // 1) create a data document
+ const doc = document.implementation.createHTMLDocument();
+ // 2) add meta csp to that document
+ const metaEl = doc.createElement('meta');
+ metaEl.setAttribute('http-equiv', 'Content-Security-Policy');
+ metaEl.setAttribute('content', "img-src 'none'");
+ doc.head.appendChild(metaEl);
+ // 3) let the parent know we are done here
+ var result = "dataDocCreated";
+ window.parent.postMessage({result}, "*");
+</script>
+
+</body>
+</html>
diff --git a/dom/security/test/csp/file_doccomment_meta.html b/dom/security/test/csp/file_doccomment_meta.html
new file mode 100644
index 0000000000..a0f36a4bfe
--- /dev/null
+++ b/dom/security/test/csp/file_doccomment_meta.html
@@ -0,0 +1,28 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 663570 - Test doc.write(meta csp)</title>
+ <meta charset="utf-8">
+
+ <!-- Use doc.write() to *un*apply meta csp -->
+ <script type="application/javascript">
+ document.write("<!--");
+ </script>
+
+ <meta http-equiv="Content-Security-Policy" content= "style-src 'none'; script-src 'none'; img-src 'none'">
+ -->
+
+ <!-- try to load a css on a page where meta CSP is commented out -->
+ <link rel="stylesheet" type="text/css" href="file_docwrite_meta.css">
+
+ <!-- try to load a script on a page where meta CSP is commented out -->
+ <script id="testscript" src="file_docwrite_meta.js"></script>
+
+</head>
+<body>
+
+ <!-- try to load an image on a page where meta CSP is commented out -->
+ <img id="testimage" src="http://mochi.test:8888/tests/image/test/mochitest/blue.png"></img>
+
+</body>
+</html>
diff --git a/dom/security/test/csp/file_docwrite_meta.css b/dom/security/test/csp/file_docwrite_meta.css
new file mode 100644
index 0000000000..de725038b6
--- /dev/null
+++ b/dom/security/test/csp/file_docwrite_meta.css
@@ -0,0 +1,3 @@
+body {
+ background-color: rgb(255, 0, 0);
+}
diff --git a/dom/security/test/csp/file_docwrite_meta.html b/dom/security/test/csp/file_docwrite_meta.html
new file mode 100644
index 0000000000..292de3bec5
--- /dev/null
+++ b/dom/security/test/csp/file_docwrite_meta.html
@@ -0,0 +1,26 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 663570 - Test doc.write(meta csp)</title>
+ <meta charset="utf-8">
+
+ <!-- Use doc.write() to apply meta csp -->
+ <script type="application/javascript">
+ var metaCSP = "style-src 'none'; script-src 'none'; img-src 'none'";
+ document.write("<meta http-equiv=\"Content-Security-Policy\" content=\" " + metaCSP + "\">");
+ </script>
+
+ <!-- try to load a css which is forbidden by meta CSP -->
+ <link rel="stylesheet" type="text/css" href="file_docwrite_meta.css">
+
+ <!-- try to load a script which is forbidden by meta CSP -->
+ <script id="testscript" src="file_docwrite_meta.js"></script>
+
+</head>
+<body>
+
+ <!-- try to load an image which is forbidden by meta CSP -->
+ <img id="testimage" src="http://mochi.test:8888/tests/image/test/mochitest/blue.png"></img>
+
+</body>
+</html>
diff --git a/dom/security/test/csp/file_docwrite_meta.js b/dom/security/test/csp/file_docwrite_meta.js
new file mode 100644
index 0000000000..722adc235e
--- /dev/null
+++ b/dom/security/test/csp/file_docwrite_meta.js
@@ -0,0 +1,3 @@
+// set a variable on the document which we can check to verify
+// whether the external script was loaded or blocked
+document.myMetaCSPScript = "external-JS-loaded";
diff --git a/dom/security/test/csp/file_dual_header_testserver.sjs b/dom/security/test/csp/file_dual_header_testserver.sjs
new file mode 100644
index 0000000000..0efe186d57
--- /dev/null
+++ b/dom/security/test/csp/file_dual_header_testserver.sjs
@@ -0,0 +1,45 @@
+/*
+ * Custom sjs file serving a test page using *two* CSP policies.
+ * See Bug 1036399 - Multiple CSP policies should be combined towards an intersection
+ */
+
+const TIGHT_POLICY = "default-src 'self'";
+const LOOSE_POLICY = "default-src 'self' 'unsafe-inline'";
+
+function handleRequest(request, response) {
+ // avoid confusing cache behaviors
+ response.setHeader("Cache-Control", "no-cache", false);
+
+ var csp = "";
+ // deliver *TWO* comma separated policies which is in fact the same as serving
+ // to separate CSP headers (AppendPolicy is called twice).
+ if (request.queryString == "tight") {
+ // script execution will be *blocked*
+ csp = TIGHT_POLICY + ", " + LOOSE_POLICY;
+ } else {
+ // script execution will be *allowed*
+ csp = LOOSE_POLICY + ", " + LOOSE_POLICY;
+ }
+ response.setHeader("Content-Security-Policy", csp, false);
+
+ // Send HTML to test allowed/blocked behaviors
+ response.setHeader("Content-Type", "text/html", false);
+
+ // generate an html file that contains a div container which is updated
+ // in case the inline script is *not* blocked by CSP.
+ var html =
+ "<!DOCTYPE HTML>" +
+ "<html>" +
+ "<head>" +
+ "<title>Testpage for Bug 1036399</title>" +
+ "</head>" +
+ "<body>" +
+ "<div id='testdiv'>blocked</div>" +
+ "<script type='text/javascript'>" +
+ "document.getElementById('testdiv').innerHTML = 'allowed';" +
+ "</script>" +
+ "</body>" +
+ "</html>";
+
+ response.write(html);
+}
diff --git a/dom/security/test/csp/file_dummy_pixel.png b/dom/security/test/csp/file_dummy_pixel.png
new file mode 100644
index 0000000000..52c591798e
--- /dev/null
+++ b/dom/security/test/csp/file_dummy_pixel.png
Binary files differ
diff --git a/dom/security/test/csp/file_empty_directive.html b/dom/security/test/csp/file_empty_directive.html
new file mode 100644
index 0000000000..16196bb19f
--- /dev/null
+++ b/dom/security/test/csp/file_empty_directive.html
@@ -0,0 +1,11 @@
+<!doctype html>
+<html>
+ <head>
+ <meta charset="utf8">
+ <title>Bug 587377 - CSP keywords "'self'" and "'none'" are easy to confuse with host names "self" and "none"</title>
+ <!-- Any copyright is dedicated to the Public Domain.
+ - http://creativecommons.org/publicdomain/zero/1.0/ -->
+ </head>
+ <body>
+ </body>
+</html>
diff --git a/dom/security/test/csp/file_empty_directive.html^headers^ b/dom/security/test/csp/file_empty_directive.html^headers^
new file mode 100644
index 0000000000..50dbe57bb9
--- /dev/null
+++ b/dom/security/test/csp/file_empty_directive.html^headers^
@@ -0,0 +1 @@
+Content-Security-Policy: ;
diff --git a/dom/security/test/csp/file_evalscript_main.html b/dom/security/test/csp/file_evalscript_main.html
new file mode 100644
index 0000000000..e83c1d9ed7
--- /dev/null
+++ b/dom/security/test/csp/file_evalscript_main.html
@@ -0,0 +1,12 @@
+<html>
+ <head>
+ <title>CSP eval script tests</title>
+ <script type="application/javascript"
+ src="file_evalscript_main.js"></script>
+ </head>
+ <body>
+
+ Foo.
+
+ </body>
+</html>
diff --git a/dom/security/test/csp/file_evalscript_main.html^headers^ b/dom/security/test/csp/file_evalscript_main.html^headers^
new file mode 100644
index 0000000000..b91ba384d9
--- /dev/null
+++ b/dom/security/test/csp/file_evalscript_main.html^headers^
@@ -0,0 +1,2 @@
+Cache-Control: no-cache
+Content-Security-Policy: default-src 'self'
diff --git a/dom/security/test/csp/file_evalscript_main.js b/dom/security/test/csp/file_evalscript_main.js
new file mode 100644
index 0000000000..cc2c3fbe73
--- /dev/null
+++ b/dom/security/test/csp/file_evalscript_main.js
@@ -0,0 +1,240 @@
+// some javascript for the CSP eval() tests
+
+function logResult(str, passed) {
+ var elt = document.createElement("div");
+ var color = passed ? "#cfc;" : "#fcc";
+ elt.setAttribute(
+ "style",
+ "background-color:" +
+ color +
+ "; width:100%; border:1px solid black; padding:3px; margin:4px;"
+ );
+ elt.innerHTML = str;
+ document.body.appendChild(elt);
+}
+
+window._testResults = {};
+
+// check values for return values from blocked timeout or intervals
+var verifyZeroRetVal = (function (window) {
+ return function (val, details) {
+ logResult(
+ (val === 0 ? "PASS: " : "FAIL: ") +
+ "Blocked interval/timeout should have zero return value; " +
+ details,
+ val === 0
+ );
+ window.parent.verifyZeroRetVal(val, details);
+ };
+})(window);
+
+// callback for when stuff is allowed by CSP
+var onevalexecuted = (function (window) {
+ return function (shouldrun, what, data) {
+ window._testResults[what] = "ran";
+ window.parent.scriptRan(shouldrun, what, data);
+ logResult(
+ (shouldrun ? "PASS: " : "FAIL: ") + what + " : " + data,
+ shouldrun
+ );
+ };
+})(window);
+
+// callback for when stuff is blocked
+var onevalblocked = (function (window) {
+ return function (shouldrun, what, data) {
+ window._testResults[what] = "blocked";
+ window.parent.scriptBlocked(shouldrun, what, data);
+ logResult(
+ (shouldrun ? "FAIL: " : "PASS: ") + what + " : " + data,
+ !shouldrun
+ );
+ };
+})(window);
+
+// Defer until document is loaded so that we can write the pretty result boxes
+// out.
+addEventListener(
+ "load",
+ function () {
+ // setTimeout(String) test -- mutate something in the window._testResults
+ // obj, then check it.
+ {
+ var str_setTimeoutWithStringRan =
+ 'onevalexecuted(false, "setTimeout(String)", "setTimeout with a string was enabled.");';
+ function fcn_setTimeoutWithStringCheck() {
+ if (this._testResults["setTimeout(String)"] !== "ran") {
+ onevalblocked(
+ false,
+ "setTimeout(String)",
+ "setTimeout with a string was blocked"
+ );
+ }
+ }
+ setTimeout(fcn_setTimeoutWithStringCheck.bind(window), 10);
+ var res = setTimeout(str_setTimeoutWithStringRan, 10);
+ verifyZeroRetVal(res, "setTimeout(String)");
+ }
+
+ // setInterval(String) test -- mutate something in the window._testResults
+ // obj, then check it.
+ {
+ var str_setIntervalWithStringRan =
+ 'onevalexecuted(false, "setInterval(String)", "setInterval with a string was enabled.");';
+ function fcn_setIntervalWithStringCheck() {
+ if (this._testResults["setInterval(String)"] !== "ran") {
+ onevalblocked(
+ false,
+ "setInterval(String)",
+ "setInterval with a string was blocked"
+ );
+ }
+ }
+ setTimeout(fcn_setIntervalWithStringCheck.bind(window), 10);
+ var res = setInterval(str_setIntervalWithStringRan, 10);
+ verifyZeroRetVal(res, "setInterval(String)");
+
+ // emergency cleanup, just in case.
+ if (res != 0) {
+ setTimeout(function () {
+ clearInterval(res);
+ }, 15);
+ }
+ }
+
+ // setTimeout(function) test -- mutate something in the window._testResults
+ // obj, then check it.
+ {
+ function fcn_setTimeoutWithFunctionRan() {
+ onevalexecuted(
+ true,
+ "setTimeout(function)",
+ "setTimeout with a function was enabled."
+ );
+ }
+ function fcn_setTimeoutWithFunctionCheck() {
+ if (this._testResults["setTimeout(function)"] !== "ran") {
+ onevalblocked(
+ true,
+ "setTimeout(function)",
+ "setTimeout with a function was blocked"
+ );
+ }
+ }
+ setTimeout(fcn_setTimeoutWithFunctionRan.bind(window), 10);
+ setTimeout(fcn_setTimeoutWithFunctionCheck.bind(window), 10);
+ }
+
+ // eval() test -- should throw exception as per spec
+ try {
+ eval('onevalexecuted(false, "eval(String)", "eval() was enabled.");');
+ } catch (e) {
+ onevalblocked(false, "eval(String)", "eval() was blocked");
+ }
+
+ // eval(foo,bar) test -- should throw exception as per spec
+ try {
+ eval(
+ 'onevalexecuted(false, "eval(String,scope)", "eval() was enabled.");',
+ 1
+ );
+ } catch (e) {
+ onevalblocked(
+ false,
+ "eval(String,object)",
+ "eval() with scope was blocked"
+ );
+ }
+
+ // [foo,bar].sort(eval) test -- should throw exception as per spec
+ try {
+ [
+ 'onevalexecuted(false, "[String, obj].sort(eval)", "eval() was enabled.");',
+ 1,
+ ].sort(eval);
+ } catch (e) {
+ onevalblocked(
+ false,
+ "[String, obj].sort(eval)",
+ "eval() with scope via sort was blocked"
+ );
+ }
+
+ // [].sort.call([foo,bar], eval) test -- should throw exception as per spec
+ try {
+ [].sort.call(
+ [
+ 'onevalexecuted(false, "[String, obj].sort(eval)", "eval() was enabled.");',
+ 1,
+ ],
+ eval
+ );
+ } catch (e) {
+ onevalblocked(
+ false,
+ "[].sort.call([String, obj], eval)",
+ "eval() with scope via sort/call was blocked"
+ );
+ }
+
+ // new Function() test -- should throw exception as per spec
+ try {
+ var fcn = new Function(
+ 'onevalexecuted(false, "new Function(String)", "new Function(String) was enabled.");'
+ );
+ fcn();
+ } catch (e) {
+ onevalblocked(
+ false,
+ "new Function(String)",
+ "new Function(String) was blocked."
+ );
+ }
+
+ // ShadowRealm.prototype.evaluate -- should throw exception as per spec.
+ try {
+ var sr = new ShadowRealm();
+ sr.evaluate("var x = 10");
+ onevalexecuted(
+ false,
+ "ShadowRealm.prototype.evaluate(String)",
+ "ShadowRealm.prototype.evaluate(String) was enabled."
+ );
+ } catch (e) {
+ onevalblocked(
+ false,
+ "ShadowRealm.prototype.evaluate(String)",
+ "ShadowRealm.prototype.evaluate(String) was blocked."
+ );
+ }
+
+ // setTimeout(eval, 0, str)
+ {
+ // error is not catchable here, instead, we're going to side-effect
+ // 'worked'.
+ var worked = false;
+
+ setTimeout(eval, 0, "worked = true");
+ setTimeout(
+ function (worked) {
+ if (worked) {
+ onevalexecuted(
+ false,
+ "setTimeout(eval, 0, str)",
+ "setTimeout(eval, 0, string) was enabled."
+ );
+ } else {
+ onevalblocked(
+ false,
+ "setTimeout(eval, 0, str)",
+ "setTimeout(eval, 0, str) was blocked."
+ );
+ }
+ },
+ 0,
+ worked
+ );
+ }
+ },
+ false
+);
diff --git a/dom/security/test/csp/file_evalscript_main_allowed.html b/dom/security/test/csp/file_evalscript_main_allowed.html
new file mode 100644
index 0000000000..274972d9bd
--- /dev/null
+++ b/dom/security/test/csp/file_evalscript_main_allowed.html
@@ -0,0 +1,12 @@
+<html>
+ <head>
+ <title>CSP eval script tests</title>
+ <script type="application/javascript"
+ src="file_evalscript_main_allowed.js"></script>
+ </head>
+ <body>
+
+ Foo.
+
+ </body>
+</html>
diff --git a/dom/security/test/csp/file_evalscript_main_allowed.html^headers^ b/dom/security/test/csp/file_evalscript_main_allowed.html^headers^
new file mode 100644
index 0000000000..0cb5288bec
--- /dev/null
+++ b/dom/security/test/csp/file_evalscript_main_allowed.html^headers^
@@ -0,0 +1,2 @@
+Cache-Control: no-cache
+Content-Security-Policy: default-src 'self' ; script-src 'self' 'unsafe-eval'
diff --git a/dom/security/test/csp/file_evalscript_main_allowed.js b/dom/security/test/csp/file_evalscript_main_allowed.js
new file mode 100644
index 0000000000..69c1cce00e
--- /dev/null
+++ b/dom/security/test/csp/file_evalscript_main_allowed.js
@@ -0,0 +1,193 @@
+// some javascript for the CSP eval() tests
+// all of these evals should succeed, as the document loading this script
+// has script-src 'self' 'unsafe-eval'
+
+function logResult(str, passed) {
+ var elt = document.createElement("div");
+ var color = passed ? "#cfc;" : "#fcc";
+ elt.setAttribute(
+ "style",
+ "background-color:" +
+ color +
+ "; width:100%; border:1px solid black; padding:3px; margin:4px;"
+ );
+ elt.innerHTML = str;
+ document.body.appendChild(elt);
+}
+
+// callback for when stuff is allowed by CSP
+var onevalexecuted = (function (window) {
+ return function (shouldrun, what, data) {
+ window.parent.scriptRan(shouldrun, what, data);
+ logResult(
+ (shouldrun ? "PASS: " : "FAIL: ") + what + " : " + data,
+ shouldrun
+ );
+ };
+})(window);
+
+// callback for when stuff is blocked
+var onevalblocked = (function (window) {
+ return function (shouldrun, what, data) {
+ window.parent.scriptBlocked(shouldrun, what, data);
+ logResult(
+ (shouldrun ? "FAIL: " : "PASS: ") + what + " : " + data,
+ !shouldrun
+ );
+ };
+})(window);
+
+// Defer until document is loaded so that we can write the pretty result boxes
+// out.
+addEventListener(
+ "load",
+ function () {
+ // setTimeout(String) test -- should pass
+ try {
+ setTimeout(
+ 'onevalexecuted(true, "setTimeout(String)", "setTimeout with a string was enabled.");',
+ 10
+ );
+ } catch (e) {
+ onevalblocked(
+ true,
+ "setTimeout(String)",
+ "setTimeout with a string was blocked"
+ );
+ }
+
+ // setTimeout(function) test -- should pass
+ try {
+ setTimeout(function () {
+ onevalexecuted(
+ true,
+ "setTimeout(function)",
+ "setTimeout with a function was enabled."
+ );
+ }, 10);
+ } catch (e) {
+ onevalblocked(
+ true,
+ "setTimeout(function)",
+ "setTimeout with a function was blocked"
+ );
+ }
+
+ // eval() test
+ try {
+ eval('onevalexecuted(true, "eval(String)", "eval() was enabled.");');
+ } catch (e) {
+ onevalblocked(true, "eval(String)", "eval() was blocked");
+ }
+
+ // eval(foo,bar) test
+ try {
+ eval(
+ 'onevalexecuted(true, "eval(String,scope)", "eval() was enabled.");',
+ 1
+ );
+ } catch (e) {
+ onevalblocked(
+ true,
+ "eval(String,object)",
+ "eval() with scope was blocked"
+ );
+ }
+
+ // [foo,bar].sort(eval) test
+ try {
+ [
+ 'onevalexecuted(true, "[String, obj].sort(eval)", "eval() was enabled.");',
+ 1,
+ ].sort(eval);
+ } catch (e) {
+ onevalblocked(
+ true,
+ "[String, obj].sort(eval)",
+ "eval() with scope via sort was blocked"
+ );
+ }
+
+ // [].sort.call([foo,bar], eval) test
+ try {
+ [].sort.call(
+ [
+ 'onevalexecuted(true, "[String, obj].sort(eval)", "eval() was enabled.");',
+ 1,
+ ],
+ eval
+ );
+ } catch (e) {
+ onevalblocked(
+ true,
+ "[].sort.call([String, obj], eval)",
+ "eval() with scope via sort/call was blocked"
+ );
+ }
+
+ // new Function() test
+ try {
+ var fcn = new Function(
+ 'onevalexecuted(true, "new Function(String)", "new Function(String) was enabled.");'
+ );
+ fcn();
+ } catch (e) {
+ onevalblocked(
+ true,
+ "new Function(String)",
+ "new Function(String) was blocked."
+ );
+ }
+
+ // ShadowRealm.prototype.evaluate
+ try {
+ var sr = new ShadowRealm();
+ sr.evaluate("var x = 10");
+ onevalexecuted(
+ true,
+ "ShadowRealm.prototype.evaluate(String)",
+ "ShadowRealm.prototype.evaluate(String) was enabled."
+ );
+ } catch (e) {
+ onevalblocked(
+ true,
+ "ShadowRealm.prototype.evaluate(String)",
+ "ShadowRealm.prototype.evaluate(String) was blocked."
+ );
+ }
+
+ function checkResult() {
+ //alert(bar);
+ if (bar) {
+ onevalexecuted(
+ true,
+ "setTimeout(eval, 0, str)",
+ "setTimeout(eval, 0, string) was enabled."
+ );
+ } else {
+ onevalblocked(
+ true,
+ "setTimeout(eval, 0, str)",
+ "setTimeout(eval, 0, str) was blocked."
+ );
+ }
+ }
+
+ var bar = false;
+
+ function foo() {
+ bar = true;
+ }
+
+ window.foo = foo;
+
+ // setTimeout(eval, 0, str)
+
+ // error is not catchable here
+
+ setTimeout(eval, 0, "window.foo();");
+
+ setTimeout(checkResult.bind(this), 0);
+ },
+ false
+);
diff --git a/dom/security/test/csp/file_fontloader.sjs b/dom/security/test/csp/file_fontloader.sjs
new file mode 100644
index 0000000000..b9b5e602fe
--- /dev/null
+++ b/dom/security/test/csp/file_fontloader.sjs
@@ -0,0 +1,57 @@
+// custom *.sjs for Bug 1195172
+// CSP: 'block-all-mixed-content'
+
+const PRE_HEAD =
+ "<!DOCTYPE HTML>" +
+ '<html><head><meta charset="utf-8">' +
+ "<title>Bug 1195172 - CSP should block font from cache</title>";
+
+const CSP_BLOCK =
+ '<meta http-equiv="Content-Security-Policy" content="font-src \'none\'">';
+
+const CSP_ALLOW =
+ '<meta http-equiv="Content-Security-Policy" content="font-src *">';
+
+const CSS =
+ "<style>" +
+ " @font-face {" +
+ " font-family: myFontTest;" +
+ " src: url(file_fontloader.woff);" +
+ " }" +
+ " div {" +
+ " font-family: myFontTest;" +
+ " }" +
+ "</style>";
+
+const POST_HEAD_AND_BODY =
+ "</head>" +
+ "<body>" +
+ "<div> Just testing the font </div>" +
+ "</body>" +
+ "</html>";
+
+function handleRequest(request, response) {
+ // avoid confusing cache behaviors
+ response.setHeader("Cache-Control", "no-cache", false);
+
+ var queryString = request.queryString;
+
+ if (queryString == "baseline") {
+ response.write(PRE_HEAD + POST_HEAD_AND_BODY);
+ return;
+ }
+ if (queryString == "no-csp") {
+ response.write(PRE_HEAD + CSS + POST_HEAD_AND_BODY);
+ return;
+ }
+ if (queryString == "csp-block") {
+ response.write(PRE_HEAD + CSP_BLOCK + CSS + POST_HEAD_AND_BODY);
+ return;
+ }
+ if (queryString == "csp-allow") {
+ response.write(PRE_HEAD + CSP_ALLOW + CSS + POST_HEAD_AND_BODY);
+ return;
+ }
+ // we should never get here, but just in case return something unexpected
+ response.write("do'h");
+}
diff --git a/dom/security/test/csp/file_fontloader.woff b/dom/security/test/csp/file_fontloader.woff
new file mode 100644
index 0000000000..fbf7390d59
--- /dev/null
+++ b/dom/security/test/csp/file_fontloader.woff
Binary files differ
diff --git a/dom/security/test/csp/file_form-action.html b/dom/security/test/csp/file_form-action.html
new file mode 100644
index 0000000000..cfff156bae
--- /dev/null
+++ b/dom/security/test/csp/file_form-action.html
@@ -0,0 +1,15 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 529697 - Test mapping of form submission to form-action</title>
+</head>
+<body>
+ <form action="submit-form">
+ <input id="submitButton" type="submit" value="Submit form">
+ </form>
+ <script type="text/javascript">
+ var submitButton = document.getElementById('submitButton');
+ submitButton.click();
+ </script>
+</body>
+</html>
diff --git a/dom/security/test/csp/file_form_action_server.sjs b/dom/security/test/csp/file_form_action_server.sjs
new file mode 100644
index 0000000000..0c79736d47
--- /dev/null
+++ b/dom/security/test/csp/file_form_action_server.sjs
@@ -0,0 +1,32 @@
+// Custom *.sjs file specifically for the needs of Bug 1251043
+
+const FRAME = `
+ <!DOCTYPE html>
+ <html>
+ <head>
+ <title>Bug 1251043 - Test form-action blocks URL</title>
+ <meta http-equiv="Content-Security-Policy" content="form-action 'none';">
+ </head>
+ <body>
+ CONTROL-TEXT
+ <form action="file_form_action_server.sjs?formsubmission" method="GET">
+ <input type="submit" id="submitButton" value="submit">
+ </form>
+ </body>
+ </html>`;
+
+function handleRequest(request, response) {
+ // avoid confusing cache behaviors
+ response.setHeader("Cache-Control", "no-cache", false);
+
+ // PART 1: Return a frame including the FORM and the CSP
+ if (request.queryString === "loadframe") {
+ response.write(FRAME);
+ return;
+ }
+
+ // PART 2: We should never get here because the form
+ // should not be submitted. Just in case; return
+ // something unexpected so the test fails!
+ response.write("do'h");
+}
diff --git a/dom/security/test/csp/file_frame_ancestors_ro.html b/dom/security/test/csp/file_frame_ancestors_ro.html
new file mode 100644
index 0000000000..ff5ae9cf9f
--- /dev/null
+++ b/dom/security/test/csp/file_frame_ancestors_ro.html
@@ -0,0 +1 @@
+<html><body>Child Document</body></html>
diff --git a/dom/security/test/csp/file_frame_ancestors_ro.html^headers^ b/dom/security/test/csp/file_frame_ancestors_ro.html^headers^
new file mode 100644
index 0000000000..d018af3a96
--- /dev/null
+++ b/dom/security/test/csp/file_frame_ancestors_ro.html^headers^
@@ -0,0 +1 @@
+Content-Security-Policy-Report-Only: frame-ancestors 'none'; report-uri http://mochi.test:8888/foo.sjs
diff --git a/dom/security/test/csp/file_frame_src.js b/dom/security/test/csp/file_frame_src.js
new file mode 100644
index 0000000000..d30bc0ec62
--- /dev/null
+++ b/dom/security/test/csp/file_frame_src.js
@@ -0,0 +1,20 @@
+let testframe = document.getElementById("testframe");
+testframe.onload = function () {
+ parent.postMessage(
+ {
+ result: "frame-allowed",
+ href: document.location.href,
+ },
+ "*"
+ );
+};
+testframe.onerror = function () {
+ parent.postMessage(
+ {
+ result: "frame-blocked",
+ href: document.location.href,
+ },
+ "*"
+ );
+};
+testframe.src = "file_frame_src_inner.html";
diff --git a/dom/security/test/csp/file_frame_src_child_governs.html b/dom/security/test/csp/file_frame_src_child_governs.html
new file mode 100644
index 0000000000..a51cb75be2
--- /dev/null
+++ b/dom/security/test/csp/file_frame_src_child_governs.html
@@ -0,0 +1,10 @@
+<html>
+<head>
+ <meta charset="utf-8">
+ <meta http-equiv="Content-Security-Policy" content="child-src https://example.com">";
+</head>
+<body>
+<iframe id="testframe"></iframe>
+<script type="text/javascript" src="file_frame_src.js"></script>
+</body>
+</html>
diff --git a/dom/security/test/csp/file_frame_src_frame_governs.html b/dom/security/test/csp/file_frame_src_frame_governs.html
new file mode 100644
index 0000000000..2c5d5857f2
--- /dev/null
+++ b/dom/security/test/csp/file_frame_src_frame_governs.html
@@ -0,0 +1,10 @@
+<html>
+<head>
+ <meta charset="utf-8">
+ <meta http-equiv="Content-Security-Policy" content="frame-src https://example.com; child-src 'none'">";
+</head>
+<body>
+<iframe id="testframe"></iframe>
+<script type="text/javascript" src="file_frame_src.js"></script>
+</body>
+</html>
diff --git a/dom/security/test/csp/file_frame_src_inner.html b/dom/security/test/csp/file_frame_src_inner.html
new file mode 100644
index 0000000000..4a2fc6095a
--- /dev/null
+++ b/dom/security/test/csp/file_frame_src_inner.html
@@ -0,0 +1,5 @@
+<html>
+<body>
+dummy iframe
+</body>
+</html>
diff --git a/dom/security/test/csp/file_frameancestors.sjs b/dom/security/test/csp/file_frameancestors.sjs
new file mode 100644
index 0000000000..25d4b3fe08
--- /dev/null
+++ b/dom/security/test/csp/file_frameancestors.sjs
@@ -0,0 +1,69 @@
+// SJS file for CSP frame ancestor mochitests
+function handleRequest(request, response) {
+ var query = {};
+ request.queryString.split("&").forEach(function (val) {
+ var [name, value] = val.split("=");
+ query[name] = unescape(value);
+ });
+
+ var isPreflight = request.method == "OPTIONS";
+
+ //avoid confusing cache behaviors
+ response.setHeader("Cache-Control", "no-cache", false);
+
+ // grab the desired policy from the query, and then serve a page
+ if (query.csp) {
+ response.setHeader("Content-Security-Policy", unescape(query.csp), false);
+ }
+ if (query.scriptedreport) {
+ // spit back a script that records that the page loaded
+ response.setHeader("Content-Type", "text/javascript", false);
+ if (query.double) {
+ response.write(
+ 'window.parent.parent.parent.postMessage({call: "frameLoaded", testname: "' +
+ query.scriptedreport +
+ '", uri: "window.location.toString()"}, "*");'
+ );
+ } else {
+ response.write(
+ 'window.parent.parent.postMessage({call: "frameLoaded", testname: "' +
+ query.scriptedreport +
+ '", uri: "window.location.toString()"}, "*");'
+ );
+ }
+ } else if (query.internalframe) {
+ // spit back an internal iframe (one that might be blocked)
+ response.setHeader("Content-Type", "text/html", false);
+ response.write("<html><head>");
+ if (query.double) {
+ response.write(
+ '<script src="file_frameancestors.sjs?double=1&scriptedreport=' +
+ query.testid +
+ '"></script>'
+ );
+ } else {
+ response.write(
+ '<script src="file_frameancestors.sjs?scriptedreport=' +
+ query.testid +
+ '"></script>'
+ );
+ }
+ response.write("</head><body>");
+ response.write(unescape(query.internalframe));
+ response.write("</body></html>");
+ } else if (query.externalframe) {
+ // spit back an internal iframe (one that won't be blocked, and probably
+ // has no CSP)
+ response.setHeader("Content-Type", "text/html", false);
+ response.write("<html><head>");
+ response.write("</head><body>");
+ response.write(unescape(query.externalframe));
+ response.write("</body></html>");
+ } else {
+ // default case: error.
+ response.setHeader("Content-Type", "text/html", false);
+ response.write("<html><body>");
+ response.write("ERROR: not sure what to serve.");
+ response.write("</body></html>");
+ }
+}
diff --git a/dom/security/test/csp/file_frameancestors_main.html b/dom/security/test/csp/file_frameancestors_main.html
new file mode 100644
index 0000000000..97f9cb9ac5
--- /dev/null
+++ b/dom/security/test/csp/file_frameancestors_main.html
@@ -0,0 +1,44 @@
+<html>
+ <head>
+ <title>CSP frame ancestors tests</title>
+
+ <!-- this page shouldn't have a CSP, just the sub-pages. -->
+ <script src='file_frameancestors_main.js'></script>
+
+ </head>
+ <body>
+
+<!-- These iframes will get populated by the attached javascript. -->
+<tt> aa_allow: /* innermost frame allows a */</tt><br/>
+<iframe id='aa_allow'></iframe><br/>
+
+<tt> aa_block: /* innermost frame denies a */</tt><br/>
+<iframe id='aa_block'></iframe><br/>
+
+<tt> ab_allow: /* innermost frame allows a */</tt><br/>
+<iframe id='ab_allow'></iframe><br/>
+
+<tt> ab_block: /* innermost frame denies a */</tt><br/>
+<iframe id='ab_block'></iframe><br/>
+
+<tt> aba_allow: /* innermost frame allows b,a */</tt><br/>
+<iframe id='aba_allow'></iframe><br/>
+
+<tt> aba_block: /* innermost frame denies b */</tt><br/>
+<iframe id='aba_block'></iframe><br/>
+
+<tt> aba2_block: /* innermost frame denies a */</tt><br/>
+<iframe id='aba2_block'></iframe><br/>
+
+<tt> abb_allow: /* innermost frame allows b,a */</tt><br/>
+<iframe id='abb_allow'></iframe><br/>
+
+<tt> abb_block: /* innermost frame denies b */</tt><br/>
+<iframe id='abb_block'></iframe><br/>
+
+<tt> abb2_block: /* innermost frame denies a */</tt><br/>
+<iframe id='abb2_block'></iframe><br/>
+
+
+ </body>
+</html>
diff --git a/dom/security/test/csp/file_frameancestors_main.js b/dom/security/test/csp/file_frameancestors_main.js
new file mode 100644
index 0000000000..2c5caf739f
--- /dev/null
+++ b/dom/security/test/csp/file_frameancestors_main.js
@@ -0,0 +1,134 @@
+// Script to populate the test frames in the frame ancestors mochitest.
+//
+function setupFrames() {
+ var $ = function (v) {
+ return document.getElementById(v);
+ };
+ var base = {
+ self: "/tests/dom/security/test/csp/file_frameancestors.sjs",
+ a: "http://mochi.test:8888/tests/dom/security/test/csp/file_frameancestors.sjs",
+ b: "http://example.com/tests/dom/security/test/csp/file_frameancestors.sjs",
+ };
+
+ // In both cases (base.a, base.b) the path starts with /tests/. Let's make sure this
+ // path within the CSP policy is completely ignored when enforcing frame ancestors.
+ // To test this behavior we use /foo/ and /bar/ as dummy values for the path.
+ var host = {
+ a: "http://mochi.test:8888/foo/",
+ b: "http://example.com:80/bar/",
+ };
+
+ var innerframeuri = null;
+ var elt = null;
+
+ elt = $("aa_allow");
+ elt.src =
+ base.a +
+ "?testid=aa_allow&internalframe=aa_a&csp=" +
+ escape(
+ "default-src 'none'; frame-ancestors " + host.a + "; script-src 'self'"
+ );
+
+ elt = $("aa_block");
+ elt.src =
+ base.a +
+ "?testid=aa_block&internalframe=aa_b&csp=" +
+ escape("default-src 'none'; frame-ancestors 'none'; script-src 'self'");
+
+ elt = $("ab_allow");
+ elt.src =
+ base.b +
+ "?testid=ab_allow&internalframe=ab_a&csp=" +
+ escape(
+ "default-src 'none'; frame-ancestors " + host.a + "; script-src 'self'"
+ );
+
+ elt = $("ab_block");
+ elt.src =
+ base.b +
+ "?testid=ab_block&internalframe=ab_b&csp=" +
+ escape("default-src 'none'; frame-ancestors 'none'; script-src 'self'");
+
+ /* .... two-level framing */
+ elt = $("aba_allow");
+ innerframeuri =
+ base.a +
+ "?testid=aba_allow&double=1&internalframe=aba_a&csp=" +
+ escape(
+ "default-src 'none'; frame-ancestors " +
+ host.a +
+ " " +
+ host.b +
+ "; script-src 'self'"
+ );
+ elt.src =
+ base.b +
+ "?externalframe=" +
+ escape('<iframe src="' + innerframeuri + '"></iframe>');
+
+ elt = $("aba_block");
+ innerframeuri =
+ base.a +
+ "?testid=aba_allow&double=1&internalframe=aba_b&csp=" +
+ escape(
+ "default-src 'none'; frame-ancestors " + host.a + "; script-src 'self'"
+ );
+ elt.src =
+ base.b +
+ "?externalframe=" +
+ escape('<iframe src="' + innerframeuri + '"></iframe>');
+
+ elt = $("aba2_block");
+ innerframeuri =
+ base.a +
+ "?testid=aba_allow&double=1&internalframe=aba2_b&csp=" +
+ escape(
+ "default-src 'none'; frame-ancestors " + host.b + "; script-src 'self'"
+ );
+ elt.src =
+ base.b +
+ "?externalframe=" +
+ escape('<iframe src="' + innerframeuri + '"></iframe>');
+
+ elt = $("abb_allow");
+ innerframeuri =
+ base.b +
+ "?testid=abb_allow&double=1&internalframe=abb_a&csp=" +
+ escape(
+ "default-src 'none'; frame-ancestors " +
+ host.a +
+ " " +
+ host.b +
+ "; script-src 'self'"
+ );
+ elt.src =
+ base.b +
+ "?externalframe=" +
+ escape('<iframe src="' + innerframeuri + '"></iframe>');
+
+ elt = $("abb_block");
+ innerframeuri =
+ base.b +
+ "?testid=abb_allow&double=1&internalframe=abb_b&csp=" +
+ escape(
+ "default-src 'none'; frame-ancestors " + host.a + "; script-src 'self'"
+ );
+ elt.src =
+ base.b +
+ "?externalframe=" +
+ escape('<iframe src="' + innerframeuri + '"></iframe>');
+
+ elt = $("abb2_block");
+ innerframeuri =
+ base.b +
+ "?testid=abb_allow&double=1&internalframe=abb2_b&csp=" +
+ escape(
+ "default-src 'none'; frame-ancestors " + host.b + "; script-src 'self'"
+ );
+ elt.src =
+ base.b +
+ "?externalframe=" +
+ escape('<iframe src="' + innerframeuri + '"></iframe>');
+}
+
+window.addEventListener("load", setupFrames);
diff --git a/dom/security/test/csp/file_frameancestors_userpass.html b/dom/security/test/csp/file_frameancestors_userpass.html
new file mode 100644
index 0000000000..c840995b6c
--- /dev/null
+++ b/dom/security/test/csp/file_frameancestors_userpass.html
@@ -0,0 +1,10 @@
+<html>
+<head>
+ <title>CSP frame ancestors tests</title>
+</head>
+<body>
+ <tt>Nested Frames</tt><br/>
+ <iframe src='http://sampleuser:samplepass@mochi.test:8888/tests/dom/security/test/csp/file_frameancestors_userpass_frame_a.html'></iframe><br/>
+ <iframe src='http://sampleuser:samplepass@example.com/tests/dom/security/test/csp/file_frameancestors_userpass_frame_b.html'></iframe><br/>
+</body>
+</html>
diff --git a/dom/security/test/csp/file_frameancestors_userpass_frame_a.html b/dom/security/test/csp/file_frameancestors_userpass_frame_a.html
new file mode 100644
index 0000000000..d5a5bb604b
--- /dev/null
+++ b/dom/security/test/csp/file_frameancestors_userpass_frame_a.html
@@ -0,0 +1,12 @@
+<html>
+<head>
+ <title>Nested frame</title>
+ <script>
+ parent.parent.postMessage({call: "frameLoaded", testname: "frame_a", uri: window.location.toString()}, "*");
+ </script>
+</head>
+<body>
+ <tt>IFRAME A</tt><br/>
+ <iframe src='http://sampleuser:samplepass@mochi.test:8888/tests/dom/security/test/csp/file_frameancestors_userpass_frame_c.html'></iframe><br/>
+</body>
+</html>
diff --git a/dom/security/test/csp/file_frameancestors_userpass_frame_b.html b/dom/security/test/csp/file_frameancestors_userpass_frame_b.html
new file mode 100644
index 0000000000..87055ef149
--- /dev/null
+++ b/dom/security/test/csp/file_frameancestors_userpass_frame_b.html
@@ -0,0 +1,12 @@
+<html>
+<head>
+ <title>Nested frame</title>
+ <script>
+ parent.parent.postMessage({call: "frameLoaded", testname: "frame_b", uri: window.location.toString()}, "*");
+ </script>
+</head>
+<body>
+ <tt>IFRAME B</tt><br/>
+ <iframe src='http://sampleuser:samplepass@example.com/tests/dom/security/test/csp/file_frameancestors_userpass_frame_d.html'></iframe><br/>
+</body>
+</html>
diff --git a/dom/security/test/csp/file_frameancestors_userpass_frame_c.html b/dom/security/test/csp/file_frameancestors_userpass_frame_c.html
new file mode 100644
index 0000000000..159e6c4633
--- /dev/null
+++ b/dom/security/test/csp/file_frameancestors_userpass_frame_c.html
@@ -0,0 +1,8 @@
+<html>
+<head>
+ <title>Nested frame</title>
+</head>
+<body>
+ Nested frame C content
+</body>
+</html>
diff --git a/dom/security/test/csp/file_frameancestors_userpass_frame_c.html^headers^ b/dom/security/test/csp/file_frameancestors_userpass_frame_c.html^headers^
new file mode 100644
index 0000000000..9e7dfefcda
--- /dev/null
+++ b/dom/security/test/csp/file_frameancestors_userpass_frame_c.html^headers^
@@ -0,0 +1 @@
+Content-Security-Policy: default-src 'none'; frame-ancestors http://mochi.test:8888/ ; script-src 'self';
diff --git a/dom/security/test/csp/file_frameancestors_userpass_frame_d.html b/dom/security/test/csp/file_frameancestors_userpass_frame_d.html
new file mode 100644
index 0000000000..0cb49c4836
--- /dev/null
+++ b/dom/security/test/csp/file_frameancestors_userpass_frame_d.html
@@ -0,0 +1,8 @@
+<html>
+<head>
+ <title>Nested frame</title>
+</head>
+<body>
+ Nested frame D content
+</body>
+</html>
diff --git a/dom/security/test/csp/file_frameancestors_userpass_frame_d.html^headers^ b/dom/security/test/csp/file_frameancestors_userpass_frame_d.html^headers^
new file mode 100644
index 0000000000..019fcea026
--- /dev/null
+++ b/dom/security/test/csp/file_frameancestors_userpass_frame_d.html^headers^
@@ -0,0 +1 @@
+Content-Security-Policy: default-src 'none'; frame-ancestors http://sampleuser:samplepass@example.com/ ; script-src 'self';
diff --git a/dom/security/test/csp/file_hash_source.html b/dom/security/test/csp/file_hash_source.html
new file mode 100644
index 0000000000..47eba6cf3e
--- /dev/null
+++ b/dom/security/test/csp/file_hash_source.html
@@ -0,0 +1,65 @@
+<!doctype html>
+<html>
+ <body>
+ <!-- inline scripts -->
+ <p id="inline-script-valid-hash">blocked</p>
+ <p id="inline-script-invalid-hash">blocked</p>
+ <p id="inline-script-invalid-hash-valid-nonce">blocked</p>
+ <p id="inline-script-valid-hash-invalid-nonce">blocked</p>
+ <p id="inline-script-invalid-hash-invalid-nonce">blocked</p>
+ <p id="inline-script-valid-sha512-hash">blocked</p>
+ <p id="inline-script-valid-sha384-hash">blocked</p>
+ <p id="inline-script-valid-sha1-hash">blocked</p>
+ <p id="inline-script-valid-md5-hash">blocked</p>
+
+ <!-- 'sha256-siVR8vAcqP06h2ppeNwqgjr0yZ6yned4X2VF84j4GmI=' (in policy) -->
+ <script>document.getElementById("inline-script-valid-hash").innerHTML = "allowed";</script>
+ <!-- 'sha256-cYPTF2pm0QeyDtbmJ3+xi00o2Rxrw7vphBoHgOg9EnQ=' (not in policy) -->
+ <script>document.getElementById("inline-script-invalid-hash").innerHTML = "allowed";</script>
+ <!-- 'sha256-SKtBKyfeMjBpOujES0etR9t/cklbouJu/3T4PXnjbIo=' (not in policy) -->
+ <script nonce="jPRxvuRHbiQnCWVuoCMAvQ==">document.getElementById("inline-script-invalid-hash-valid-nonce").innerHTML = "allowed";</script>
+ <!-- 'sha256-z7rzCkbOJqi08lga3CVQ3b+3948ZbJWaSxsBs8zPliE=' -->
+ <script nonce="foobar">document.getElementById("inline-script-valid-hash-invalid-nonce").innerHTML = "allowed";</script>
+ <!-- 'sha256-E5TX2PmYZ4YQOK/F3XR1wFcvFjbO7QHMmxHTT/18LbE=' (not in policy) -->
+ <script nonce="foobar">document.getElementById("inline-script-invalid-hash-invalid-nonce").innerHTML = "allowed";</script>
+ <!-- 'sha512-tMLuv22jJ5RHkvLNlv0otvA2fgw6PF16HKu6wy0ZDQ3M7UKzoygs1uxIMSfjMttgWrB5WRvIr35zrTZppMYBVw==' (in policy) -->
+ <script>document.getElementById("inline-script-valid-sha512-hash").innerHTML = "allowed";</script>
+ <!-- 'sha384-XjAD+FxZfipkxna4id1JrR2QP6OYUZfAxpn9+yHOmT1VSLVa9SQR/dz7CEb7jw7w' (in policy) -->
+ <script>document.getElementById("inline-script-valid-sha384-hash").innerHTML = "allowed";</script>
+ <!-- 'sha1-LHErkMxKGcSpa/znpzmKYkKnI30=' (in policy) -->
+ <script>document.getElementById("inline-script-valid-sha1-hash").innerHTML = "allowed";</script>
+ <!-- 'md5-/m4wX3YU+IHs158KwKOBWg==' (in policy) -->
+ <script>document.getElementById("inline-script-valid-md5-hash").innerHTML = "allowed";</script>
+
+ <!-- inline styles -->
+ <p id="inline-style-valid-hash"></p>
+ <p id="inline-style-invalid-hash"></p>
+ <p id="inline-style-invalid-hash-valid-nonce"></p>
+ <p id="inline-style-valid-hash-invalid-nonce"></p>
+ <p id="inline-style-invalid-hash-invalid-nonce"></p>
+ <p id="inline-style-valid-sha512-hash"></p>
+ <p id="inline-style-valid-sha384-hash"></p>
+ <p id="inline-style-valid-sha1-hash"></p>
+ <p id="inline-style-valid-md5-hash"></p>
+
+ <!-- 'sha256-UpNH6x+Ux99QTW1fJikQsVbBERJruIC98et0YDVKKHQ=' (in policy) -->
+ <style>p#inline-style-valid-hash { color: green; }</style>
+ <!-- 'sha256-+TYxTx+bsfTDdivWLZUwScEYyxuv6lknMbNjrgGBRZo=' (not in policy) -->
+ <style>p#inline-style-invalid-hash { color: red; }</style>
+ <!-- 'sha256-U+9UPC/CFzz3QuOrl5q3KCVNngOYWuIkE2jK6Ir0Mbs=' (not in policy) -->
+ <style nonce="ftL2UbGHlSEaZTLWMwtA5Q==">p#inline-style-invalid-hash-valid-nonce { color: green; }</style>
+ <!-- 'sha256-0IPbWW5IDJ/juvETq60oTnhC+XzOqdYp5/UBsBKCaOY=' (in policy) -->
+ <style nonce="foobar">p#inline-style-valid-hash-invalid-nonce { color: green; }</style>
+ <!-- 'sha256-KaHZgPd4nC4S8BVLT/9WjzdPDtunGWojR83C2whbd50=' (not in policy) -->
+ <style nonce="foobar">p#inline-style-invalid-hash-invalid-nonce { color: red; }</style>
+ <!-- 'sha512-EpcDbSuvFv0HIyKtU5tQMN7UtBMeEbljz1dWPfy7PNCa1RYdHKwdJWT1tie41evq/ZUL1rzadSVdEzq3jl6Twg==' (in policy) -->
+ <style>p#inline-style-valid-sha512-hash { color: green; }</style>
+ <!-- 'sha384-c5W8ON4WyeA2zEOGdrOGhRmRYI8+2UzUUmhGQFjUFP6yiPZx9FGEV3UOiQ+tIshF' (in policy) -->
+ <style>p#inline-style-valid-sha384-hash { color: green; }</style>
+ <!-- 'sha1-T/+b4sxCIiJxDr6XS9dAEyHKt2M=' (in policy) -->
+ <style>p#inline-style-valid-sha1-hash { color: red; }</style>
+ <!-- 'md5-oNrgrtzOZduwDYYi1yo12g==' (in policy) -->
+ <style>p#inline-style-valid-md5-hash { color: red; }</style>
+
+ </body>
+</html>
diff --git a/dom/security/test/csp/file_hash_source.html^headers^ b/dom/security/test/csp/file_hash_source.html^headers^
new file mode 100644
index 0000000000..785d63391e
--- /dev/null
+++ b/dom/security/test/csp/file_hash_source.html^headers^
@@ -0,0 +1,2 @@
+Content-Security-Policy: script-src 'sha256-siVR8vAcqP06h2ppeNwqgjr0yZ6yned4X2VF84j4GmI=' 'nonce-jPRxvuRHbiQnCWVuoCMAvQ==' 'sha256-z7rzCkbOJqi08lga3CVQ3b+3948ZbJWaSxsBs8zPliE=' 'sha512-tMLuv22jJ5RHkvLNlv0otvA2fgw6PF16HKu6wy0ZDQ3M7UKzoygs1uxIMSfjMttgWrB5WRvIr35zrTZppMYBVw==' 'sha384-XjAD+FxZfipkxna4id1JrR2QP6OYUZfAxpn9+yHOmT1VSLVa9SQR/dz7CEb7jw7w' 'sha1-LHErkMxKGcSpa/znpzmKYkKnI30=' 'md5-/m4wX3YU+IHs158KwKOBWg=='; style-src 'sha256-UpNH6x+Ux99QTW1fJikQsVbBERJruIC98et0YDVKKHQ=' 'nonce-ftL2UbGHlSEaZTLWMwtA5Q==' 'sha256-0IPbWW5IDJ/juvETq60oTnhC+XzOqdYp5/UBsBKCaOY=' 'sha512-EpcDbSuvFv0HIyKtU5tQMN7UtBMeEbljz1dWPfy7PNCa1RYdHKwdJWT1tie41evq/ZUL1rzadSVdEzq3jl6Twg==' 'sha384-c5W8ON4WyeA2zEOGdrOGhRmRYI8+2UzUUmhGQFjUFP6yiPZx9FGEV3UOiQ+tIshF' 'sha1-T/+b4sxCIiJxDr6XS9dAEyHKt2M=' 'md5-oNrgrtzOZduwDYYi1yo12g==';
+Cache-Control: no-cache
diff --git a/dom/security/test/csp/file_iframe_parent_location_js.html b/dom/security/test/csp/file_iframe_parent_location_js.html
new file mode 100644
index 0000000000..0d980f9925
--- /dev/null
+++ b/dom/security/test/csp/file_iframe_parent_location_js.html
@@ -0,0 +1,10 @@
+<html>
+<head>
+ <title>Test setting parent location to javascript:</title>
+</head>
+<body>
+<script>
+ parent.window.location ="javascript:location.href";
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/file_iframe_sandbox_document_write.html b/dom/security/test/csp/file_iframe_sandbox_document_write.html
new file mode 100644
index 0000000000..a3a0952941
--- /dev/null
+++ b/dom/security/test/csp/file_iframe_sandbox_document_write.html
@@ -0,0 +1,21 @@
+<!DOCTYPE HTML>
+<html>
+<head> <meta charset="utf-8"> </head>
+<script type="text/javascript">
+ function ok(result, desc) {
+ window.parent.postMessage({ok: result, desc}, "*");
+ }
+ function doStuff() {
+ var beforePrincipal = SpecialPowers.wrap(document).nodePrincipal;
+ document.open();
+ document.write("rewritten sandboxed document");
+ document.close();
+ var afterPrincipal = SpecialPowers.wrap(document).nodePrincipal;
+ ok(beforePrincipal.equals(afterPrincipal),
+ "document.write() does not change underlying principal");
+ }
+</script>
+<body onLoad='doStuff();'>
+ sandboxed with allow-scripts
+</body>
+</html>
diff --git a/dom/security/test/csp/file_iframe_sandbox_srcdoc.html b/dom/security/test/csp/file_iframe_sandbox_srcdoc.html
new file mode 100644
index 0000000000..bc700ed68f
--- /dev/null
+++ b/dom/security/test/csp/file_iframe_sandbox_srcdoc.html
@@ -0,0 +1,11 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Bug 1073952 - CSP should restrict scripts in srcdoc iframe even if sandboxed</title>
+</head>
+<body>
+<iframe srcdoc="<img src=x onerror='parent.postMessage({result: `unexpected-csp-violation`}, `*`);'>"
+ sandbox="allow-scripts"></iframe>
+</body>
+</html>
diff --git a/dom/security/test/csp/file_iframe_sandbox_srcdoc.html^headers^ b/dom/security/test/csp/file_iframe_sandbox_srcdoc.html^headers^
new file mode 100644
index 0000000000..cf869e07d4
--- /dev/null
+++ b/dom/security/test/csp/file_iframe_sandbox_srcdoc.html^headers^
@@ -0,0 +1 @@
+content-security-policy: default-src *;
diff --git a/dom/security/test/csp/file_iframe_srcdoc.sjs b/dom/security/test/csp/file_iframe_srcdoc.sjs
new file mode 100644
index 0000000000..9f8774e4cc
--- /dev/null
+++ b/dom/security/test/csp/file_iframe_srcdoc.sjs
@@ -0,0 +1,87 @@
+// Custom *.sjs file specifically for the needs of
+// https://bugzilla.mozilla.org/show_bug.cgi?id=1073952
+
+"use strict";
+Components.utils.importGlobalProperties(["URLSearchParams"]);
+
+const SCRIPT = `
+ <script>
+ parent.parent.postMessage({result: &quot;allowed&quot;}, &quot;*&quot;);
+ </script>`;
+
+const SIMPLE_IFRAME_SRCDOC =
+ `
+ <!DOCTYPE html>
+ <html>
+ <head><meta charset="utf-8"></head>
+ <body>
+ <iframe sandbox="allow-scripts" srcdoc="` +
+ SCRIPT +
+ `"></iframe>
+ </body>
+ </html>`;
+
+const INNER_SRCDOC_IFRAME = `
+ <iframe sandbox='allow-scripts' srcdoc='<script>
+ parent.parent.parent.postMessage({result: &quot;allowed&quot;}, &quot;*&quot;);
+ </script>'>
+ </iframe>`;
+
+const NESTED_IFRAME_SRCDOC =
+ `
+ <!DOCTYPE html>
+ <html>
+ <head><meta charset="utf-8"></head>
+ <body>
+ <iframe sandbox="allow-scripts" srcdoc="` +
+ INNER_SRCDOC_IFRAME +
+ `"></iframe>
+ </body>
+ </html>`;
+
+const INNER_DATAURI_IFRAME = `
+ <iframe sandbox='allow-scripts' src='data:text/html,<script>
+ parent.parent.parent.postMessage({result: &quot;allowed&quot;}, &quot;*&quot;);
+ </script>'>
+ </iframe>`;
+
+const NESTED_IFRAME_SRCDOC_DATAURI =
+ `
+ <!DOCTYPE html>
+ <html>
+ <head><meta charset="utf-8"></head>
+ <body>
+ <iframe sandbox="allow-scripts" srcdoc="` +
+ INNER_DATAURI_IFRAME +
+ `"></iframe>
+ </body>
+ </html>`;
+
+function handleRequest(request, response) {
+ const query = new URLSearchParams(request.queryString);
+
+ response.setHeader("Cache-Control", "no-cache", false);
+ if (typeof query.get("csp") === "string") {
+ response.setHeader("Content-Security-Policy", query.get("csp"), false);
+ }
+ response.setHeader("Content-Type", "text/html", false);
+
+ if (query.get("action") === "simple_iframe_srcdoc") {
+ response.write(SIMPLE_IFRAME_SRCDOC);
+ return;
+ }
+
+ if (query.get("action") === "nested_iframe_srcdoc") {
+ response.write(NESTED_IFRAME_SRCDOC);
+ return;
+ }
+
+ if (query.get("action") === "nested_iframe_srcdoc_datauri") {
+ response.write(NESTED_IFRAME_SRCDOC_DATAURI);
+ return;
+ }
+
+ // we should never get here, but just in case
+ // return something unexpected
+ response.write("do'h");
+}
diff --git a/dom/security/test/csp/file_ignore_unsafe_inline.html b/dom/security/test/csp/file_ignore_unsafe_inline.html
new file mode 100644
index 0000000000..773184201c
--- /dev/null
+++ b/dom/security/test/csp/file_ignore_unsafe_inline.html
@@ -0,0 +1,26 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<title>Bug 1004703 - ignore 'unsafe-inline' if nonce- or hash-source specified</title>
+</head>
+<body>
+<div id="testdiv">a</div>
+
+<!-- first script allowlisted by 'unsafe-inline' -->
+<script type="application/javascript">
+document.getElementById('testdiv').innerHTML += 'b';
+</script>
+
+<!-- second script allowlisted by hash -->
+<!-- sha256-uJXAPKP5NZxnVMZMUkDofh6a9P3UMRc1CRTevVPS/rI= -->
+<script type="application/javascript">
+document.getElementById('testdiv').innerHTML += 'c';
+</script>
+
+<!-- thrid script allowlisted by nonce -->
+<script type="application/javascript" nonce="FooNonce">
+document.getElementById('testdiv').innerHTML += 'd';
+</script>
+
+</body>
+</html>
diff --git a/dom/security/test/csp/file_ignore_unsafe_inline_multiple_policies_server.sjs b/dom/security/test/csp/file_ignore_unsafe_inline_multiple_policies_server.sjs
new file mode 100644
index 0000000000..c27aee0f42
--- /dev/null
+++ b/dom/security/test/csp/file_ignore_unsafe_inline_multiple_policies_server.sjs
@@ -0,0 +1,56 @@
+// custom *.sjs file specifically for the needs of:
+// * Bug 1004703 - ignore 'unsafe-inline' if nonce- or hash-source specified
+// * Bug 1198422: should not block inline script if default-src is not specified
+
+const { NetUtil } = ChromeUtils.import("resource://gre/modules/NetUtil.jsm");
+
+function loadHTMLFromFile(path) {
+ // Load the HTML to return in the response from file.
+ // Since it's relative to the cwd of the test runner, we start there and
+ // append to get to the actual path of the file.
+ var testHTMLFile = Components.classes["@mozilla.org/file/directory_service;1"]
+ .getService(Components.interfaces.nsIProperties)
+ .get("CurWorkD", Components.interfaces.nsIFile);
+ var dirs = path.split("/");
+ for (var i = 0; i < dirs.length; i++) {
+ testHTMLFile.append(dirs[i]);
+ }
+ var testHTMLFileStream = Components.classes[
+ "@mozilla.org/network/file-input-stream;1"
+ ].createInstance(Components.interfaces.nsIFileInputStream);
+ testHTMLFileStream.init(testHTMLFile, -1, 0, 0);
+ var testHTML = NetUtil.readInputStreamToString(
+ testHTMLFileStream,
+ testHTMLFileStream.available()
+ );
+ return testHTML;
+}
+
+function handleRequest(request, response) {
+ var query = {};
+ request.queryString.split("&").forEach(function (val) {
+ var [name, value] = val.split("=");
+ query[name] = unescape(value);
+ });
+
+ var csp1 = query.csp1 ? unescape(query.csp1) : "";
+ var csp2 = query.csp2 ? unescape(query.csp2) : "";
+ var file = unescape(query.file);
+
+ // avoid confusing cache behaviors
+ response.setHeader("Cache-Control", "no-cache", false);
+
+ // deliver the CSP encoded in the URI
+ // please note that comma separation of two policies
+ // acts like sending *two* separate policies
+ var csp = csp1;
+ if (csp2 !== "") {
+ csp += ", " + csp2;
+ }
+ response.setHeader("Content-Security-Policy", csp, false);
+
+ // Send HTML to test allowed/blocked behaviors
+ response.setHeader("Content-Type", "text/html", false);
+
+ response.write(loadHTMLFromFile(file));
+}
diff --git a/dom/security/test/csp/file_ignore_xfo.html b/dom/security/test/csp/file_ignore_xfo.html
new file mode 100644
index 0000000000..6746a3adba
--- /dev/null
+++ b/dom/security/test/csp/file_ignore_xfo.html
@@ -0,0 +1,10 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Bug 1024557: Ignore x-frame-options if CSP with frame-ancestors exists</title>
+</head>
+<body>
+<div id="cspmessage">Ignoring XFO because of CSP</div>
+</body>
+</html>
diff --git a/dom/security/test/csp/file_ignore_xfo.html^headers^ b/dom/security/test/csp/file_ignore_xfo.html^headers^
new file mode 100644
index 0000000000..e93f9e3ecb
--- /dev/null
+++ b/dom/security/test/csp/file_ignore_xfo.html^headers^
@@ -0,0 +1,3 @@
+Content-Security-Policy: frame-ancestors http://mochi.test:8888
+X-Frame-Options: deny
+Cache-Control: no-cache
diff --git a/dom/security/test/csp/file_image_document_pixel.png b/dom/security/test/csp/file_image_document_pixel.png
new file mode 100644
index 0000000000..52c591798e
--- /dev/null
+++ b/dom/security/test/csp/file_image_document_pixel.png
Binary files differ
diff --git a/dom/security/test/csp/file_image_document_pixel.png^headers^ b/dom/security/test/csp/file_image_document_pixel.png^headers^
new file mode 100644
index 0000000000..7c727854d0
--- /dev/null
+++ b/dom/security/test/csp/file_image_document_pixel.png^headers^
@@ -0,0 +1,2 @@
+Content-Security-Policy: default-src https://bug1627235.test.com
+Cache-Control: no-cache
diff --git a/dom/security/test/csp/file_image_nonce.html b/dom/security/test/csp/file_image_nonce.html
new file mode 100644
index 0000000000..5d57bb8372
--- /dev/null
+++ b/dom/security/test/csp/file_image_nonce.html
@@ -0,0 +1,39 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <meta charset='utf-8'>
+ <title>Bug 1355801: Nonce should not apply to images</title>
+ </head>
+<body>
+
+<img id='matchingNonce' src='http://mochi.test:8888/tests/image/test/mochitest/blue.png?a' nonce='abc'></img>
+<img id='nonMatchingNonce' src='http://mochi.test:8888/tests/image/test/mochitest/blue.png?b' nonce='bca'></img>
+<img id='noNonce' src='http://mochi.test:8888/tests/image/test/mochitest/blue.png?c'></img>
+
+<script type='application/javascript'>
+ var matchingNonce = document.getElementById('matchingNonce');
+ matchingNonce.onload = function(e) {
+ window.parent.postMessage({result: 'img-with-matching-nonce-loaded'}, '*');
+ };
+ matchingNonce.onerror = function(e) {
+ window.parent.postMessage({result: 'img-with-matching-nonce-blocked'}, '*');
+ }
+
+ var nonMatchingNonce = document.getElementById('nonMatchingNonce');
+ nonMatchingNonce.onload = function(e) {
+ window.parent.postMessage({result: 'img-with_non-matching-nonce-loaded'}, '*');
+ };
+ nonMatchingNonce.onerror = function(e) {
+ window.parent.postMessage({result: 'img-with_non-matching-nonce-blocked'}, '*');
+ }
+
+ var noNonce = document.getElementById('noNonce');
+ noNonce.onload = function(e) {
+ window.parent.postMessage({result: 'img-without-nonce-loaded'}, '*');
+ };
+ noNonce.onerror = function(e) {
+ window.parent.postMessage({result: 'img-without-nonce-blocked'}, '*');
+ }
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/file_image_nonce.html^headers^ b/dom/security/test/csp/file_image_nonce.html^headers^
new file mode 100644
index 0000000000..0d63558c46
--- /dev/null
+++ b/dom/security/test/csp/file_image_nonce.html^headers^
@@ -0,0 +1,2 @@
+Content-Security-Policy: img-src 'nonce-abc';
+Cache-Control: no-cache
diff --git a/dom/security/test/csp/file_independent_iframe_csp.html b/dom/security/test/csp/file_independent_iframe_csp.html
new file mode 100644
index 0000000000..0581f5ea85
--- /dev/null
+++ b/dom/security/test/csp/file_independent_iframe_csp.html
@@ -0,0 +1,43 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 1419222 - iFrame CSP should not affect parent document CSP</title>
+ <meta charset="utf-8">
+ <meta http-equiv="Content-Security-Policy" content="connect-src *; style-src * 'unsafe-inline'; "/>
+</head>
+<body>
+ <script>
+ var getCspObj = function(doc) {
+ var contentDoc = SpecialPowers.wrap(doc);
+ var cspJSON = contentDoc.cspJSON;
+ var cspOBJ = JSON.parse(cspJSON);
+ return cspOBJ;
+ }
+
+ // Add an iFrame, add an additional CSP directive to that iFrame, and
+ // return the CSP object of that iFrame.
+ var addIFrame = function() {
+ var frame = document.createElement("iframe");
+ frame.id = "nestedframe";
+ document.body.appendChild(frame);
+ var metaTag = document.createElement("meta");
+ metaTag.setAttribute("http-equiv", "Content-Security-Policy");
+ metaTag.setAttribute("content", "img-src 'self' data:;");
+ frame.contentDocument.head.appendChild(metaTag);
+ return getCspObj(frame.contentDocument);
+ }
+
+ // Get the CSP objects of the parent document before and after adding the
+ // iFrame, as well as of the iFram itself.
+ var parentBeginCspObj = getCspObj(document);
+ var iFrameCspObj = addIFrame();
+ var parentEndCspObj = getCspObj(document);
+
+ // Post a message containing the three CSP objects to the test context.
+ window.parent.postMessage(
+ {result: [parentBeginCspObj, iFrameCspObj, parentEndCspObj]},
+ "*"
+ );
+ </script>
+</body>
+</html>
diff --git a/dom/security/test/csp/file_inlinescript.html b/dom/security/test/csp/file_inlinescript.html
new file mode 100644
index 0000000000..55a9b9b180
--- /dev/null
+++ b/dom/security/test/csp/file_inlinescript.html
@@ -0,0 +1,15 @@
+<html>
+<head>
+ <title>CSP inline script tests</title>
+</head>
+<body onload="window.parent.postMessage('body-onload-fired', '*')">
+ <script type="text/javascript">
+ window.parent.postMessage("text-node-fired", "*");
+ </script>
+
+ <iframe src='javascript:window.parent.parent.postMessage("javascript-uri-fired", "*")'></iframe>
+
+ <a id='anchortoclick' href='javascript:window.parent.postMessage("javascript-uri-anchor-fired", "*")'>testlink</a>
+
+</body>
+</html>
diff --git a/dom/security/test/csp/file_inlinestyle_main.html b/dom/security/test/csp/file_inlinestyle_main.html
new file mode 100644
index 0000000000..a0d2969883
--- /dev/null
+++ b/dom/security/test/csp/file_inlinestyle_main.html
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<html>
+ <head>
+ <title>CSP inline script tests</title>
+ <!-- content= "div#linkstylediv { color: #0f0; }" -->
+ <link rel="stylesheet" type="text/css"
+ href='file_CSP.sjs?type=text/css&content=div%23linkstylediv%20%7B%20color%3A%20%230f0%3B%20%7D' />
+ <!-- content= "div#modifycsstextdiv { color: #0f0; }" -->
+ <link rel="stylesheet" type="text/css"
+ href='file_CSP.sjs?type=text/css&content=div%23modifycsstextdiv%20%7B%20color%3A%20%23f00%3B%20%7D' />
+ <script>
+ function cssTest() {
+ var elem = document.getElementById('csstextstylediv');
+ elem.style.cssText = "color: #00FF00;";
+ getComputedStyle(elem, null).color;
+
+ document.styleSheets[1].cssRules[0].style.cssText = "color: #00FF00;";
+ elem = document.getElementById('modifycsstextdiv');
+ getComputedStyle(elem, null).color;
+ }
+ </script>
+ </head>
+ <body onload='cssTest()'>
+
+ <style type="text/css">
+ div#inlinestylediv {
+ color: #FF0000;
+ }
+ </style>
+
+ <div id='linkstylediv'>Link tag (external) stylesheet test (should be green)</div>
+ <div id='inlinestylediv'>Inline stylesheet test (should be black)</div>
+ <div id='attrstylediv' style="color: #FF0000;">Attribute stylesheet test (should be black)</div>
+ <div id='csstextstylediv'>cssText test (should be black)</div>
+ <div id='modifycsstextdiv'> modify rule from style sheet via cssText(should be green) </div>
+
+ <!-- tests for SMIL stuff - animations -->
+ <svg xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ width="100%"
+ height="100px">
+
+ <!-- Animates XML attribute, which is mapped into style. -->
+ <text id="xmlTest" x="0" y="15">
+ This shouldn't be red since the animation should be blocked by CSP.
+
+ <animate attributeName="fill" attributeType="XML"
+ values="red;orange;red" dur="2s"
+ repeatCount="indefinite" />
+ </text>
+
+ <!-- Animates override value for CSS property. -->
+ <text id="cssOverrideTest" x="0" y="35">
+ This shouldn't be red since the animation should be blocked by CSP.
+
+ <animate attributeName="fill" attributeType="CSS"
+ values="red;orange;red" dur="2s"
+ repeatCount="indefinite" />
+ </text>
+
+ <!-- Animates override value for CSS property targeted via ID. -->
+ <text id="cssOverrideTestById" x="0" y="55">
+ This shouldn't be red since the animation should be blocked by CSP.
+ </text>
+ <animate xlink:href="#cssOverrideTestById"
+ attributeName="fill"
+ values="red;orange;red"
+ dur="2s" repeatCount="indefinite" />
+
+ <!-- Sets value for CSS property targeted via ID. -->
+ <text id="cssSetTestById" x="0" y="75">
+ This shouldn't be red since the &lt;set&gt; should be blocked by CSP.
+ </text>
+ <set xlink:href="#cssSetTestById"
+ attributeName="fill"
+ to="red" />
+ </svg>
+ </body>
+</html>
diff --git a/dom/security/test/csp/file_inlinestyle_main.html^headers^ b/dom/security/test/csp/file_inlinestyle_main.html^headers^
new file mode 100644
index 0000000000..7b6a251679
--- /dev/null
+++ b/dom/security/test/csp/file_inlinestyle_main.html^headers^
@@ -0,0 +1,2 @@
+Content-Security-Policy: default-src 'self' ; script-src 'self' 'unsafe-inline'
+Cache-Control: no-cache
diff --git a/dom/security/test/csp/file_inlinestyle_main_allowed.html b/dom/security/test/csp/file_inlinestyle_main_allowed.html
new file mode 100644
index 0000000000..9b533ef074
--- /dev/null
+++ b/dom/security/test/csp/file_inlinestyle_main_allowed.html
@@ -0,0 +1,84 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<html>
+ <head>
+ <title>CSP inline script tests</title>
+ <!-- content= "div#linkstylediv { color: #0f0; }" -->
+ <link rel="stylesheet" type="text/css"
+ href='file_CSP.sjs?type=text/css&content=div%23linkstylediv%20%7B%20color%3A%20%230f0%3B%20%7D' />
+ <!-- content= "div#modifycsstextdiv { color: #f00; }" -->
+ <link rel="stylesheet" type="text/css"
+ href='file_CSP.sjs?type=text/css&content=div%23modifycsstextdiv%20%7B%20color%3A%20%23f00%3B%20%7D' />
+ <script>
+ function cssTest() {
+ // CSSStyleDeclaration.cssText
+ var elem = document.getElementById('csstextstylediv');
+ elem.style.cssText = "color: #00FF00;";
+
+ // If I call getComputedStyle as below, this test passes as the parent page
+ // correctly detects that the text is colored green - if I remove this, getComputedStyle
+ // thinks the text is black when called by the parent page.
+ getComputedStyle(elem, null).color;
+
+ document.styleSheets[1].cssRules[0].style.cssText = "color: #00FF00;";
+ elem = document.getElementById('modifycsstextdiv');
+ getComputedStyle(elem, null).color;
+ }
+ </script>
+ </head>
+ <body onload='cssTest()'>
+
+ <style type="text/css">
+ div#inlinestylediv {
+ color: #00FF00;
+ }
+ </style>
+
+ <div id='linkstylediv'>Link tag (external) stylesheet test (should be green)</div>
+ <div id='inlinestylediv'>Inline stylesheet test (should be green)</div>
+ <div id='attrstylediv' style="color: #00FF00;">Attribute stylesheet test (should be green)</div>
+ <div id='csstextstylediv'>style.cssText test (should be green)</div>
+ <div id='modifycsstextdiv'> modify rule from style sheet via cssText(should be green) </div>
+
+ <!-- tests for SMIL stuff - animations -->
+ <svg xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ width="100%"
+ height="100px">
+
+ <!-- Animates XML attribute, which is mapped into style. -->
+ <text id="xmlTest" x="0" y="15">
+ This should be green since the animation should be allowed by CSP.
+
+ <animate attributeName="fill" attributeType="XML"
+ values="lime;green;lime" dur="2s"
+ repeatCount="indefinite" />
+ </text>
+
+ <!-- Animates override value for CSS property. -->
+ <text id="cssOverrideTest" x="0" y="35">
+ This should be green since the animation should be allowed by CSP.
+
+ <animate attributeName="fill" attributeType="CSS"
+ values="lime;green;lime" dur="2s"
+ repeatCount="indefinite" />
+ </text>
+
+ <!-- Animates override value for CSS property targeted via ID. -->
+ <text id="cssOverrideTestById" x="0" y="55">
+ This should be green since the animation should be allowed by CSP.
+ </text>
+ <animate xlink:href="#cssOverrideTestById"
+ attributeName="fill"
+ values="lime;green;lime"
+ dur="2s" repeatCount="indefinite" />
+
+ <!-- Sets value for CSS property targeted via ID. -->
+ <text id="cssSetTestById" x="0" y="75">
+ This should be green since the &lt;set&gt; should be allowed by CSP.
+ </text>
+ <set xlink:href="#cssSetTestById"
+ attributeName="fill"
+ to="lime" />
+ </svg>
+ </body>
+</html>
diff --git a/dom/security/test/csp/file_inlinestyle_main_allowed.html^headers^ b/dom/security/test/csp/file_inlinestyle_main_allowed.html^headers^
new file mode 100644
index 0000000000..621d2536b0
--- /dev/null
+++ b/dom/security/test/csp/file_inlinestyle_main_allowed.html^headers^
@@ -0,0 +1,2 @@
+Content-Security-Policy: default-src 'self' ; script-src 'self' 'unsafe-inline' ; style-src 'self' 'unsafe-inline'
+Cache-Control: no-cache
diff --git a/dom/security/test/csp/file_invalid_source_expression.html b/dom/security/test/csp/file_invalid_source_expression.html
new file mode 100644
index 0000000000..83bb0ec0ca
--- /dev/null
+++ b/dom/security/test/csp/file_invalid_source_expression.html
@@ -0,0 +1,11 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title>Bug 1086612 - CSP: Let source expression be the empty set in case no valid source can be parsed</title>
+ </head>
+ <body>
+ <div id="testdiv">blocked</div>
+ <!-- Note, we reuse file_path_matching.js which only updates the testdiv to 'allowed' if loaded !-->
+ <script src="http://test1.example.com/tests/dom/security/test/csp/file_path_matching.js"></script>
+</body>
+</html>
diff --git a/dom/security/test/csp/file_leading_wildcard.html b/dom/security/test/csp/file_leading_wildcard.html
new file mode 100644
index 0000000000..ea5e993447
--- /dev/null
+++ b/dom/security/test/csp/file_leading_wildcard.html
@@ -0,0 +1,11 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title>Bug 1032303 - CSP - Keep FULL STOP when matching *.foo.com to disallow loads from foo.com</title>
+ </head>
+ <body>
+ <!-- Please note that both scripts do *not* exist in the file system -->
+ <script src="http://test1.example.com/tests/dom/security/test/csp/leading_wildcard_allowed.js" ></script>
+ <script src="http://example.com/tests/dom/security/test/csp/leading_wildcard_blocked.js" ></script>
+</body>
+</html>
diff --git a/dom/security/test/csp/file_link_rel_preload.html b/dom/security/test/csp/file_link_rel_preload.html
new file mode 100644
index 0000000000..8af49a77fe
--- /dev/null
+++ b/dom/security/test/csp/file_link_rel_preload.html
@@ -0,0 +1,19 @@
+<!doctype html>
+<html>
+<head>
+ <title>Bug 1599791 - Test link rel=preload</title>
+ <!-- Please note that fakeServer does not exist in our testsuite -->
+ <meta http-equiv="Content-Security-Policy" content="default-src 'none'">
+ <link rel="preload" as="script" href="fakeServer?script"></link>
+ <link rel="preload" as="style" href="fakeServer?style"></link>
+ <link rel="preload" as="image" href="fakeServer?image"></link>
+ <link rel="preload" as="fetch" href="fakeServer?fetch"></link>
+ <link rel="preload" as="font" href="fakeServer?font"></link>
+
+ <link rel="stylesheet" href="fakeServer?style">
+</head>
+<body>
+<script src="fakeServer?script"></script>
+<img src="fakeServer?image"></img>
+</body>
+</html>
diff --git a/dom/security/test/csp/file_main.html b/dom/security/test/csp/file_main.html
new file mode 100644
index 0000000000..ddc8382617
--- /dev/null
+++ b/dom/security/test/csp/file_main.html
@@ -0,0 +1,55 @@
+<html>
+ <head>
+ <link rel='stylesheet' type='text/css'
+ href='http://example.org/tests/dom/security/test/csp/file_CSP.sjs?testid=style_bad&type=text/css' />
+ <link rel='stylesheet' type='text/css'
+ href='file_CSP.sjs?testid=style_good&type=text/css' />
+
+
+ <style>
+ /* CSS font embedding tests */
+ @font-face {
+ font-family: "arbitrary_good";
+ src: url('file_CSP.sjs?testid=font_good&type=application/octet-stream');
+ }
+ @font-face {
+ font-family: "arbitrary_bad";
+ src: url('http://example.org/tests/dom/security/test/csp/file_CSP.sjs?testid=font_bad&type=application/octet-stream');
+ }
+
+ .div_arbitrary_good { font-family: "arbitrary_good"; }
+ .div_arbitrary_bad { font-family: "arbitrary_bad"; }
+ </style>
+ </head>
+ <body>
+ <!-- these should be stopped by CSP. :) -->
+ <img src="http://example.org/tests/dom/security/test/csp/file_CSP.sjs?testid=img_bad&type=img/png"> </img>
+ <audio src="http://example.org/tests/dom/security/test/csp/file_CSP.sjs?testid=media_bad&type=audio/vorbis"></audio>
+ <script src='http://example.org/tests/dom/security/test/csp/file_CSP.sjs?testid=script_bad&type=text/javascript'></script>
+ <iframe src='http://example.org/tests/dom/security/test/csp/file_CSP.sjs?testid=frame_bad&content=FAIL'></iframe>
+ <object width="10" height="10">
+ <param name="movie" value="http://example.org/tests/dom/security/test/csp/file_CSP.sjs?testid=object_bad&type=application/x-shockwave-flash">
+ <embed src="http://example.org/tests/dom/security/test/csp/file_CSP.sjs?testid=object_bad&type=application/x-shockwave-flash"></embed>
+ </object>
+
+ <!-- these should load ok. :) -->
+ <img src="file_CSP.sjs?testid=img_good&type=img/png" />
+ <audio src="file_CSP.sjs?testid=media_good&type=audio/vorbis"></audio>
+ <script src='file_CSP.sjs?testid=script_good&type=text/javascript'></script>
+ <iframe src='file_CSP.sjs?testid=frame_good&content=PASS'></iframe>
+
+ <object width="10" height="10">
+ <param name="movie" value="file_CSP.sjs?testid=object_good&type=application/x-shockwave-flash">
+ <embed src="file_CSP.sjs?testid=object_good&type=application/x-shockwave-flash"></embed>
+ </object>
+
+ <!-- XHR tests... they're taken care of in this script,
+ and since the URI doesn't have any 'testid' values,
+ it will just be ignored by the test framework. -->
+ <script src='file_main.js'></script>
+
+ <!-- Support elements for the @font-face test -->
+ <div class="div_arbitrary_good">arbitrary good</div>
+ <div class="div_arbitrary_bad">arbitrary_bad</div>
+ </body>
+</html>
diff --git a/dom/security/test/csp/file_main.html^headers^ b/dom/security/test/csp/file_main.html^headers^
new file mode 100644
index 0000000000..3338de389b
--- /dev/null
+++ b/dom/security/test/csp/file_main.html^headers^
@@ -0,0 +1 @@
+Content-Security-Policy: default-src 'self' blob: ; style-src 'unsafe-inline' 'self'
diff --git a/dom/security/test/csp/file_main.js b/dom/security/test/csp/file_main.js
new file mode 100644
index 0000000000..01dd43cbf5
--- /dev/null
+++ b/dom/security/test/csp/file_main.js
@@ -0,0 +1,26 @@
+function doXHR(uri) {
+ try {
+ var xhr = new XMLHttpRequest();
+ xhr.open("GET", uri);
+ xhr.send();
+ } catch (ex) {}
+}
+
+doXHR(
+ "http://mochi.test:8888/tests/dom/security/test/csp/file_CSP.sjs?testid=xhr_good"
+);
+doXHR(
+ "http://example.com/tests/dom/security/test/csp/file_CSP.sjs?testid=xhr_bad"
+);
+fetch(
+ "http://mochi.test:8888/tests/dom/security/test/csp/file_CSP.sjs?testid=fetch_good"
+);
+fetch(
+ "http://example.com/tests/dom/security/test/csp/file_CSP.sjs?testid=fetch_bad"
+);
+navigator.sendBeacon(
+ "http://mochi.test:8888/tests/dom/security/test/csp/file_CSP.sjs?testid=beacon_good"
+);
+navigator.sendBeacon(
+ "http://example.com/tests/dom/security/test/csp/file_CSP.sjs?testid=beacon_bad"
+);
diff --git a/dom/security/test/csp/file_meta_element.html b/dom/security/test/csp/file_meta_element.html
new file mode 100644
index 0000000000..17f19c7c86
--- /dev/null
+++ b/dom/security/test/csp/file_meta_element.html
@@ -0,0 +1,27 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <meta http-equiv="Content-Security-Policy"
+ content= "img-src 'none'; script-src 'unsafe-inline'; report-uri http://www.example.com; frame-ancestors https:; sandbox allow-scripts">
+ <title>Bug 663570 - Implement Content Security Policy via meta tag</title>
+</head>
+<body>
+
+ <!-- try to load an image which is forbidden by meta CSP -->
+ <img id="testimage"></img>
+
+ <script type="application/javascript">
+ var myImg = document.getElementById("testimage");
+ myImg.onload = function(e) {
+ window.parent.postMessage({result: "img-loaded"}, "*");
+ };
+ myImg.onerror = function(e) {
+ window.parent.postMessage({result: "img-blocked"}, "*");
+ };
+ //Image should be tried to load only after onload/onerror event declaration.
+ myImg.src = "http://mochi.test:8888/tests/image/test/mochitest/blue.png";
+ </script>
+
+</body>
+</html>
diff --git a/dom/security/test/csp/file_meta_header_dual.sjs b/dom/security/test/csp/file_meta_header_dual.sjs
new file mode 100644
index 0000000000..445b3e444e
--- /dev/null
+++ b/dom/security/test/csp/file_meta_header_dual.sjs
@@ -0,0 +1,101 @@
+// Custom *.sjs file specifically for the needs of Bug:
+// Bug 663570 - Implement Content Security Policy via meta tag
+
+const HTML_HEAD =
+ "<!DOCTYPE HTML>" +
+ "<html>" +
+ "<head>" +
+ "<meta charset='utf-8'>" +
+ "<title>Bug 663570 - Implement Content Security Policy via <meta> tag</title>";
+
+const HTML_BODY =
+ "</head>" +
+ "<body>" +
+ "<img id='testimage' src='http://mochi.test:8888/tests/image/test/mochitest/blue.png'></img>" +
+ "<script type='application/javascript'>" +
+ " var myImg = document.getElementById('testimage');" +
+ " myImg.onload = function(e) {" +
+ " window.parent.postMessage({result: 'img-loaded'}, '*');" +
+ " };" +
+ " myImg.onerror = function(e) { " +
+ " window.parent.postMessage({result: 'img-blocked'}, '*');" +
+ " };" +
+ "</script>" +
+ "</body>" +
+ "</html>";
+
+const META_CSP_BLOCK_IMG =
+ '<meta http-equiv="Content-Security-Policy" content="img-src \'none\'">';
+
+const META_CSP_ALLOW_IMG =
+ '<meta http-equiv="Content-Security-Policy" content="img-src http://mochi.test:8888;">';
+
+const HEADER_CSP_BLOCK_IMG = "img-src 'none';";
+
+const HEADER_CSP_ALLOW_IMG = "img-src http://mochi.test:8888";
+
+function handleRequest(request, response) {
+ // avoid confusing cache behaviors
+ response.setHeader("Cache-Control", "no-cache", false);
+ response.setHeader("Content-Type", "text/html", false);
+ var queryString = request.queryString;
+
+ if (queryString === "test1") {
+ /* load image without any CSP */
+ response.write(HTML_HEAD + HTML_BODY);
+ return;
+ }
+
+ if (queryString === "test2") {
+ /* load image where meta denies load */
+ response.write(HTML_HEAD + META_CSP_BLOCK_IMG + HTML_BODY);
+ return;
+ }
+
+ if (queryString === "test3") {
+ /* load image where meta allows load */
+ response.write(HTML_HEAD + META_CSP_ALLOW_IMG + HTML_BODY);
+ return;
+ }
+
+ if (queryString === "test4") {
+ /* load image where meta allows but header blocks */
+ response.setHeader("Content-Security-Policy", HEADER_CSP_BLOCK_IMG, false);
+ response.write(HTML_HEAD + META_CSP_ALLOW_IMG + HTML_BODY);
+ return;
+ }
+
+ if (queryString === "test5") {
+ /* load image where meta blocks but header allows */
+ response.setHeader("Content-Security-Policy", HEADER_CSP_ALLOW_IMG, false);
+ response.write(HTML_HEAD + META_CSP_BLOCK_IMG + HTML_BODY);
+ return;
+ }
+
+ if (queryString === "test6") {
+ /* load image where meta allows and header allows */
+ response.setHeader("Content-Security-Policy", HEADER_CSP_ALLOW_IMG, false);
+ response.write(HTML_HEAD + META_CSP_ALLOW_IMG + HTML_BODY);
+ return;
+ }
+
+ if (queryString === "test7") {
+ /* load image where meta1 allows but meta2 blocks */
+ response.write(
+ HTML_HEAD + META_CSP_ALLOW_IMG + META_CSP_BLOCK_IMG + HTML_BODY
+ );
+ return;
+ }
+
+ if (queryString === "test8") {
+ /* load image where meta1 allows and meta2 allows */
+ response.write(
+ HTML_HEAD + META_CSP_ALLOW_IMG + META_CSP_ALLOW_IMG + HTML_BODY
+ );
+ return;
+ }
+
+ // we should never get here, but just in case, return
+ // something unexpected
+ response.write("do'h");
+}
diff --git a/dom/security/test/csp/file_meta_whitespace_skipping.html b/dom/security/test/csp/file_meta_whitespace_skipping.html
new file mode 100644
index 0000000000..c0cfc8cc28
--- /dev/null
+++ b/dom/security/test/csp/file_meta_whitespace_skipping.html
@@ -0,0 +1,31 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <!-- Test all the different space characters within the meta csp:
+ * U+0020 space | &#x20;
+ * U+0009 tab | &#x9;
+ * U+000A line feed | &#xa;
+ * U+000C form feed | &#xc;
+ * U+000D carriage return | &#xd;
+ !-->
+ <meta http-equiv="Content-Security-Policy"
+ content= "
+ img-src&#x20; 'none'; &#x20;
+ script-src 'unsafe-inline' &#xd;
+ ;
+ style-src&#x9;&#x9; https://example.com&#xa;
+ https://foo.com;&#xc;;;;&#xc;;;&#xc; child-src foo.com
+ bar.com
+ &#xd;;&#xd;
+ font-src 'none'">
+ <title>Bug 1261634 - Update whitespace skipping for meta csp</title>
+</head>
+<body>
+ <script type="application/javascript">
+ // notify the including document that we are done parsing the meta csp
+ window.parent.postMessage({result: "meta-csp-parsed"}, "*");
+ </script>
+
+</body>
+</html>
diff --git a/dom/security/test/csp/file_multi_policy_injection_bypass.html b/dom/security/test/csp/file_multi_policy_injection_bypass.html
new file mode 100644
index 0000000000..a3cb415a9e
--- /dev/null
+++ b/dom/security/test/csp/file_multi_policy_injection_bypass.html
@@ -0,0 +1,15 @@
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=717511
+-->
+ <body>
+ <!-- these should be stopped by CSP after fixing bug 717511. :) -->
+ <img src="http://example.org/tests/dom/security/test/csp/file_CSP.sjs?testid=img_bad&type=img/png"> </img>
+ <script src='http://example.org/tests/dom/security/test/csp/file_CSP.sjs?testid=script_bad&type=text/javascript'></script>
+
+ <!-- these should load ok after fixing bug 717511. :) -->
+ <img src="file_CSP.sjs?testid=img_good&type=img/png" />
+ <script src='file_CSP.sjs?testid=script_good&type=text/javascript'></script>
+
+ </body>
+</html>
diff --git a/dom/security/test/csp/file_multi_policy_injection_bypass.html^headers^ b/dom/security/test/csp/file_multi_policy_injection_bypass.html^headers^
new file mode 100644
index 0000000000..e1b64a9220
--- /dev/null
+++ b/dom/security/test/csp/file_multi_policy_injection_bypass.html^headers^
@@ -0,0 +1 @@
+Content-Security-Policy: default-src 'self', default-src *
diff --git a/dom/security/test/csp/file_multi_policy_injection_bypass_2.html b/dom/security/test/csp/file_multi_policy_injection_bypass_2.html
new file mode 100644
index 0000000000..3fa6c7ab91
--- /dev/null
+++ b/dom/security/test/csp/file_multi_policy_injection_bypass_2.html
@@ -0,0 +1,15 @@
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=717511
+-->
+ <body>
+ <!-- these should be stopped by CSP after fixing bug 717511. :) -->
+ <img src="http://example.org/tests/dom/security/test/csp/file_CSP.sjs?testid=img2_bad&type=img/png"> </img>
+ <script src='http://example.org/tests/dom/security/test/csp/file_CSP.sjs?testid=script2_bad&type=text/javascript'></script>
+
+ <!-- these should load ok after fixing bug 717511. :) -->
+ <img src="file_CSP.sjs?testid=img2_good&type=img/png" />
+ <script src='file_CSP.sjs?testid=script2_good&type=text/javascript'></script>
+
+ </body>
+</html>
diff --git a/dom/security/test/csp/file_multi_policy_injection_bypass_2.html^headers^ b/dom/security/test/csp/file_multi_policy_injection_bypass_2.html^headers^
new file mode 100644
index 0000000000..b523073cd3
--- /dev/null
+++ b/dom/security/test/csp/file_multi_policy_injection_bypass_2.html^headers^
@@ -0,0 +1 @@
+Content-Security-Policy: default-src 'self' , default-src *
diff --git a/dom/security/test/csp/file_multipart_testserver.sjs b/dom/security/test/csp/file_multipart_testserver.sjs
new file mode 100644
index 0000000000..571dd4006d
--- /dev/null
+++ b/dom/security/test/csp/file_multipart_testserver.sjs
@@ -0,0 +1,160 @@
+// SJS file specifically for the needs of bug
+// Bug 1416045/Bug 1223743 - CSP: Check baseChannel for CSP when loading multipart channel
+
+var CSP = "script-src 'unsafe-inline', img-src 'none'";
+var rootCSP = "script-src 'unsafe-inline'";
+var part1CSP = "img-src *";
+var part2CSP = "img-src 'none'";
+var BOUNDARY = "fooboundary";
+
+// small red image
+const IMG_BYTES = atob(
+ "iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12" +
+ "P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=="
+);
+
+var RESPONSE = `
+ <script>
+ var myImg = new Image;
+ myImg.src = "file_multipart_testserver.sjs?img";
+ myImg.onerror = function(e) {
+ window.parent.postMessage({"test": "rootCSP_test",
+ "msg": "img-blocked"}, "*");
+ };
+ myImg.onload = function() {
+ window.parent.postMessage({"test": "rootCSP_test",
+ "msg": "img-loaded"}, "*");
+ };
+ document.body.appendChild(myImg);
+ </script>
+`;
+
+var RESPONSE1 = `
+ <body>
+ <script>
+ var triggerNextPartFrame = document.createElement('iframe');
+ var myImg = new Image;
+ myImg.src = "file_multipart_testserver.sjs?img";
+ myImg.onerror = function(e) {
+ window.parent.postMessage({"test": "part1CSP_test",
+ "msg": "part1-img-blocked"}, "*");
+ triggerNextPartFrame.src = 'file_multipart_testserver.sjs?sendnextpart';
+ };
+ myImg.onload = function() {
+ window.parent.postMessage({"test": "part1CSP_test",
+ "msg": "part1-img-loaded"}, "*");
+ triggerNextPartFrame.src = 'file_multipart_testserver.sjs?sendnextpart';
+ };
+ document.body.appendChild(myImg);
+ document.body.appendChild(triggerNextPartFrame);
+ </script>
+ </body>
+`;
+
+var RESPONSE2 = `
+ <body>
+ <script>
+ var myImg = new Image;
+ myImg.src = "file_multipart_testserver.sjs?img";
+ myImg.onerror = function(e) {
+ window.parent.postMessage({"test": "part2CSP_test",
+ "msg": "part2-img-blocked"}, "*");
+ };
+ myImg.onload = function() {
+ window.parent.postMessage({"test": "part2CSP_test",
+ "msg": "part2-img-loaded"}, "*");
+ };
+ document.body.appendChild(myImg);
+ </script>
+ </body>
+`;
+
+function setGlobalState(data, key) {
+ x = {
+ data,
+ QueryInterface(iid) {
+ return this;
+ },
+ };
+ x.wrappedJSObject = x;
+ setObjectState(key, x);
+}
+
+function getGlobalState(key) {
+ var data;
+ getObjectState(key, function (x) {
+ data = x && x.wrappedJSObject.data;
+ });
+ return data;
+}
+
+function handleRequest(request, response) {
+ // avoid confusing cache behaviors
+ response.setHeader("Cache-Control", "no-cache", false);
+
+ if (request.queryString == "doc") {
+ response.setHeader("Content-Security-Policy", CSP, false);
+ response.setHeader(
+ "Content-Type",
+ "multipart/x-mixed-replace; boundary=" + BOUNDARY,
+ false
+ );
+ response.write(BOUNDARY + "\r\n");
+ response.write(RESPONSE);
+ response.write(BOUNDARY + "\r\n");
+ return;
+ }
+
+ if (request.queryString == "partcspdoc") {
+ response.setHeader("Content-Security-Policy", rootCSP, false);
+ response.setHeader(
+ "Content-Type",
+ "multipart/x-mixed-replace; boundary=" + BOUNDARY,
+ false
+ );
+ response.setStatusLine(request.httpVersion, 200, "OK");
+ response.processAsync();
+ response.write("--" + BOUNDARY + "\r\n");
+ sendNextPart(response, 1);
+ return;
+ }
+
+ if (request.queryString == "sendnextpart") {
+ response.setStatusLine(request.httpVersion, 204, "No content");
+ var blockedResponse = getGlobalState("root-document-response");
+ if (typeof blockedResponse == "object") {
+ sendNextPart(blockedResponse, 2);
+ sendClose(blockedResponse);
+ } else {
+ dump("Couldn't find the stored response object.");
+ }
+ return;
+ }
+
+ if (request.queryString == "img") {
+ response.setHeader("Content-Type", "image/png");
+ response.write(IMG_BYTES);
+ return;
+ }
+
+ // we should never get here - return something unexpected
+ response.write("d'oh");
+}
+
+function sendClose(response) {
+ response.write("--" + BOUNDARY + "--\r\n");
+ response.finish();
+}
+
+function sendNextPart(response, partNumber) {
+ response.write("Content-type: text/html" + "\r\n");
+ if (partNumber == 1) {
+ response.write("Content-Security-Policy:" + part1CSP + "\r\n");
+ response.write(RESPONSE1);
+ setGlobalState(response, "root-document-response");
+ } else {
+ response.write("Content-Security-Policy:" + part2CSP + "\r\n");
+ response.write(RESPONSE2);
+ }
+ response.write("--" + BOUNDARY + "\r\n");
+}
diff --git a/dom/security/test/csp/file_navigate_to.html b/dom/security/test/csp/file_navigate_to.html
new file mode 100644
index 0000000000..f6ea36d389
--- /dev/null
+++ b/dom/security/test/csp/file_navigate_to.html
@@ -0,0 +1,11 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 1529068 Implement CSP 'navigate-to' directive</title>
+</head>
+<body>
+ <script type="text/javascript">
+ window.location = "http://www.example.com/";
+ </script>
+</body>
+</html>
diff --git a/dom/security/test/csp/file_navigate_to.sjs b/dom/security/test/csp/file_navigate_to.sjs
new file mode 100644
index 0000000000..d1cffb74cc
--- /dev/null
+++ b/dom/security/test/csp/file_navigate_to.sjs
@@ -0,0 +1,58 @@
+// Custom *.sjs file specifically for the needs of
+// https://bugzilla.mozilla.org/show_bug.cgi?id=1529068
+
+"use strict";
+Components.utils.importGlobalProperties(["URLSearchParams"]);
+
+const TEST_NAVIGATION_HEAD = `
+ <!DOCTYPE HTML>
+ <html>
+ <head>
+ <title>Bug 1529068 Implement CSP 'navigate-to' directive</title>`;
+
+const TEST_NAVIGATION_AFTER_META = `
+ </head>
+ <body>
+ <script type="text/javascript">
+ window.location = "`;
+
+const TEST_NAVIGATION_FOOT = `";
+ </script>
+ </body>
+ </html>
+ `;
+
+function handleRequest(request, response) {
+ const query = new URLSearchParams(request.queryString);
+
+ response.setHeader("Cache-Control", "no-cache", false);
+ response.setHeader("Content-Type", "text/html", false);
+
+ if (query.get("redir")) {
+ response.setStatusLine(request.httpVersion, "302", "Found");
+ response.setHeader("Location", query.get("redir"), false);
+ return;
+ }
+
+ response.write(TEST_NAVIGATION_HEAD);
+
+ // We need meta to set multiple CSP headers.
+ if (query.get("csp")) {
+ response.write(
+ '<meta http-equiv="Content-Security-Policy" content="' +
+ query.get("csp") +
+ '">'
+ );
+ }
+ if (query.get("csp2")) {
+ response.write(
+ '<meta http-equiv="Content-Security-Policy" content="' +
+ query.get("csp2") +
+ '">'
+ );
+ }
+
+ response.write(
+ TEST_NAVIGATION_AFTER_META + query.get("target") + TEST_NAVIGATION_FOOT
+ );
+}
diff --git a/dom/security/test/csp/file_navigate_to_request.html b/dom/security/test/csp/file_navigate_to_request.html
new file mode 100644
index 0000000000..4f82525599
--- /dev/null
+++ b/dom/security/test/csp/file_navigate_to_request.html
@@ -0,0 +1,17 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+</head>
+<script type="text/javascript">
+ // The idea with this file is to convert responses into requests.
+ // This is needed because we don't have
+ // specialpowers-http-notify-response
+
+ // Response from this file => request to www.example.com => Allowed
+ // CSP error => Blocked
+ fetch('http://www.example.com/');
+</script>
+<body>
+</body>
+</html>
diff --git a/dom/security/test/csp/file_no_log_ignore_xfo.html b/dom/security/test/csp/file_no_log_ignore_xfo.html
new file mode 100644
index 0000000000..fc5528a35c
--- /dev/null
+++ b/dom/security/test/csp/file_no_log_ignore_xfo.html
@@ -0,0 +1,10 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Bug 1722252: "Content-Security-Policy: Ignoring ‘x-frame-options’ because of ‘frame-ancestors’ directive." warning message even when no "x-frame-options" header present</title>
+</head>
+<body>
+<div id="cspmessage">Do not log xfo ignore warning when no xfo is set.</div>
+</body>
+</html>
diff --git a/dom/security/test/csp/file_no_log_ignore_xfo.html^headers^ b/dom/security/test/csp/file_no_log_ignore_xfo.html^headers^
new file mode 100644
index 0000000000..1fbbf3de99
--- /dev/null
+++ b/dom/security/test/csp/file_no_log_ignore_xfo.html^headers^
@@ -0,0 +1,2 @@
+Content-Security-Policy: frame-ancestors http://mochi.test:8888
+Cache-Control: no-cache
diff --git a/dom/security/test/csp/file_nonce_redirector.sjs b/dom/security/test/csp/file_nonce_redirector.sjs
new file mode 100644
index 0000000000..b56b9ded37
--- /dev/null
+++ b/dom/security/test/csp/file_nonce_redirector.sjs
@@ -0,0 +1,28 @@
+// custom *.sjs file for
+// Bug 1469150:Scripts with valid nonce get blocked if URL redirects.
+
+const URL_PATH = "example.com/tests/dom/security/test/csp/";
+
+function handleRequest(request, response) {
+ response.setHeader("Cache-Control", "no-cache", false);
+ let queryStr = request.queryString;
+
+ if (queryStr === "redirect") {
+ response.setStatusLine("1.1", 302, "Found");
+ response.setHeader(
+ "Location",
+ "https://" + URL_PATH + "file_nonce_redirector.sjs?load",
+ false
+ );
+ return;
+ }
+
+ if (queryStr === "load") {
+ response.setHeader("Content-Type", "application/javascript", false);
+ response.write("console.log('script loaded');");
+ return;
+ }
+
+ // we should never get here - return something unexpected
+ response.write("d'oh");
+}
diff --git a/dom/security/test/csp/file_nonce_redirects.html b/dom/security/test/csp/file_nonce_redirects.html
new file mode 100644
index 0000000000..e291164900
--- /dev/null
+++ b/dom/security/test/csp/file_nonce_redirects.html
@@ -0,0 +1,23 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <meta charset='utf-8'>
+ <meta http-equiv="Content-Security-Policy" content="script-src 'nonce-abcd1234'">
+ <title>Bug 1469150:Scripts with valid nonce get blocked if URL redirects</title>
+ </head>
+<body>
+
+<script nonce='abcd1234' id='redirectScript'></script>
+
+<script nonce='abcd1234' type='application/javascript'>
+ var redirectScript = document.getElementById('redirectScript');
+ redirectScript.onload = function(e) {
+ window.parent.postMessage({result: 'script-loaded'}, '*');
+ };
+ redirectScript.onerror = function(e) {
+ window.parent.postMessage({result: 'script-blocked'}, '*');
+ }
+ redirectScript.src = 'file_nonce_redirector.sjs?redirect';
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/file_nonce_snapshot.sjs b/dom/security/test/csp/file_nonce_snapshot.sjs
new file mode 100644
index 0000000000..2b114fd87e
--- /dev/null
+++ b/dom/security/test/csp/file_nonce_snapshot.sjs
@@ -0,0 +1,54 @@
+"use strict";
+
+const TEST_FRAME = `<!DOCTYPE HTML>
+ <html>
+ <body>
+ <script id='myScript' nonce='123456789' type='application/javascript'></script>
+ <script nonce='123456789'>
+ let myScript = document.getElementById('myScript');
+ // 1) start loading the script using the nonce 123456789
+ myScript.src='file_nonce_snapshot.sjs?redir-script';
+ // 2) dynamically change the nonce, load should use initial nonce
+ myScript.setAttribute('nonce','987654321');
+ </script>
+ </body>
+ </html>`;
+
+const SCRIPT = "window.parent.postMessage('script-loaded', '*');";
+
+function handleRequest(request, response) {
+ // avoid confusing cache behaviors
+ response.setHeader("Cache-Control", "no-cache", false);
+
+ let queryString = request.queryString;
+
+ if (queryString === "load-frame") {
+ response.setHeader(
+ "Content-Security-Policy",
+ "script-src 'nonce-123456789'",
+ false
+ );
+ response.setHeader("Content-Type", "text/html", false);
+ response.write(TEST_FRAME);
+ return;
+ }
+
+ if (queryString === "redir-script") {
+ response.setStatusLine("1.1", 302, "Found");
+ response.setHeader(
+ "Location",
+ "file_nonce_snapshot.sjs?load-script",
+ false
+ );
+ return;
+ }
+
+ if (queryString === "load-script") {
+ response.setHeader("Content-Type", "application/javascript", false);
+ response.write(SCRIPT);
+ return;
+ }
+
+ // we should never get here but just in case return something unexpected
+ response.write("do'h");
+}
diff --git a/dom/security/test/csp/file_nonce_source.html b/dom/security/test/csp/file_nonce_source.html
new file mode 100644
index 0000000000..01d4046c37
--- /dev/null
+++ b/dom/security/test/csp/file_nonce_source.html
@@ -0,0 +1,73 @@
+<!doctype html>
+<html>
+ <head>
+ <!-- external styles -->
+ <link rel='stylesheet' nonce="correctstylenonce" href="file_CSP.sjs?testid=external_style_correct_nonce_good&type=text/css" />
+ <link rel='stylesheet' nonce="incorrectstylenonce" href="file_CSP.sjs?testid=external_style_incorrect_nonce_bad&type=text/css" />
+ <link rel='stylesheet' nonce="correctscriptnonce" href="file_CSP.sjs?testid=external_style_correct_script_nonce_bad&type=text/css" />
+ <link rel='stylesheet' href="file_CSP.sjs?testid=external_style_no_nonce_bad&type=text/css" />
+ </head>
+ <body>
+ <!-- inline scripts -->
+ <ol>
+ <li id="inline-script-correct-nonce">(inline script with correct nonce) This text should be green.</li>
+ <li id="inline-script-incorrect-nonce">(inline script with incorrect nonce) This text should be black.</li>
+ <li id="inline-script-correct-style-nonce">(inline script with correct nonce for styles, but not for scripts) This text should be black.</li>
+ <li id="inline-script-no-nonce">(inline script with no nonce) This text should be black.</li>
+ </ol>
+ <script nonce="correctscriptnonce">
+ document.getElementById("inline-script-correct-nonce").style.color = "rgb(0, 128, 0)";
+ </script>
+ <script nonce="incorrectscriptnonce">
+ document.getElementById("inline-script-incorrect-nonce").style.color = "rgb(255, 0, 0)";
+ </script>
+ <script nonce="correctstylenonce">
+ document.getElementById("inline-script-correct-style-nonce").style.color = "rgb(255, 0, 0)";
+ </script>
+ <script>
+ document.getElementById("inline-script-no-nonce").style.color = "rgb(255, 0, 0)";
+ </script>
+
+ <!-- external scripts -->
+ <script nonce="correctscriptnonce" src="http://example.org/tests/dom/security/test/csp/file_CSP.sjs?testid=external_script_correct_nonce_good&type=text/javascript"></script>
+ <script nonce="anothercorrectscriptnonce" src="http://example.org/tests/dom/security/test/csp/file_CSP.sjs?testid=external_script_another_correct_nonce_good&type=text/javascript"></script>
+ <script nonce="incorrectscriptnonce" src="http://example.org/tests/dom/security/test/csp/file_CSP.sjs?testid=external_script_incorrect_nonce_bad&type=text/javascript"></script>
+ <script nonce="correctstylenonce" src="http://example.org/tests/dom/security/test/csp/file_CSP.sjs?testid=external_script_correct_style_nonce_bad&type=text/javascript"></script>
+ <script src="http://example.org/tests/dom/security/test/csp/file_CSP.sjs?testid=external_script_no_nonce_bad&type=text/javascript"></script>
+
+ <!-- This external script has the correct nonce and comes from a allowlisted URI. It should be allowed. -->
+ <script nonce="correctscriptnonce" src="file_CSP.sjs?testid=external_script_correct_nonce_correct_uri_good&type=text/javascript"></script>
+ <!-- This external script has an incorrect nonce, but comes from a allowlisted URI. It should be allowed. -->
+ <script nonce="incorrectscriptnonce" src="file_CSP.sjs?testid=external_script_incorrect_nonce_correct_uri_good&type=text/javascript"></script>
+ <!-- This external script has no nonce and comes from a allowlisted URI. It should be allowed. -->
+ <script src="file_CSP.sjs?testid=external_script_no_nonce_correct_uri_good&type=text/javascript"></script>
+
+ <!-- inline styles -->
+ <ol>
+ <li id=inline-style-correct-nonce>
+ (inline style with correct nonce) This text should be green
+ </li>
+ <li id=inline-style-incorrect-nonce>
+ (inline style with incorrect nonce) This text should be black
+ </li>
+ <li id=inline-style-correct-script-nonce>
+ (inline style with correct script, not style, nonce) This text should be black
+ </li>
+ <li id=inline-style-no-nonce>
+ (inline style with no nonce) This text should be black
+ </li>
+ </ol>
+ <style nonce=correctstylenonce>
+ li#inline-style-correct-nonce { color: green; }
+ </style>
+ <style nonce=incorrectstylenonce>
+ li#inline-style-incorrect-nonce { color: red; }
+ </style>
+ <style nonce=correctscriptnonce>
+ li#inline-style-correct-script-nonce { color: red; }
+ </style>
+ <style>
+ li#inline-style-no-nonce { color: red; }
+ </style>
+ </body>
+</html>
diff --git a/dom/security/test/csp/file_nonce_source.html^headers^ b/dom/security/test/csp/file_nonce_source.html^headers^
new file mode 100644
index 0000000000..865e5fe984
--- /dev/null
+++ b/dom/security/test/csp/file_nonce_source.html^headers^
@@ -0,0 +1,2 @@
+Content-Security-Policy: script-src 'self' 'nonce-correctscriptnonce' 'nonce-anothercorrectscriptnonce'; style-src 'nonce-correctstylenonce';
+Cache-Control: no-cache
diff --git a/dom/security/test/csp/file_null_baseuri.html b/dom/security/test/csp/file_null_baseuri.html
new file mode 100644
index 0000000000..f995688b13
--- /dev/null
+++ b/dom/security/test/csp/file_null_baseuri.html
@@ -0,0 +1,21 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title>Bug 1121857 - document.baseURI should not get blocked if baseURI is null</title>
+ </head>
+ <body>
+ <script type="text/javascript">
+ // check the initial base-uri
+ window.parent.postMessage({baseURI: document.baseURI, test: "initial_base_uri"}, "*");
+
+ // append a child and check the base-uri
+ var baseTag = document.head.appendChild(document.createElement('base'));
+ baseTag.href = 'http://www.base-tag.com';
+ window.parent.postMessage({baseURI: document.baseURI, test: "changed_base_uri"}, "*");
+
+ // remove the child and check that the base-uri is back to the initial one
+ document.head.remove(baseTag);
+ window.parent.postMessage({baseURI: document.baseURI, test: "initial_base_uri"}, "*");
+ </script>
+</body>
+</html>
diff --git a/dom/security/test/csp/file_object_inherit.html b/dom/security/test/csp/file_object_inherit.html
new file mode 100644
index 0000000000..76c9764162
--- /dev/null
+++ b/dom/security/test/csp/file_object_inherit.html
@@ -0,0 +1,21 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 1457100: Test OBJECT inherits CSP if needed</title>
+ <meta charset="utf-8">
+ <meta http-equiv="Content-Security-Policy" content= "img-src https://bug1457100.test.com"/>
+</head>
+<body>
+<object id="dataObject" data="data:text/html,object<script>var foo = 0;</script>"></object>
+
+<script type="application/javascript">
+ var dataObject = document.getElementById("dataObject");
+ dataObject.onload = function () {
+ var contentDoc = SpecialPowers.wrap(dataObject).contentDocument;
+ var cspJSON = contentDoc.cspJSON;
+ window.parent.postMessage({cspJSON}, "*");
+ }
+</script>
+
+</body>
+</html>
diff --git a/dom/security/test/csp/file_parent_location_js.html b/dom/security/test/csp/file_parent_location_js.html
new file mode 100644
index 0000000000..9c56f49905
--- /dev/null
+++ b/dom/security/test/csp/file_parent_location_js.html
@@ -0,0 +1,18 @@
+<html>
+<head>
+ <title>Test setting parent location to javascript:</title>
+ <meta http-equiv="Content-Security-Policy" content="script-src 'nonce-bug1550414'">
+ <script nonce="bug1550414">
+ document.addEventListener("securitypolicyviolation", (e) => {
+ window.parent.postMessage({
+ blockedURI: e.blockedURI,
+ violatedDirective: e.violatedDirective,
+ originalPolicy: e.originalPolicy,
+ }, '*');
+ });
+ </script>
+</head>
+<body>
+ <iframe src="file_iframe_parent_location_js.html"></iframe>
+</body>
+</html>
diff --git a/dom/security/test/csp/file_path_matching.html b/dom/security/test/csp/file_path_matching.html
new file mode 100644
index 0000000000..662fbfb8af
--- /dev/null
+++ b/dom/security/test/csp/file_path_matching.html
@@ -0,0 +1,10 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title>Bug 808292 - Implement path-level host-source matching to CSP</title>
+ </head>
+ <body>
+ <div id="testdiv">blocked</div>
+ <script src="http://test1.example.com/tests/dom/security/test/csp/file_path_matching.js#foo"></script>
+</body>
+</html>
diff --git a/dom/security/test/csp/file_path_matching.js b/dom/security/test/csp/file_path_matching.js
new file mode 100644
index 0000000000..09286d42e9
--- /dev/null
+++ b/dom/security/test/csp/file_path_matching.js
@@ -0,0 +1 @@
+document.getElementById("testdiv").innerHTML = "allowed";
diff --git a/dom/security/test/csp/file_path_matching_incl_query.html b/dom/security/test/csp/file_path_matching_incl_query.html
new file mode 100644
index 0000000000..50af2b1437
--- /dev/null
+++ b/dom/security/test/csp/file_path_matching_incl_query.html
@@ -0,0 +1,10 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title>Bug 1147026 - CSP should ignore query string when checking a resource load</title>
+ </head>
+ <body>
+ <div id="testdiv">blocked</div>
+ <script src="http://test1.example.com/tests/dom/security/test/csp/file_path_matching.js?val=foo"></script>
+</body>
+</html>
diff --git a/dom/security/test/csp/file_path_matching_redirect.html b/dom/security/test/csp/file_path_matching_redirect.html
new file mode 100644
index 0000000000..a16cc90ec6
--- /dev/null
+++ b/dom/security/test/csp/file_path_matching_redirect.html
@@ -0,0 +1,10 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title>Bug 808292 - Implement path-level host-source matching to CSP</title>
+ </head>
+ <body>
+ <div id="testdiv">blocked</div>
+ <script src="http://example.com/tests/dom/security/test/csp/file_path_matching_redirect_server.sjs"></script>
+</body>
+</html>
diff --git a/dom/security/test/csp/file_path_matching_redirect_server.sjs b/dom/security/test/csp/file_path_matching_redirect_server.sjs
new file mode 100644
index 0000000000..bed3a1dccf
--- /dev/null
+++ b/dom/security/test/csp/file_path_matching_redirect_server.sjs
@@ -0,0 +1,12 @@
+// Redirect server specifically to handle redirects
+// for path-level host-source matching
+// see https://bugzilla.mozilla.org/show_bug.cgi?id=808292
+
+function handleRequest(request, response) {
+ var newLocation =
+ "http://test1.example.com/tests/dom/security/test/csp/file_path_matching.js";
+
+ response.setStatusLine("1.1", 302, "Found");
+ response.setHeader("Cache-Control", "no-cache", false);
+ response.setHeader("Location", newLocation, false);
+}
diff --git a/dom/security/test/csp/file_pdfjs_not_subject_to_csp.html b/dom/security/test/csp/file_pdfjs_not_subject_to_csp.html
new file mode 100644
index 0000000000..da5c7f0a6e
--- /dev/null
+++ b/dom/security/test/csp/file_pdfjs_not_subject_to_csp.html
@@ -0,0 +1,21 @@
+<html>
+<head>
+ <meta http-equiv="Content-Security-Policy" content="script-src 'self' 'nonce-allowPDF'; base-uri 'self'">
+</head>
+<body>
+<iframe id="pdfFrame"></iframe>
+<br/>
+<button id="pdfButton">click to load pdf</button>
+<script nonce="allowPDF">
+ async function loadPDFIntoIframe() {
+ let response = await fetch("dummy.pdf");
+ let blob = await response.blob();
+ var blobUrl = URL.createObjectURL(blob);
+ var pdfFrame = document.getElementById("pdfFrame");
+ pdfFrame.src = blobUrl;
+ }
+ let pdfButton = document.getElementById("pdfButton");
+ pdfButton.addEventListener("click", loadPDFIntoIframe);
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/file_ping.html b/dom/security/test/csp/file_ping.html
new file mode 100644
index 0000000000..8aaf34cc3a
--- /dev/null
+++ b/dom/security/test/csp/file_ping.html
@@ -0,0 +1,19 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 1100181 - CSP: Enforce connect-src when submitting pings</title>
+</head>
+<body>
+ <!-- we are using an image for the test, but can be anything -->
+ <a id="testlink"
+ href="http://mochi.test:8888/tests/image/test/mochitest/blue.png"
+ ping="http://mochi.test:8888/tests/image/test/mochitest/blue.png?send-ping">
+ Send ping
+ </a>
+
+ <script type="text/javascript">
+ var link = document.getElementById("testlink");
+ link.click();
+ </script>
+</body>
+</html>
diff --git a/dom/security/test/csp/file_policyuri_regression_from_multipolicy.html b/dom/security/test/csp/file_policyuri_regression_from_multipolicy.html
new file mode 100644
index 0000000000..2a75eef7e8
--- /dev/null
+++ b/dom/security/test/csp/file_policyuri_regression_from_multipolicy.html
@@ -0,0 +1,9 @@
+<!doctype html>
+<html>
+ <body>
+ <div id=testdiv>Inline script didn't run</div>
+ <script>
+ document.getElementById('testdiv').innerHTML = "Inline Script Executed";
+ </script>
+ </body>
+</html>
diff --git a/dom/security/test/csp/file_policyuri_regression_from_multipolicy.html^headers^ b/dom/security/test/csp/file_policyuri_regression_from_multipolicy.html^headers^
new file mode 100644
index 0000000000..c4ff8ea9fd
--- /dev/null
+++ b/dom/security/test/csp/file_policyuri_regression_from_multipolicy.html^headers^
@@ -0,0 +1 @@
+content-security-policy-report-only: policy-uri /tests/dom/security/test/csp/file_policyuri_regression_from_multipolicy_policy
diff --git a/dom/security/test/csp/file_policyuri_regression_from_multipolicy_policy b/dom/security/test/csp/file_policyuri_regression_from_multipolicy_policy
new file mode 100644
index 0000000000..a5c610cd7b
--- /dev/null
+++ b/dom/security/test/csp/file_policyuri_regression_from_multipolicy_policy
@@ -0,0 +1 @@
+default-src 'self';
diff --git a/dom/security/test/csp/file_punycode_host_src.js b/dom/security/test/csp/file_punycode_host_src.js
new file mode 100644
index 0000000000..9728e2fecc
--- /dev/null
+++ b/dom/security/test/csp/file_punycode_host_src.js
@@ -0,0 +1,2 @@
+const LOADED = true;
+parent.postMessage({ result: "script-allowed" }, "*");
diff --git a/dom/security/test/csp/file_punycode_host_src.sjs b/dom/security/test/csp/file_punycode_host_src.sjs
new file mode 100644
index 0000000000..184c6b1041
--- /dev/null
+++ b/dom/security/test/csp/file_punycode_host_src.sjs
@@ -0,0 +1,47 @@
+// custom *.sjs for Bug 1224225
+// Punycode in CSP host sources
+
+const HTML_PART1 =
+ "<!DOCTYPE HTML>" +
+ '<html><head><meta charset="utf-8">' +
+ "<title>Bug 1224225 - CSP source matching should work for punycoded domain names</title>" +
+ "</head>" +
+ "<body>" +
+ "<script id='script' src='";
+
+// U+00E4 LATIN SMALL LETTER A WITH DIAERESIS, encoded as UTF-8 code units.
+// response.write() writes out the provided string characters truncated to
+// bytes, so "ä" literally would write a literal \xE4 byte, not the desired
+// two-byte UTF-8 sequence.
+const TESTCASE1 = "http://sub2.\xC3\xA4lt.example.org/";
+const TESTCASE2 = "http://sub2.xn--lt-uia.example.org/";
+
+const HTML_PART2 =
+ "tests/dom/security/test/csp/file_punycode_host_src.js'></script>" +
+ "</body>" +
+ "</html>";
+
+function handleRequest(request, response) {
+ // avoid confusing cache behaviors
+ response.setHeader("Cache-Control", "no-cache", false);
+ response.setHeader("Content-Type", "text/html", false);
+
+ Components.utils.importGlobalProperties(["URLSearchParams"]);
+ const query = new URLSearchParams(request.queryString);
+
+ if (query.get("csp")) {
+ response.setHeader("Content-Security-Policy", query.get("csp"), false);
+ }
+ if (query.get("action") == "script-unicode-csp-punycode") {
+ response.write(HTML_PART1 + TESTCASE1 + HTML_PART2);
+ return;
+ }
+ if (query.get("action") == "script-punycode-csp-punycode") {
+ response.write(HTML_PART1 + TESTCASE2 + HTML_PART2);
+ return;
+ }
+
+ // we should never get here, but just in case
+ // return something unexpected
+ response.write("do'h");
+}
diff --git a/dom/security/test/csp/file_redirect_content.sjs b/dom/security/test/csp/file_redirect_content.sjs
new file mode 100644
index 0000000000..f1eab21b08
--- /dev/null
+++ b/dom/security/test/csp/file_redirect_content.sjs
@@ -0,0 +1,41 @@
+// https://bugzilla.mozilla.org/show_bug.cgi?id=650386
+// This SJS file serves file_redirect_content.html
+// with a CSP that will trigger a violation and that will report it
+// to file_redirect_report.sjs
+//
+// This handles 301, 302, 303 and 307 redirects. The HTTP status code
+// returned/type of redirect to do comes from the query string
+// parameter passed in from the test_bug650386_* files and then also
+// uses that value in the report-uri parameter of the CSP
+function handleRequest(request, response) {
+ response.setHeader("Cache-Control", "no-cache", false);
+
+ // this gets used in the CSP as part of the report URI.
+ var redirect = request.queryString;
+
+ if (redirect < 301 || (redirect > 303 && redirect <= 306) || redirect > 307) {
+ // if we somehow got some bogus redirect code here,
+ // do a 302 redirect to the same URL as the report URI
+ // redirects to - this will fail the test.
+ var loc = "http://example.com/some/fake/path";
+ response.setStatusLine("1.1", 302, "Found");
+ response.setHeader("Location", loc, false);
+ return;
+ }
+
+ var csp =
+ "default-src 'self';report-uri http://mochi.test:8888/tests/dom/security/test/csp/file_redirect_report.sjs?" +
+ redirect;
+
+ response.setHeader("Content-Security-Policy", csp, false);
+
+ // the actual file content.
+ // this image load will (intentionally) fail due to the CSP policy of default-src: 'self'
+ // specified by the CSP string above.
+ var content =
+ '<!DOCTYPE HTML><html><body><img src = "http://some.other.domain.example.com"></body></html>';
+
+ response.write(content);
+
+ return;
+}
diff --git a/dom/security/test/csp/file_redirect_report.sjs b/dom/security/test/csp/file_redirect_report.sjs
new file mode 100644
index 0000000000..9cc7e65486
--- /dev/null
+++ b/dom/security/test/csp/file_redirect_report.sjs
@@ -0,0 +1,17 @@
+// https://bugzilla.mozilla.org/show_bug.cgi?id=650386
+// This SJS file serves as CSP violation report target
+// and issues a redirect, to make sure the browser does not post to the target
+// of the redirect, per CSP spec.
+// This handles 301, 302, 303 and 307 redirects. The HTTP status code
+// returned/type of redirect to do comes from the query string
+// parameter
+function handleRequest(request, response) {
+ response.setHeader("Cache-Control", "no-cache", false);
+
+ var redirect = request.queryString;
+
+ var loc = "http://example.com/some/fake/path";
+ response.setStatusLine("1.1", redirect, "Found");
+ response.setHeader("Location", loc, false);
+ return;
+}
diff --git a/dom/security/test/csp/file_redirect_worker.sjs b/dom/security/test/csp/file_redirect_worker.sjs
new file mode 100644
index 0000000000..0c1082021a
--- /dev/null
+++ b/dom/security/test/csp/file_redirect_worker.sjs
@@ -0,0 +1,35 @@
+// SJS file to serve resources for CSP redirect tests
+// This file redirects to a specified resource.
+const THIS_SITE = "http://mochi.test:8888";
+const OTHER_SITE = "http://example.com";
+
+function handleRequest(request, response) {
+ var query = {};
+ request.queryString.split("&").forEach(function (val) {
+ var [name, value] = val.split("=");
+ query[name] = unescape(value);
+ });
+
+ var resource = query.path;
+
+ response.setHeader("Cache-Control", "no-cache", false);
+ var loc = "";
+
+ // redirect to a resource on this site
+ if (query.redir == "same") {
+ loc = THIS_SITE + resource + "#" + query.page_id;
+ }
+
+ // redirect to a resource on a different site
+ else if (query.redir == "other") {
+ loc = OTHER_SITE + resource + "#" + query.page_id;
+ }
+
+ response.setStatusLine("1.1", 302, "Found");
+ response.setHeader("Location", loc, false);
+
+ response.write(
+ '<html><head><meta http-equiv="refresh" content="0; url=' + loc + '">'
+ );
+ return;
+}
diff --git a/dom/security/test/csp/file_redirects_main.html b/dom/security/test/csp/file_redirects_main.html
new file mode 100644
index 0000000000..d05af88fe8
--- /dev/null
+++ b/dom/security/test/csp/file_redirects_main.html
@@ -0,0 +1,37 @@
+<html>
+<head>
+<title>CSP redirect tests</title>
+</head>
+<body>
+<div id="container"></div>
+</body>
+
+<script>
+var thisSite = "http://mochi.test:8888";
+var otherSite = "http://example.com";
+var page = "/tests/dom/security/test/csp/file_redirects_page.sjs";
+
+var tests = { "font-src": thisSite+page+"?testid=font-src",
+ "frame-src": thisSite+page+"?testid=frame-src",
+ "img-src": thisSite+page+"?testid=img-src",
+ "media-src": thisSite+page+"?testid=media-src",
+ "object-src": thisSite+page+"?testid=object-src",
+ "script-src": thisSite+page+"?testid=script-src",
+ "style-src": thisSite+page+"?testid=style-src",
+ "xhr-src": thisSite+page+"?testid=xhr-src",
+ "from-worker": thisSite+page+"?testid=from-worker",
+ "from-blob-worker": thisSite+page+"?testid=from-blob-worker",
+ "img-src-from-css": thisSite+page+"?testid=img-src-from-css",
+ };
+
+var container = document.getElementById("container");
+
+// load each test in its own iframe
+for (tid in tests) {
+ var i = document.createElement("iframe");
+ i.id = tid;
+ i.src = tests[tid];
+ container.appendChild(i);
+}
+</script>
+</html>
diff --git a/dom/security/test/csp/file_redirects_page.sjs b/dom/security/test/csp/file_redirects_page.sjs
new file mode 100644
index 0000000000..31c951cc65
--- /dev/null
+++ b/dom/security/test/csp/file_redirects_page.sjs
@@ -0,0 +1,141 @@
+// SJS file for CSP redirect mochitests
+// This file serves pages which can optionally specify a Content Security Policy
+function handleRequest(request, response) {
+ var query = {};
+ request.queryString.split("&").forEach(function (val) {
+ var [name, value] = val.split("=");
+ query[name] = unescape(value);
+ });
+
+ response.setHeader("Cache-Control", "no-cache", false);
+ response.setHeader("Content-Type", "text/html", false);
+
+ var resource = "/tests/dom/security/test/csp/file_redirects_resource.sjs";
+
+ // CSP header value
+ response.setHeader(
+ "Content-Security-Policy",
+ "default-src 'self' blob: ; style-src 'self' 'unsafe-inline'",
+ false
+ );
+
+ // downloadable font that redirects to another site
+ if (query.testid == "font-src") {
+ var resp =
+ '<style type="text/css"> @font-face { font-family:' +
+ '"Redirecting Font"; src: url("' +
+ resource +
+ '?res=font&redir=other&id=font-src-redir")} #test{font-family:' +
+ '"Redirecting Font"}</style></head><body>' +
+ '<div id="test">test</div></body>';
+ response.write(resp);
+ return;
+ }
+
+ // iframe that redirects to another site
+ if (query.testid == "frame-src") {
+ response.write(
+ '<iframe src="' +
+ resource +
+ '?res=iframe&redir=other&id=frame-src-redir"></iframe>'
+ );
+ return;
+ }
+
+ // image that redirects to another site
+ if (query.testid == "img-src") {
+ response.write(
+ '<img src="' + resource + '?res=image&redir=other&id=img-src-redir" />'
+ );
+ return;
+ }
+
+ // video content that redirects to another site
+ if (query.testid == "media-src") {
+ response.write(
+ '<video src="' +
+ resource +
+ '?res=media&redir=other&id=media-src-redir"></video>'
+ );
+ return;
+ }
+
+ // object content that redirects to another site
+ if (query.testid == "object-src") {
+ response.write(
+ '<object type="text/html" data="' +
+ resource +
+ '?res=object&redir=other&id=object-src-redir"></object>'
+ );
+ return;
+ }
+
+ // external script that redirects to another site
+ if (query.testid == "script-src") {
+ response.write(
+ '<script src="' +
+ resource +
+ '?res=script&redir=other&id=script-src-redir"></script>'
+ );
+ return;
+ }
+
+ // external stylesheet that redirects to another site
+ if (query.testid == "style-src") {
+ response.write(
+ '<link rel="stylesheet" type="text/css" href="' +
+ resource +
+ '?res=style&redir=other&id=style-src-redir"></link>'
+ );
+ return;
+ }
+
+ // script that XHR's to a resource that redirects to another site
+ if (query.testid == "xhr-src") {
+ response.write('<script src="' + resource + '?res=xhr"></script>');
+ return;
+ }
+
+ // for bug949706
+ if (query.testid == "img-src-from-css") {
+ // loads a stylesheet, which in turn loads an image that redirects.
+ response.write(
+ '<link rel="stylesheet" type="text/css" href="' +
+ resource +
+ '?res=cssLoader&id=img-src-redir-from-css">'
+ );
+ return;
+ }
+
+ if (query.testid == "from-worker") {
+ // loads a script; launches a worker; that worker uses importscript; which then gets redirected
+ // So it's:
+ // <script src="res=loadWorkerThatMakesRequests">
+ // .. loads Worker("res=makeRequestsWorker")
+ // .. calls importScript("res=script")
+ // .. calls xhr("res=xhr-resp")
+ // .. calls fetch("res=xhr-resp")
+ response.write(
+ '<script src="' +
+ resource +
+ '?res=loadWorkerThatMakesRequests&id=from-worker"></script>'
+ );
+ return;
+ }
+
+ if (query.testid == "from-blob-worker") {
+ // loads a script; launches a worker; that worker uses importscript; which then gets redirected
+ // So it's:
+ // <script src="res=loadBlobWorkerThatMakesRequests">
+ // .. loads Worker("res=makeRequestsWorker")
+ // .. calls importScript("res=script")
+ // .. calls xhr("res=xhr-resp")
+ // .. calls fetch("res=xhr-resp")
+ response.write(
+ '<script src="' +
+ resource +
+ '?res=loadBlobWorkerThatMakesRequests&id=from-blob-worker"></script>'
+ );
+ return;
+ }
+}
diff --git a/dom/security/test/csp/file_redirects_resource.sjs b/dom/security/test/csp/file_redirects_resource.sjs
new file mode 100644
index 0000000000..66551970c8
--- /dev/null
+++ b/dom/security/test/csp/file_redirects_resource.sjs
@@ -0,0 +1,172 @@
+// SJS file to serve resources for CSP redirect tests
+// This file mimics serving resources, e.g. fonts, images, etc., which a CSP
+// can include. The resource may redirect to a different resource, if specified.
+function handleRequest(request, response) {
+ var query = {};
+ request.queryString.split("&").forEach(function (val) {
+ var [name, value] = val.split("=");
+ query[name] = unescape(value);
+ });
+
+ var thisSite = "http://mochi.test:8888";
+ var otherSite = "http://example.com";
+ var resource = "/tests/dom/security/test/csp/file_redirects_resource.sjs";
+
+ response.setHeader("Cache-Control", "no-cache", false);
+
+ // redirect to a resource on this site
+ if (query.redir == "same") {
+ var loc = thisSite + resource + "?res=" + query.res + "&testid=" + query.id;
+ response.setStatusLine("1.1", 302, "Found");
+ response.setHeader("Location", loc, false);
+ return;
+ }
+
+ // redirect to a resource on a different site
+ else if (query.redir == "other") {
+ var loc =
+ otherSite + resource + "?res=" + query.res + "&testid=" + query.id;
+ response.setStatusLine("1.1", 302, "Found");
+ response.setHeader("Location", loc, false);
+ return;
+ }
+
+ // not a redirect. serve some content.
+ // the content doesn't have to be valid, since we're only checking whether
+ // the request for the content was sent or not.
+
+ // downloadable font
+ if (query.res == "font") {
+ response.setHeader("Access-Control-Allow-Origin", "*", false);
+ response.setHeader("Content-Type", "text/plain", false);
+ response.write("font data...");
+ return;
+ }
+
+ // iframe with arbitrary content
+ if (query.res == "iframe") {
+ response.setHeader("Content-Type", "text/html", false);
+ response.write("iframe content...");
+ return;
+ }
+
+ // image
+ if (query.res == "image") {
+ response.setHeader("Content-Type", "image/gif", false);
+ response.write("image data...");
+ return;
+ }
+
+ // media content, e.g. Ogg video
+ if (query.res == "media") {
+ response.setHeader("Content-Type", "video/ogg", false);
+ response.write("video data...");
+ return;
+ }
+
+ // plugin content, e.g. <object>
+ if (query.res == "object") {
+ response.setHeader("Content-Type", "text/html", false);
+ response.write("object data...");
+ return;
+ }
+
+ // script
+ if (query.res == "script") {
+ response.setHeader("Content-Type", "application/javascript", false);
+ response.write("some script...");
+ return;
+ }
+
+ // external stylesheet
+ if (query.res == "style") {
+ response.setHeader("Content-Type", "text/css", false);
+ response.write("css data...");
+ return;
+ }
+
+ // internal stylesheet that loads an image from an external site
+ if (query.res == "cssLoader") {
+ let bgURL = thisSite + resource + "?redir=other&res=image&id=" + query.id;
+ response.setHeader("Content-Type", "text/css", false);
+ response.write("body { background:url('" + bgURL + "'); }");
+ return;
+ }
+
+ // script that loads an internal worker that uses importScripts on a redirect
+ // to an external script.
+ if (query.res == "loadWorkerThatMakesRequests") {
+ // this creates a worker (same origin) that imports a redirecting script.
+ let workerURL =
+ thisSite + resource + "?res=makeRequestsWorker&id=" + query.id;
+ response.setHeader("Content-Type", "application/javascript", false);
+ response.write("new Worker('" + workerURL + "');");
+ return;
+ }
+
+ // script that loads an internal worker that uses importScripts on a redirect
+ // to an external script.
+ if (query.res == "loadBlobWorkerThatMakesRequests") {
+ // this creates a worker (same origin) that imports a redirecting script.
+ let workerURL =
+ thisSite + resource + "?res=makeRequestsWorker&id=" + query.id;
+ response.setHeader("Content-Type", "application/javascript", false);
+ response.write(
+ "var x = new XMLHttpRequest(); x.open('GET', '" + workerURL + "'); "
+ );
+ response.write("x.responseType = 'blob'; x.send(); ");
+ response.write(
+ "x.onload = () => { new Worker(URL.createObjectURL(x.response)); };"
+ );
+ return;
+ }
+
+ // source for a worker that simply calls importScripts on a script that
+ // redirects.
+ if (query.res == "makeRequestsWorker") {
+ // this is code for a worker that imports a redirected script.
+ let scriptURL =
+ thisSite +
+ resource +
+ "?redir=other&res=script&id=script-src-redir-" +
+ query.id;
+ let xhrURL =
+ thisSite +
+ resource +
+ "?redir=other&res=xhr-resp&id=xhr-src-redir-" +
+ query.id;
+ let fetchURL =
+ thisSite +
+ resource +
+ "?redir=other&res=xhr-resp&id=fetch-src-redir-" +
+ query.id;
+ response.setHeader("Content-Type", "application/javascript", false);
+ response.write("try { importScripts('" + scriptURL + "'); } catch(ex) {} ");
+ response.write(
+ "var x = new XMLHttpRequest(); x.open('GET', '" + xhrURL + "'); x.send();"
+ );
+ response.write("fetch('" + fetchURL + "');");
+ return;
+ }
+
+ // script that invokes XHR
+ if (query.res == "xhr") {
+ response.setHeader("Content-Type", "application/javascript", false);
+ var resp =
+ 'var x = new XMLHttpRequest();x.open("GET", "' +
+ thisSite +
+ resource +
+ '?redir=other&res=xhr-resp&id=xhr-src-redir", false);\n' +
+ "x.send(null);";
+ response.write(resp);
+ return;
+ }
+
+ // response to XHR
+ if (query.res == "xhr-resp") {
+ response.setHeader("Access-Control-Allow-Origin", "*", false);
+ response.setHeader("Content-Type", "text/html", false);
+ response.write("XHR response...");
+ return;
+ }
+}
diff --git a/dom/security/test/csp/file_report.html b/dom/security/test/csp/file_report.html
new file mode 100644
index 0000000000..fb18af8057
--- /dev/null
+++ b/dom/security/test/csp/file_report.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title>Bug 1033424 - Test csp-report properties </title>
+ </head>
+ <body>
+ <script type="text/javascript">
+ var foo = "propEscFoo";
+ var bar = "propEscBar";
+ // just verifying that we properly escape newlines and quotes
+ </script>
+</body>
+</html>
diff --git a/dom/security/test/csp/file_report_chromescript.js b/dom/security/test/csp/file_report_chromescript.js
new file mode 100644
index 0000000000..56364605dc
--- /dev/null
+++ b/dom/security/test/csp/file_report_chromescript.js
@@ -0,0 +1,65 @@
+/* eslint-env mozilla/chrome-script */
+
+const { NetUtil } = ChromeUtils.import("resource://gre/modules/NetUtil.jsm");
+
+Cu.importGlobalProperties(["TextDecoder"]);
+
+const reportURI = "http://mochi.test:8888/foo.sjs";
+
+var openingObserver = {
+ observe(subject, topic, data) {
+ // subject should be an nsURI
+ if (subject.QueryInterface == undefined) {
+ return;
+ }
+
+ var message = { report: "", error: false };
+
+ if (topic == "http-on-opening-request") {
+ var asciiSpec = subject.QueryInterface(Ci.nsIHttpChannel).URI.asciiSpec;
+ if (asciiSpec !== reportURI) {
+ return;
+ }
+
+ var reportText = false;
+ try {
+ // Verify that the report was properly formatted.
+ // We'll parse the report text as JSON and verify that the properties
+ // have expected values.
+ var reportText = "{}";
+ var uploadStream = subject.QueryInterface(
+ Ci.nsIUploadChannel
+ ).uploadStream;
+
+ if (uploadStream) {
+ // get the bytes from the request body
+ var binstream = Cc["@mozilla.org/binaryinputstream;1"].createInstance(
+ Ci.nsIBinaryInputStream
+ );
+ binstream.setInputStream(uploadStream);
+
+ let bytes = NetUtil.readInputStream(binstream);
+
+ // rewind stream as we are supposed to - there will be an assertion later if we don't.
+ uploadStream
+ .QueryInterface(Ci.nsISeekableStream)
+ .seek(Ci.nsISeekableStream.NS_SEEK_SET, 0);
+
+ let textDecoder = new TextDecoder();
+ reportText = textDecoder.decode(bytes);
+ }
+
+ message.report = reportText;
+ } catch (e) {
+ message.error = e.toString();
+ }
+
+ sendAsyncMessage("opening-request-completed", message);
+ }
+ },
+};
+
+Services.obs.addObserver(openingObserver, "http-on-opening-request");
+addMessageListener("finish", function () {
+ Services.obs.removeObserver(openingObserver, "http-on-opening-request");
+});
diff --git a/dom/security/test/csp/file_report_font_cache-1.html b/dom/security/test/csp/file_report_font_cache-1.html
new file mode 100644
index 0000000000..59b4908f83
--- /dev/null
+++ b/dom/security/test/csp/file_report_font_cache-1.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<style>
+@font-face {
+ font-family: "CSP Report Test Font 1";
+ src: url(Ahem.ttf?report_font_cache-1);
+}
+@font-face {
+ font-family: "CSP Report Test Font 2";
+ src: url(Ahem.ttf?report_font_cache-2);
+}
+@font-face {
+ font-family: "CSP Report Test Font 3";
+ src: url(Ahem.ttf?report_font_cache-3);
+}
+.x { font: 24px "CSP Report Test Font 1"; }
+.y { font: 24px "CSP Report Test Font 2"; }
+.z { font: 24px "CSP Report Test Font 3"; }
+</style>
+<p class=x>A</p>
+<p class=y>A</p>
+<p class=z>A</p>
+<script>
+// Wait until the fonts would have been added to the user font cache.
+document.body.offsetWidth;
+document.fonts.ready.then(() => window.parent.postMessage("first-doc-ready", "*"));
+</script>
diff --git a/dom/security/test/csp/file_report_font_cache-2.html b/dom/security/test/csp/file_report_font_cache-2.html
new file mode 100644
index 0000000000..cea9cea663
--- /dev/null
+++ b/dom/security/test/csp/file_report_font_cache-2.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<style>
+@font-face {
+ font-family: "CSP Report Test Font 1";
+ src: url(Ahem.ttf?report_font_cache-1);
+}
+@font-face {
+ font-family: "CSP Report Test Font 3";
+ src: url(Ahem.ttf?report_font_cache-3);
+}
+p { margin-right: 1ex; } /* cause cached CSP check to happen OMT (due to
+ font metrics lookup) */
+.x { font: 24px "CSP Report Test Font 1"; }
+.y { font: 24px "CSP Report Test Font 3"; }
+</style>
+<p class="x">A</p>
+<script>
+// First flush should dispatch the "Test Font 1" report that is stored
+// in the user font cache.
+document.body.offsetWidth;
+
+// Second flush should dispatch "Test Font 3" report.
+document.querySelector("p").className = "y";
+document.body.offsetWidth;
+</script>
diff --git a/dom/security/test/csp/file_report_font_cache-2.html^headers^ b/dom/security/test/csp/file_report_font_cache-2.html^headers^
new file mode 100644
index 0000000000..493f850baa
--- /dev/null
+++ b/dom/security/test/csp/file_report_font_cache-2.html^headers^
@@ -0,0 +1 @@
+Content-Security-Policy: font-src 'none'; report-uri http://mochi.test:8888/foo.sjs
diff --git a/dom/security/test/csp/file_report_for_import.css b/dom/security/test/csp/file_report_for_import.css
new file mode 100644
index 0000000000..b578b77b33
--- /dev/null
+++ b/dom/security/test/csp/file_report_for_import.css
@@ -0,0 +1 @@
+@import url("http://example.com/tests/dom/security/test/csp/file_report_for_import_server.sjs?stylesheet");
diff --git a/dom/security/test/csp/file_report_for_import.html b/dom/security/test/csp/file_report_for_import.html
new file mode 100644
index 0000000000..77a36faea1
--- /dev/null
+++ b/dom/security/test/csp/file_report_for_import.html
@@ -0,0 +1,10 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title>Bug 1048048 - Test sending csp-report when using import in css</title>
+ <link rel="stylesheet" type="text/css" href="file_report_for_import.css">
+ </head>
+ <body>
+ empty body, just testing @import in the included css for bug 1048048
+</body>
+</html>
diff --git a/dom/security/test/csp/file_report_for_import_server.sjs b/dom/security/test/csp/file_report_for_import_server.sjs
new file mode 100644
index 0000000000..624c7e657b
--- /dev/null
+++ b/dom/security/test/csp/file_report_for_import_server.sjs
@@ -0,0 +1,50 @@
+// Custom *.sjs file specifically for the needs of Bug:
+// Bug 1048048 - CSP violation report not sent for @import
+
+const CC = Components.Constructor;
+const BinaryInputStream = CC(
+ "@mozilla.org/binaryinputstream;1",
+ "nsIBinaryInputStream",
+ "setInputStream"
+);
+
+function handleRequest(request, response) {
+ // avoid confusing cache behaviors
+ response.setHeader("Cache-Control", "no-cache", false);
+ response.setHeader("Content-Type", "text/html", false);
+ var queryString = request.queryString;
+
+ // (1) lets process the queryresult request async and
+ // wait till we have received the image request.
+ if (queryString === "queryresult") {
+ response.processAsync();
+ setObjectState("queryResult", response);
+ return;
+ }
+
+ // (2) handle the csp-report and return the JSON back to
+ // the testfile using the afore stored xml request in (1).
+ if (queryString === "report") {
+ getObjectState("queryResult", function (queryResponse) {
+ if (!queryResponse) {
+ return;
+ }
+
+ // send the report back to the XML request for verification
+ var report = new BinaryInputStream(request.bodyInputStream);
+ var avail;
+ var bytes = [];
+ while ((avail = report.available()) > 0) {
+ Array.prototype.push.apply(bytes, report.readByteArray(avail));
+ }
+ var data = String.fromCharCode.apply(null, bytes);
+ queryResponse.bodyOutputStream.write(data, data.length);
+ queryResponse.finish();
+ });
+ return;
+ }
+
+ // we should not get here ever, but just in case return
+ // something unexpected.
+ response.write("doh!");
+}
diff --git a/dom/security/test/csp/file_report_uri_missing_in_report_only_header.html b/dom/security/test/csp/file_report_uri_missing_in_report_only_header.html
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/dom/security/test/csp/file_report_uri_missing_in_report_only_header.html
diff --git a/dom/security/test/csp/file_report_uri_missing_in_report_only_header.html^headers^ b/dom/security/test/csp/file_report_uri_missing_in_report_only_header.html^headers^
new file mode 100644
index 0000000000..3f2fdfe9e6
--- /dev/null
+++ b/dom/security/test/csp/file_report_uri_missing_in_report_only_header.html^headers^
@@ -0,0 +1 @@
+Content-Security-Policy-Report-Only: default-src 'self';
diff --git a/dom/security/test/csp/file_ro_ignore_xfo.html b/dom/security/test/csp/file_ro_ignore_xfo.html
new file mode 100644
index 0000000000..85e7f0092c
--- /dev/null
+++ b/dom/security/test/csp/file_ro_ignore_xfo.html
@@ -0,0 +1,10 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Bug 1024557: Ignore x-frame-options if CSP with frame-ancestors exists</title>
+</head>
+<body>
+<div id="cspmessage">Ignoring XFO because of CSP_RO</div>
+</body>
+</html> \ No newline at end of file
diff --git a/dom/security/test/csp/file_ro_ignore_xfo.html^headers^ b/dom/security/test/csp/file_ro_ignore_xfo.html^headers^
new file mode 100644
index 0000000000..ab8366f061
--- /dev/null
+++ b/dom/security/test/csp/file_ro_ignore_xfo.html^headers^
@@ -0,0 +1,3 @@
+Content-Security-Policy-Report-Only: frame-ancestors http://mochi.test:8888
+X-Frame-Options: deny
+Cache-Control: no-cache
diff --git a/dom/security/test/csp/file_sandbox_1.html b/dom/security/test/csp/file_sandbox_1.html
new file mode 100644
index 0000000000..ce1e80c865
--- /dev/null
+++ b/dom/security/test/csp/file_sandbox_1.html
@@ -0,0 +1,16 @@
+<html>
+<head> <meta charset="utf-8"> </head>
+ <body>
+ <!-- sandbox="allow-same-origin" -->
+ <!-- Content-Security-Policy: default-src 'self' -->
+
+ <!-- these should be stopped by CSP -->
+ <img src="http://example.org/tests/dom/security/test/csp/file_CSP.sjs?testid=img1_bad&type=img/png"> </img>
+
+ <!-- these should load ok -->
+ <img src="/tests/dom/security/test/csp/file_CSP.sjs?testid=img1a_good&type=img/png" />
+ <!-- should not execute script -->
+ <script src='/tests/dom/security/test/csp/file_sandbox_fail.js'></script>
+
+ </body>
+</html>
diff --git a/dom/security/test/csp/file_sandbox_10.html b/dom/security/test/csp/file_sandbox_10.html
new file mode 100644
index 0000000000..f934497eee
--- /dev/null
+++ b/dom/security/test/csp/file_sandbox_10.html
@@ -0,0 +1,12 @@
+<html>
+<head> <meta charset="utf-8"> </head>
+ <body>
+ <!-- Content-Security-Policy: default-src 'none'; sandbox -->
+
+ <!-- these should be stopped by CSP -->
+ <img src="http://example.org/tests/dom/security/test/csp/file_CSP.sjs?testid=img10_bad&type=img/png"> </img>
+ <img src="/tests/dom/security/test/csp/file_CSP.sjs?testid=img10a_bad&type=img/png" />
+ <script src='/tests/dom/security/test/csp/file_sandbox_fail.js'></script>
+
+ </body>
+</html>
diff --git a/dom/security/test/csp/file_sandbox_11.html b/dom/security/test/csp/file_sandbox_11.html
new file mode 100644
index 0000000000..087b5651a9
--- /dev/null
+++ b/dom/security/test/csp/file_sandbox_11.html
@@ -0,0 +1,25 @@
+<!DOCTYPE HTML>
+<html>
+<head> <meta charset="utf-8"> </head>
+<script type="text/javascript">
+ function ok(result, desc) {
+ window.parent.postMessage({ok: result, desc}, "*");
+ }
+
+ function doStuff() {
+ ok(true, "documents sandboxed with allow-scripts should be able to run inline scripts");
+ }
+</script>
+<script src='file_sandbox_fail.js'></script>
+<body onLoad='ok(true, "documents sandboxed with allow-scripts should be able to run script from event listeners");doStuff();'>
+ I am sandboxed but with only inline "allow-scripts"
+
+ <!-- Content-Security-Policy: default-src 'none'; script-src 'unsafe-inline'; sandbox allow-scripts -->
+
+ <!-- these should be stopped by CSP -->
+ <img src="/tests/dom/security/test/csp/file_CSP.sjs?testid=img11_bad&type=img/png" />
+ <img src="http://example.org/tests/dom/security/test/csp/file_CSP.sjs?testid=img11a_bad&type=img/png"> </img>
+ <script src='/tests/dom/security/test/csp/file_CSP.sjs?testid=script11_bad&type=text/javascript'></script>
+ <script src='http://example.org/tests/dom/security/test/csp/file_CSP.sjs?testid=script11a_bad&type=text/javascript'></script>
+</body>
+</html>
diff --git a/dom/security/test/csp/file_sandbox_12.html b/dom/security/test/csp/file_sandbox_12.html
new file mode 100644
index 0000000000..79631bd394
--- /dev/null
+++ b/dom/security/test/csp/file_sandbox_12.html
@@ -0,0 +1,40 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+</head>
+<script type="text/javascript">
+ function ok(result, desc) {
+ window.parent.postMessage({ok: result, desc}, "*");
+ }
+
+ function doStuff() {
+ ok(true, "documents sandboxed with allow-scripts should be able to run inline scripts");
+
+ document.getElementById('a_form').submit();
+
+ // trigger the javascript: url test
+ sendMouseEvent({type:'click'}, 'a_link');
+ }
+</script>
+<script src='file_sandbox_pass.js'></script>
+<body onLoad='ok(true, "documents sandboxed with allow-scripts should be able to run script from event listeners");doStuff();'>
+ I am sandboxed but with "allow-same-origin" and allow-scripts"
+
+
+ <!-- Content-Security-Policy: sandbox allow-same-origin allow-scripts; default-src 'self' 'unsafe-inline'; -->
+
+ <!-- these should be stopped by CSP -->
+ <img src="http://example.org/tests/dom/security/test/csp/file_CSP.sjs?testid=img12_bad&type=img/png"> </img>
+ <script src='http://example.org/tests/dom/security/test/csp/file_CSP.sjs?testid=script12_bad&type=text/javascript'></script>
+
+ <form method="get" action="/tests/content/html/content/test/file_iframe_sandbox_form_fail.html" id="a_form">
+ First name: <input type="text" name="firstname">
+ Last name: <input type="text" name="lastname">
+ <input type="submit" onclick="doSubmit()" id="a_button">
+ </form>
+
+ <a href = 'javascript:ok(true, "documents sandboxed with allow-scripts should be able to run script from javascript: URLs");' id='a_link'>click me</a>
+</body>
+</html>
diff --git a/dom/security/test/csp/file_sandbox_13.html b/dom/security/test/csp/file_sandbox_13.html
new file mode 100644
index 0000000000..96286db8d5
--- /dev/null
+++ b/dom/security/test/csp/file_sandbox_13.html
@@ -0,0 +1,25 @@
+<!DOCTYPE HTML>
+<html>
+<head> <meta charset="utf-8"> </head>
+<script type="text/javascript">
+ function ok(result, desc) {
+ window.parent.postMessage({ok: result, desc}, "*");
+ }
+
+ function doStuff() {
+ ok(true, "documents sandboxed with allow-scripts should be able to run inline scripts");
+ }
+</script>
+<script src='file_sandbox_fail.js'></script>
+<body onLoad='ok(true, "documents sandboxed with allow-scripts should be able to run script from event listeners");doStuff();'>
+ I am sandboxed but with only inline "allow-scripts"
+
+ <!-- Content-Security-Policy: default-src 'none'; script-src 'unsafe-inline'; sandbox allow-scripts -->
+
+ <!-- these should be stopped by CSP -->
+ <img src="/tests/dom/security/test/csp/file_CSP.sjs?testid=img13_bad&type=img/png" />
+ <img src="http://example.org/tests/dom/security/test/csp/file_CSP.sjs?testid=img13a_bad&type=img/png"> </img>
+ <script src='/tests/dom/security/test/csp/file_CSP.sjs?testid=script13_bad&type=text/javascript'></script>
+ <script src='http://example.org/tests/dom/security/test/csp/file_CSP.sjs?testid=script13a_bad&type=text/javascript'></script>
+</body>
+</html>
diff --git a/dom/security/test/csp/file_sandbox_2.html b/dom/security/test/csp/file_sandbox_2.html
new file mode 100644
index 0000000000..b37aa1bcef
--- /dev/null
+++ b/dom/security/test/csp/file_sandbox_2.html
@@ -0,0 +1,16 @@
+<html>
+<head> <meta charset="utf-8"> </head>
+ <body>
+ <!-- sandbox -->
+ <!-- Content-Security-Policy: default-src 'self' -->
+
+ <!-- these should be stopped by CSP -->
+ <img src="http://example.org/tests/dom/security/test/csp/file_CSP.sjs?testid=img2_bad&type=img/png"> </img>
+
+ <!-- these should load ok -->
+ <img src="/tests/dom/security/test/csp/file_CSP.sjs?testid=img2a_good&type=img/png" />
+ <!-- should not execute script -->
+ <script src='/tests/dom/security/test/csp/file_sandbox_fail.js'></script>
+
+ </body>
+</html>
diff --git a/dom/security/test/csp/file_sandbox_3.html b/dom/security/test/csp/file_sandbox_3.html
new file mode 100644
index 0000000000..ba808e47d5
--- /dev/null
+++ b/dom/security/test/csp/file_sandbox_3.html
@@ -0,0 +1,13 @@
+<html>
+<head> <meta charset="utf-8"> </head>
+ <body>
+ <!-- sandbox="allow-same-origin" -->
+ <!-- Content-Security-Policy: default-src 'none' -->
+
+ <!-- these should be stopped by CSP -->
+ <img src="http://example.org/tests/dom/security/test/csp/file_CSP.sjs?testid=img3_bad&type=img/png"> </img>
+ <img src="/tests/dom/security/test/csp/file_CSP.sjs?testid=img3a_bad&type=img/png" />
+ <script src='/tests/dom/security/test/csp/file_sandbox_fail.js'></script>
+
+ </body>
+</html>
diff --git a/dom/security/test/csp/file_sandbox_4.html b/dom/security/test/csp/file_sandbox_4.html
new file mode 100644
index 0000000000..b2d4ed0940
--- /dev/null
+++ b/dom/security/test/csp/file_sandbox_4.html
@@ -0,0 +1,13 @@
+<html>
+<head> <meta charset="utf-8"> </head>
+ <body>
+ <!-- sandbox -->
+ <!-- Content-Security-Policy: default-src 'none' -->
+
+ <!-- these should be stopped by CSP -->
+ <img src="http://example.org/tests/dom/base/test/csp/file_CSP.sjs?testid=img4_bad&type=img/png"> </img>
+ <img src="/tests/dom/base/test/csp/file_CSP.sjs?testid=img4a_bad&type=img/png" />
+ <script src='/tests/dom/base/test/csp/file_sandbox_fail.js'></script>
+
+ </body>
+</html>
diff --git a/dom/security/test/csp/file_sandbox_5.html b/dom/security/test/csp/file_sandbox_5.html
new file mode 100644
index 0000000000..c08849b689
--- /dev/null
+++ b/dom/security/test/csp/file_sandbox_5.html
@@ -0,0 +1,26 @@
+<!DOCTYPE HTML>
+<html>
+<head> <meta charset="utf-8"> </head>
+<script type="text/javascript">
+ function ok(result, desc) {
+ window.parent.postMessage({ok: result, desc}, "*");
+ }
+
+ function doStuff() {
+ ok(true, "documents sandboxed with allow-scripts should be able to run inline scripts");
+ }
+</script>
+<script src='file_sandbox_fail.js'></script>
+<body onLoad='ok(true, "documents sandboxed with allow-scripts should be able to run script from event listeners");doStuff();'>
+ I am sandboxed but with only inline "allow-scripts"
+
+ <!-- sandbox="allow-scripts" -->
+ <!-- Content-Security-Policy: default-src 'none'; script-src 'unsafe-inline' -->
+
+ <!-- these should be stopped by CSP -->
+ <img src="/tests/dom/security/test/csp/file_CSP.sjs?testid=img5_bad&type=img/png" />
+ <img src="http://example.org/tests/dom/security/test/csp/file_CSP.sjs?testid=img5a_bad&type=img/png"> </img>
+ <script src='/tests/dom/security/test/csp/file_CSP.sjs?testid=script5_bad&type=text/javascript'></script>
+ <script src='http://example.org/tests/dom/security/test/csp/file_CSP.sjs?testid=script5a_bad&type=text/javascript'></script>
+</body>
+</html>
diff --git a/dom/security/test/csp/file_sandbox_6.html b/dom/security/test/csp/file_sandbox_6.html
new file mode 100644
index 0000000000..44705f4d2b
--- /dev/null
+++ b/dom/security/test/csp/file_sandbox_6.html
@@ -0,0 +1,35 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+</head>
+<script type="text/javascript">
+ function ok(result, desc) {
+ window.parent.postMessage({ok: result, desc}, "*");
+ }
+
+ function doStuff() {
+ ok(true, "documents sandboxed with allow-scripts should be able to run inline scripts");
+
+ document.getElementById('a_form').submit();
+
+ // trigger the javascript: url test
+ sendMouseEvent({type:'click'}, 'a_link');
+ }
+</script>
+<script src='file_sandbox_pass.js'></script>
+<body onLoad='ok(true, "documents sandboxed with allow-scripts should be able to run script from event listeners");doStuff();'>
+ I am sandboxed but with "allow-same-origin" and allow-scripts"
+ <img src="http://example.org/tests/dom/security/test/csp/file_CSP.sjs?testid=img6_bad&type=img/png"> </img>
+ <script src='http://example.org/tests/dom/security/test/csp/file_CSP.sjs?testid=script6_bad&type=text/javascript'></script>
+
+ <form method="get" action="/tests/content/html/content/test/file_iframe_sandbox_form_fail.html" id="a_form">
+ First name: <input type="text" name="firstname">
+ Last name: <input type="text" name="lastname">
+ <input type="submit" onclick="doSubmit()" id="a_button">
+ </form>
+
+ <a href = 'javascript:ok(true, "documents sandboxed with allow-scripts should be able to run script from javascript: URLs");' id='a_link'>click me</a>
+</body>
+</html>
diff --git a/dom/security/test/csp/file_sandbox_7.html b/dom/security/test/csp/file_sandbox_7.html
new file mode 100644
index 0000000000..3b249d4101
--- /dev/null
+++ b/dom/security/test/csp/file_sandbox_7.html
@@ -0,0 +1,15 @@
+<html>
+<head> <meta charset="utf-8"> </head>
+ <body>
+ <!-- Content-Security-Policy: default-src 'self'; sandbox allow-same-origin -->
+
+ <!-- these should be stopped by CSP -->
+ <img src="http://example.org/tests/dom/security/test/csp/file_CSP.sjs?testid=img7_bad&type=img/png"> </img>
+
+ <!-- these should load ok -->
+ <img src="/tests/dom/security/test/csp/file_CSP.sjs?testid=img7a_good&type=img/png" />
+ <!-- should not execute script -->
+ <script src='/tests/dom/security/test/csp/file_sandbox_fail.js'></script>
+
+ </body>
+</html>
diff --git a/dom/security/test/csp/file_sandbox_8.html b/dom/security/test/csp/file_sandbox_8.html
new file mode 100644
index 0000000000..4f9cd89161
--- /dev/null
+++ b/dom/security/test/csp/file_sandbox_8.html
@@ -0,0 +1,15 @@
+<html>
+<head> <meta charset="utf-8"> </head>
+ <body>
+ <!-- Content-Security-Policy: sandbox; default-src 'self' -->
+
+ <!-- these should be stopped by CSP -->
+ <img src="http://example.org/tests/dom/security/test/csp/file_CSP.sjs?testid=img8_bad&type=img/png"> </img>
+
+ <!-- these should load ok -->
+ <img src="/tests/dom/security/test/csp/file_CSP.sjs?testid=img8a_good&type=img/png" />
+ <!-- should not execute script -->
+ <script src='/tests/dom/security/test/csp/file_sandbox_fail.js'></script>
+
+ </body>
+</html>
diff --git a/dom/security/test/csp/file_sandbox_9.html b/dom/security/test/csp/file_sandbox_9.html
new file mode 100644
index 0000000000..29ffc191cd
--- /dev/null
+++ b/dom/security/test/csp/file_sandbox_9.html
@@ -0,0 +1,12 @@
+<html>
+<head> <meta charset="utf-8"> </head>
+ <body>
+ <!-- Content-Security-Policy: default-src 'none'; sandbox allow-same-origin -->
+
+ <!-- these should be stopped by CSP -->
+ <img src="http://example.org/tests/dom/security/test/csp/file_CSP.sjs?testid=img9_bad&type=img/png"> </img>
+ <img src="/tests/dom/security/test/csp/file_CSP.sjs?testid=img9a_bad&type=img/png" />
+
+ <script src='/tests/dom/security/test/csp/file_sandbox_fail.js'></script>
+ </body>
+</html>
diff --git a/dom/security/test/csp/file_sandbox_allow_scripts.html b/dom/security/test/csp/file_sandbox_allow_scripts.html
new file mode 100644
index 0000000000..faab9f0fc6
--- /dev/null
+++ b/dom/security/test/csp/file_sandbox_allow_scripts.html
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <meta charset='utf-8'>
+ <title>Bug 1396320: Fix CSP sandbox regression for allow-scripts</title>
+ </head>
+<body>
+<script type='application/javascript'>
+ window.parent.postMessage({result: document.domain }, '*');
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/file_sandbox_allow_scripts.html^headers^ b/dom/security/test/csp/file_sandbox_allow_scripts.html^headers^
new file mode 100644
index 0000000000..4705ce9ded
--- /dev/null
+++ b/dom/security/test/csp/file_sandbox_allow_scripts.html^headers^
@@ -0,0 +1 @@
+Content-Security-Policy: sandbox allow-scripts;
diff --git a/dom/security/test/csp/file_sandbox_fail.js b/dom/security/test/csp/file_sandbox_fail.js
new file mode 100644
index 0000000000..7f43927ddf
--- /dev/null
+++ b/dom/security/test/csp/file_sandbox_fail.js
@@ -0,0 +1,7 @@
+function ok(result, desc) {
+ window.parent.postMessage({ ok: result, desc }, "*");
+}
+ok(
+ false,
+ "documents sandboxed with allow-scripts should NOT be able to run <script src=...>"
+);
diff --git a/dom/security/test/csp/file_sandbox_pass.js b/dom/security/test/csp/file_sandbox_pass.js
new file mode 100644
index 0000000000..c06341a082
--- /dev/null
+++ b/dom/security/test/csp/file_sandbox_pass.js
@@ -0,0 +1,7 @@
+function ok(result, desc) {
+ window.parent.postMessage({ ok: result, desc }, "*");
+}
+ok(
+ true,
+ "documents sandboxed with allow-scripts should be able to run <script src=...>"
+);
diff --git a/dom/security/test/csp/file_scheme_relative_sources.js b/dom/security/test/csp/file_scheme_relative_sources.js
new file mode 100644
index 0000000000..09286d42e9
--- /dev/null
+++ b/dom/security/test/csp/file_scheme_relative_sources.js
@@ -0,0 +1 @@
+document.getElementById("testdiv").innerHTML = "allowed";
diff --git a/dom/security/test/csp/file_scheme_relative_sources.sjs b/dom/security/test/csp/file_scheme_relative_sources.sjs
new file mode 100644
index 0000000000..c32f773484
--- /dev/null
+++ b/dom/security/test/csp/file_scheme_relative_sources.sjs
@@ -0,0 +1,45 @@
+/**
+ * Custom *.sjs specifically for the needs of
+ * Bug 921493 - CSP: test allowlisting of scheme-relative sources
+ */
+
+function handleRequest(request, response) {
+ Components.utils.importGlobalProperties(["URLSearchParams"]);
+ let query = new URLSearchParams(request.queryString);
+
+ let scheme = query.get("scheme");
+ let policy = query.get("policy");
+
+ let linkUrl =
+ scheme +
+ "://example.com/tests/dom/security/test/csp/file_scheme_relative_sources.js";
+
+ let html =
+ "<!DOCTYPE HTML>" +
+ "<html>" +
+ "<head>" +
+ "<title>test schemeless sources within CSP</title>" +
+ "</head>" +
+ "<body> " +
+ "<div id='testdiv'>blocked</div>" +
+ // try to load a scheme relative script
+ "<script src='" +
+ linkUrl +
+ "'></script>" +
+ // have an inline script that reports back to the parent whether
+ // the script got loaded or not from within the sandboxed iframe.
+ "<script type='application/javascript'>" +
+ "window.onload = function() {" +
+ "var inner = document.getElementById('testdiv').innerHTML;" +
+ "window.parent.postMessage({ result: inner }, '*');" +
+ "}" +
+ "</script>" +
+ "</body>" +
+ "</html>";
+
+ response.setHeader("Cache-Control", "no-cache", false);
+ response.setHeader("Content-Type", "text/html", false);
+ response.setHeader("Content-Security-Policy", policy, false);
+
+ response.write(html);
+}
diff --git a/dom/security/test/csp/file_script_template.html b/dom/security/test/csp/file_script_template.html
new file mode 100644
index 0000000000..3819592912
--- /dev/null
+++ b/dom/security/test/csp/file_script_template.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta http-equiv="Content-Security-Policy" content="default-src 'unsafe-inline'">
+<template id="a">
+ <script src="file_script_template.js"></script>
+</template>
+</head>
+<body>
+<script>
+ var temp = document.getElementsByTagName("template")[0];
+ var clon = temp.content.cloneNode(true);
+ document.body.appendChild(clon);
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/file_script_template.js b/dom/security/test/csp/file_script_template.js
new file mode 100644
index 0000000000..d75869f763
--- /dev/null
+++ b/dom/security/test/csp/file_script_template.js
@@ -0,0 +1 @@
+// dummy *.js file
diff --git a/dom/security/test/csp/file_self_none_as_hostname_confusion.html b/dom/security/test/csp/file_self_none_as_hostname_confusion.html
new file mode 100644
index 0000000000..16196bb19f
--- /dev/null
+++ b/dom/security/test/csp/file_self_none_as_hostname_confusion.html
@@ -0,0 +1,11 @@
+<!doctype html>
+<html>
+ <head>
+ <meta charset="utf8">
+ <title>Bug 587377 - CSP keywords "'self'" and "'none'" are easy to confuse with host names "self" and "none"</title>
+ <!-- Any copyright is dedicated to the Public Domain.
+ - http://creativecommons.org/publicdomain/zero/1.0/ -->
+ </head>
+ <body>
+ </body>
+</html>
diff --git a/dom/security/test/csp/file_self_none_as_hostname_confusion.html^headers^ b/dom/security/test/csp/file_self_none_as_hostname_confusion.html^headers^
new file mode 100644
index 0000000000..26af7ed9b5
--- /dev/null
+++ b/dom/security/test/csp/file_self_none_as_hostname_confusion.html^headers^
@@ -0,0 +1 @@
+Content-Security-Policy: default-src 'self' SELF;
diff --git a/dom/security/test/csp/file_sendbeacon.html b/dom/security/test/csp/file_sendbeacon.html
new file mode 100644
index 0000000000..13202c65ff
--- /dev/null
+++ b/dom/security/test/csp/file_sendbeacon.html
@@ -0,0 +1,21 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <meta http-equiv="Content-Security-Policy" content= "connect-src 'none'">
+ <title>Bug 1234813 - sendBeacon should not throw if blocked by Content Policy</title>
+</head>
+<body>
+
+<script type="application/javascript">
+try {
+ navigator.sendBeacon("http://example.com/sendbeaconintonirvana");
+ window.parent.postMessage({result: "blocked-beacon-does-not-throw"}, "*");
+ }
+ catch (e) {
+ window.parent.postMessage({result: "blocked-beacon-throws"}, "*");
+ }
+</script>
+
+</body>
+</html>
diff --git a/dom/security/test/csp/file_service_worker.html b/dom/security/test/csp/file_service_worker.html
new file mode 100644
index 0000000000..b819946983
--- /dev/null
+++ b/dom/security/test/csp/file_service_worker.html
@@ -0,0 +1,21 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 1208559 - ServiceWorker registration not governed by CSP</title>
+</head>
+<body>
+<script>
+ function finish(status) {
+ window.parent.postMessage({result: status}, "*");
+ }
+
+ const promises = [
+ navigator.serviceWorker.ready,
+ navigator.serviceWorker.register("file_service_worker.js", { scope: "." })
+ ];
+
+ Promise.race(promises).then(finish.bind(null, 'allowed'),
+ finish.bind(null, 'blocked'));
+ </script>
+</body>
+</html>
diff --git a/dom/security/test/csp/file_service_worker.js b/dom/security/test/csp/file_service_worker.js
new file mode 100644
index 0000000000..1bf583f4cc
--- /dev/null
+++ b/dom/security/test/csp/file_service_worker.js
@@ -0,0 +1 @@
+dump("service workers: hello world");
diff --git a/dom/security/test/csp/file_spawn_service_worker.js b/dom/security/test/csp/file_spawn_service_worker.js
new file mode 100644
index 0000000000..b262fa10a3
--- /dev/null
+++ b/dom/security/test/csp/file_spawn_service_worker.js
@@ -0,0 +1 @@
+// dummy file
diff --git a/dom/security/test/csp/file_spawn_shared_worker.js b/dom/security/test/csp/file_spawn_shared_worker.js
new file mode 100644
index 0000000000..e4f53b9ce1
--- /dev/null
+++ b/dom/security/test/csp/file_spawn_shared_worker.js
@@ -0,0 +1,7 @@
+onconnect = function (e) {
+ var port = e.ports[0];
+ port.addEventListener("message", function (e) {
+ port.postMessage("shared worker is executing");
+ });
+ port.start();
+};
diff --git a/dom/security/test/csp/file_spawn_worker.js b/dom/security/test/csp/file_spawn_worker.js
new file mode 100644
index 0000000000..acde7408c1
--- /dev/null
+++ b/dom/security/test/csp/file_spawn_worker.js
@@ -0,0 +1 @@
+postMessage("worker is executing");
diff --git a/dom/security/test/csp/file_strict_dynamic.js b/dom/security/test/csp/file_strict_dynamic.js
new file mode 100644
index 0000000000..09286d42e9
--- /dev/null
+++ b/dom/security/test/csp/file_strict_dynamic.js
@@ -0,0 +1 @@
+document.getElementById("testdiv").innerHTML = "allowed";
diff --git a/dom/security/test/csp/file_strict_dynamic_default_src.html b/dom/security/test/csp/file_strict_dynamic_default_src.html
new file mode 100644
index 0000000000..0ea79e2a96
--- /dev/null
+++ b/dom/security/test/csp/file_strict_dynamic_default_src.html
@@ -0,0 +1,20 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 1299483 - CSP: Implement 'strict-dynamic'</title>
+</head>
+<body>
+
+<div id="testdiv">blocked</div>
+<script nonce="foo" src="http://mochi.test:8888/tests/dom/security/test/csp/file_strict_dynamic_default_src.js"></script>
+
+<img id="testimage" src="http://mochi.test:8888/tests/image/test/mochitest/blue.png" data-result="blocked">
+<script>
+let img = document.getElementById("testimage");
+img.addEventListener("load", function() {
+ img.dataset.result = "allowed";
+}, { once: true });
+</script>
+
+</body>
+</html>
diff --git a/dom/security/test/csp/file_strict_dynamic_default_src.js b/dom/security/test/csp/file_strict_dynamic_default_src.js
new file mode 100644
index 0000000000..09286d42e9
--- /dev/null
+++ b/dom/security/test/csp/file_strict_dynamic_default_src.js
@@ -0,0 +1 @@
+document.getElementById("testdiv").innerHTML = "allowed";
diff --git a/dom/security/test/csp/file_strict_dynamic_js_url.html b/dom/security/test/csp/file_strict_dynamic_js_url.html
new file mode 100644
index 0000000000..bd53b0adb2
--- /dev/null
+++ b/dom/security/test/csp/file_strict_dynamic_js_url.html
@@ -0,0 +1,15 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 1316826 - 'strict-dynamic' blocking DOM event handlers</title>
+</head>
+<body>
+<div id="testdiv">blocked</div>
+
+<a id="jslink" href='javascript:document.getElementById("testdiv").innerHTML = "allowed"'>click me</a>
+<script nonce="foo">
+ document.getElementById("jslink").click();
+</script>
+
+</body>
+</html>
diff --git a/dom/security/test/csp/file_strict_dynamic_non_parser_inserted.html b/dom/security/test/csp/file_strict_dynamic_non_parser_inserted.html
new file mode 100644
index 0000000000..c51fefd72e
--- /dev/null
+++ b/dom/security/test/csp/file_strict_dynamic_non_parser_inserted.html
@@ -0,0 +1,17 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 1299483 - CSP: Implement 'strict-dynamic'</title>
+</head>
+<body>
+<div id="testdiv">blocked</div>
+
+<script nonce="foo">
+ // generates a *non* parser inserted script and should be allowed
+ var myScript = document.createElement('script');
+ myScript.src = 'http://example.com/tests/dom/security/test/csp/file_strict_dynamic.js';
+ document.head.appendChild(myScript);
+</script>
+
+</body>
+</html>
diff --git a/dom/security/test/csp/file_strict_dynamic_non_parser_inserted_inline.html b/dom/security/test/csp/file_strict_dynamic_non_parser_inserted_inline.html
new file mode 100644
index 0000000000..10a0f32e4b
--- /dev/null
+++ b/dom/security/test/csp/file_strict_dynamic_non_parser_inserted_inline.html
@@ -0,0 +1,16 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 1299483 - CSP: Implement 'strict-dynamic'</title>
+</head>
+<body>
+<div id="testdiv">blocked</div>
+
+<script nonce="foo">
+ var dynamicScript = document.createElement('script');
+ dynamicScript.textContent = 'document.getElementById("testdiv").textContent="allowed"';
+ document.head.appendChild(dynamicScript);
+</script>
+
+</body>
+</html>
diff --git a/dom/security/test/csp/file_strict_dynamic_parser_inserted_doc_write.html b/dom/security/test/csp/file_strict_dynamic_parser_inserted_doc_write.html
new file mode 100644
index 0000000000..2a3a7d4998
--- /dev/null
+++ b/dom/security/test/csp/file_strict_dynamic_parser_inserted_doc_write.html
@@ -0,0 +1,15 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 1299483 - CSP: Implement 'strict-dynamic'</title>
+</head>
+<body>
+<div id="testdiv">blocked</div>
+
+<script nonce="foo">
+ // generates a parser inserted script and should be blocked
+ document.write("<script src='http://example.com/tests/dom/security/test/csp/file_strict_dynamic.js'><\/script>");
+</script>
+
+</body>
+</html>
diff --git a/dom/security/test/csp/file_strict_dynamic_parser_inserted_doc_write_correct_nonce.html b/dom/security/test/csp/file_strict_dynamic_parser_inserted_doc_write_correct_nonce.html
new file mode 100644
index 0000000000..9938ef2dcd
--- /dev/null
+++ b/dom/security/test/csp/file_strict_dynamic_parser_inserted_doc_write_correct_nonce.html
@@ -0,0 +1,15 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 1299483 - CSP: Implement 'strict-dynamic'</title>
+</head>
+<body>
+<div id="testdiv">blocked</div>
+
+<script nonce="foo">
+ // generates a parser inserted script with a valid nonce- and should be allowed
+ document.write("<script nonce='foo' src='http://example.com/tests/dom/security/test/csp/file_strict_dynamic.js'><\/script>");
+</script>
+
+</body>
+</html>
diff --git a/dom/security/test/csp/file_strict_dynamic_script_events.html b/dom/security/test/csp/file_strict_dynamic_script_events.html
new file mode 100644
index 0000000000..0889583821
--- /dev/null
+++ b/dom/security/test/csp/file_strict_dynamic_script_events.html
@@ -0,0 +1,14 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 1316826 - 'strict-dynamic' blocking DOM event handlers</title>
+</head>
+<body>
+<div id="testdiv">blocked</div>
+
+ <img src='/nonexisting.jpg'
+ onerror='document.getElementById("testdiv").innerHTML = "allowed";'
+ style='display:none'>
+
+</body>
+</html>
diff --git a/dom/security/test/csp/file_strict_dynamic_script_events_marquee.html b/dom/security/test/csp/file_strict_dynamic_script_events_marquee.html
new file mode 100644
index 0000000000..701ef32269
--- /dev/null
+++ b/dom/security/test/csp/file_strict_dynamic_script_events_marquee.html
@@ -0,0 +1,14 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 1316826 - 'strict-dynamic' blocking DOM event handlers</title>
+</head>
+<body>
+<div id="testdiv">blocked</div>
+
+<marquee onstart='document.getElementById("testdiv").innerHTML = "allowed";'>
+ Bug 1316826
+</marquee>
+
+</body>
+</html>
diff --git a/dom/security/test/csp/file_strict_dynamic_script_extern.html b/dom/security/test/csp/file_strict_dynamic_script_extern.html
new file mode 100644
index 0000000000..94b6aefb19
--- /dev/null
+++ b/dom/security/test/csp/file_strict_dynamic_script_extern.html
@@ -0,0 +1,10 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 1299483 - CSP: Implement 'strict-dynamic'</title>
+</head>
+<body>
+<div id="testdiv">blocked</div>
+<script nonce="foo" src="http://example.com/tests/dom/security/test/csp/file_strict_dynamic.js"></script>
+</body>
+</html>
diff --git a/dom/security/test/csp/file_strict_dynamic_script_inline.html b/dom/security/test/csp/file_strict_dynamic_script_inline.html
new file mode 100644
index 0000000000..d17a58f279
--- /dev/null
+++ b/dom/security/test/csp/file_strict_dynamic_script_inline.html
@@ -0,0 +1,14 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 1299483 - CSP: Implement 'strict-dynamic'</title>
+</head>
+<body>
+<div id="testdiv">blocked</div>
+
+<script nonce="foo">
+ document.getElementById("testdiv").innerHTML = "allowed";
+</script>
+
+</body>
+</html>
diff --git a/dom/security/test/csp/file_strict_dynamic_unsafe_eval.html b/dom/security/test/csp/file_strict_dynamic_unsafe_eval.html
new file mode 100644
index 0000000000..f0b26da915
--- /dev/null
+++ b/dom/security/test/csp/file_strict_dynamic_unsafe_eval.html
@@ -0,0 +1,14 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 1299483 - CSP: Implement 'strict-dynamic'</title>
+</head>
+<body>
+<div id="testdiv">blocked</div>
+
+<script nonce="foo">
+ eval('document.getElementById("testdiv").innerHTML = "allowed";');
+</script>
+
+</body>
+</html> \ No newline at end of file
diff --git a/dom/security/test/csp/file_subframe_run_js_if_allowed.html b/dom/security/test/csp/file_subframe_run_js_if_allowed.html
new file mode 100644
index 0000000000..3ba970ce84
--- /dev/null
+++ b/dom/security/test/csp/file_subframe_run_js_if_allowed.html
@@ -0,0 +1,13 @@
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=702439
+
+This document is a child frame of a CSP document and the
+test verifies that it is permitted to run javascript: URLs
+if the parent has a policy that allows them.
+-->
+<body onload="document.getElementById('a').click()">
+<a id="a" href="javascript:parent.javascript_link_ran = true;
+ parent.checkResult();">click</a>
+</body>
+</html>
diff --git a/dom/security/test/csp/file_subframe_run_js_if_allowed.html^headers^ b/dom/security/test/csp/file_subframe_run_js_if_allowed.html^headers^
new file mode 100644
index 0000000000..233b359310
--- /dev/null
+++ b/dom/security/test/csp/file_subframe_run_js_if_allowed.html^headers^
@@ -0,0 +1 @@
+Content-Security-Policy: default-src *; script-src 'unsafe-inline'
diff --git a/dom/security/test/csp/file_svg_inline_style_base.html b/dom/security/test/csp/file_svg_inline_style_base.html
new file mode 100644
index 0000000000..4d7ce0cd6e
--- /dev/null
+++ b/dom/security/test/csp/file_svg_inline_style_base.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+</head>
+<body>
+ <img src="file_svg_inline_style_server.sjs?svg_inline_style_nocsp&1">
+</body>
+</html>
diff --git a/dom/security/test/csp/file_svg_inline_style_csp.html b/dom/security/test/csp/file_svg_inline_style_csp.html
new file mode 100644
index 0000000000..040ee02e19
--- /dev/null
+++ b/dom/security/test/csp/file_svg_inline_style_csp.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <meta http-equiv="Content-Security-Policy" content="default-src 'self'">
+</head>
+<body>
+ <img src="file_svg_inline_style_server.sjs?svg_inline_style_csp&2">
+</body>
+</html>
diff --git a/dom/security/test/csp/file_svg_inline_style_server.sjs b/dom/security/test/csp/file_svg_inline_style_server.sjs
new file mode 100644
index 0000000000..6073f36f62
--- /dev/null
+++ b/dom/security/test/csp/file_svg_inline_style_server.sjs
@@ -0,0 +1,43 @@
+"use strict";
+
+const SVG_IMG = `<svg width="200" height="200" viewBox="0 0 150 150" xmlns="http://www.w3.org/2000/svg">
+ <style>
+ circle {
+ fill: orange;
+ stroke: black;
+ stroke-width: 10px;
+ }
+ </style>
+ <circle cx="50" cy="50" r="40" />
+ </svg>`;
+
+const SVG_IMG_NO_INLINE_STYLE = `<svg width="200" height="200" viewBox="0 0 150 150" xmlns="http://www.w3.org/2000/svg">
+ <circle cx="50" cy="50" r="40" />
+ </svg>`;
+
+function handleRequest(request, response) {
+ const query = request.queryString;
+
+ response.setHeader("Cache-Control", "no-cache", false);
+ response.setHeader("Content-Type", "image/svg+xml", false);
+
+ if (query.includes("svg_inline_style_csp")) {
+ response.setHeader("Content-Security-Policy", "default-src 'none'", false);
+ response.write(SVG_IMG);
+ return;
+ }
+
+ if (query.includes("svg_inline_style_nocsp")) {
+ response.write(SVG_IMG);
+ return;
+ }
+
+ if (query.includes("svg_no_inline_style")) {
+ response.write(SVG_IMG_NO_INLINE_STYLE);
+ return;
+ }
+
+ // we should never get here, but just in case
+ // return something unexpected
+ response.write("do'h");
+}
diff --git a/dom/security/test/csp/file_svg_srcset_inline_style_base.html b/dom/security/test/csp/file_svg_srcset_inline_style_base.html
new file mode 100644
index 0000000000..1754c557f0
--- /dev/null
+++ b/dom/security/test/csp/file_svg_srcset_inline_style_base.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+</head>
+<body>
+ <img srcset="file_svg_inline_style_server.sjs?svg_inline_style_nocsp&3">
+</body>
+</html>
diff --git a/dom/security/test/csp/file_svg_srcset_inline_style_csp.html b/dom/security/test/csp/file_svg_srcset_inline_style_csp.html
new file mode 100644
index 0000000000..418d714882
--- /dev/null
+++ b/dom/security/test/csp/file_svg_srcset_inline_style_csp.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <meta http-equiv="Content-Security-Policy" content="default-src 'self'">
+</head>
+<body>
+ <img srcset="file_svg_inline_style_server.sjs?svg_inline_style_csp&4">
+</body>
+</html>
diff --git a/dom/security/test/csp/file_test_browser_bookmarklets.html b/dom/security/test/csp/file_test_browser_bookmarklets.html
new file mode 100644
index 0000000000..cb12e4efd0
--- /dev/null
+++ b/dom/security/test/csp/file_test_browser_bookmarklets.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <meta http-equiv="X-UA-Compatible" content="ie=edge">
+ <title>Document</title>
+</head>
+<body>
+ <h1>Test-Document</h1>
+</body>
+</html> \ No newline at end of file
diff --git a/dom/security/test/csp/file_test_browser_bookmarklets.html^headers^ b/dom/security/test/csp/file_test_browser_bookmarklets.html^headers^
new file mode 100644
index 0000000000..e138f234fb
--- /dev/null
+++ b/dom/security/test/csp/file_test_browser_bookmarklets.html^headers^
@@ -0,0 +1,2 @@
+Content-Security-Policy: script-src 'none'
+Cache-Control: no-cache
diff --git a/dom/security/test/csp/file_testserver.sjs b/dom/security/test/csp/file_testserver.sjs
new file mode 100644
index 0000000000..0363fc2c7a
--- /dev/null
+++ b/dom/security/test/csp/file_testserver.sjs
@@ -0,0 +1,67 @@
+// SJS file for CSP mochitests
+"use strict";
+const { NetUtil } = ChromeUtils.import("resource://gre/modules/NetUtil.jsm");
+Components.utils.importGlobalProperties(["URLSearchParams"]);
+
+function loadHTMLFromFile(path) {
+ // Load the HTML to return in the response from file.
+ // Since it's relative to the cwd of the test runner, we start there and
+ // append to get to the actual path of the file.
+ const testHTMLFile = Components.classes[
+ "@mozilla.org/file/directory_service;1"
+ ]
+ .getService(Components.interfaces.nsIProperties)
+ .get("CurWorkD", Components.interfaces.nsIFile);
+
+ const testHTMLFileStream = Components.classes[
+ "@mozilla.org/network/file-input-stream;1"
+ ].createInstance(Components.interfaces.nsIFileInputStream);
+
+ path
+ .split("/")
+ .filter(path => path)
+ .reduce((file, path) => {
+ testHTMLFile.append(path);
+ return testHTMLFile;
+ }, testHTMLFile);
+ testHTMLFileStream.init(testHTMLFile, -1, 0, 0);
+ const isAvailable = testHTMLFileStream.available();
+ return NetUtil.readInputStreamToString(testHTMLFileStream, isAvailable);
+}
+
+function handleRequest(request, response) {
+ const query = new URLSearchParams(request.queryString);
+
+ // avoid confusing cache behaviors
+ response.setHeader("Cache-Control", "no-cache", false);
+
+ // Deliver the CSP policy encoded in the URL
+ if (query.has("csp")) {
+ response.setHeader("Content-Security-Policy", query.get("csp"), false);
+ }
+
+ // Deliver the CSP report-only policy encoded in the URI
+ if (query.has("cspRO")) {
+ response.setHeader(
+ "Content-Security-Policy-Report-Only",
+ query.get("cspRO"),
+ false
+ );
+ }
+
+ // Deliver the CORS header in the URL
+ if (query.has("cors")) {
+ response.setHeader("Access-Control-Allow-Origin", query.get("cors"), false);
+ }
+
+ // Send HTML to test allowed/blocked behaviors
+ let type = "text/html";
+ if (query.has("type")) {
+ type = query.get("type");
+ }
+
+ response.setHeader("Content-Type", type, false);
+ if (query.has("file")) {
+ response.write(loadHTMLFromFile(query.get("file")));
+ }
+}
diff --git a/dom/security/test/csp/file_uir_top_nav.html b/dom/security/test/csp/file_uir_top_nav.html
new file mode 100644
index 0000000000..28263e9db7
--- /dev/null
+++ b/dom/security/test/csp/file_uir_top_nav.html
@@ -0,0 +1,17 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">
+</head>
+<body>
+<script class="testbody" type="text/javascript">
+
+// 1) same origin navigation
+window.open("http://example.com/tests/dom/security/test/csp/file_uir_top_nav_dummy.html");
+
+// 2) same origin navigation
+window.open("http://test1.example.com/tests/dom/security/test/csp/file_uir_top_nav_dummy.html");
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/file_uir_top_nav_dummy.html b/dom/security/test/csp/file_uir_top_nav_dummy.html
new file mode 100644
index 0000000000..65762f1c71
--- /dev/null
+++ b/dom/security/test/csp/file_uir_top_nav_dummy.html
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML>
+<html>
+<body>
+just a dummy page to check uir applies to top level navigations
+<script class="testbody" type="text/javascript">
+window.onload = function() {
+ window.opener.parent.postMessage({result: window.location.href}, "*");
+ window.close();
+}
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/file_upgrade_insecure.html b/dom/security/test/csp/file_upgrade_insecure.html
new file mode 100644
index 0000000000..9c4ba597f3
--- /dev/null
+++ b/dom/security/test/csp/file_upgrade_insecure.html
@@ -0,0 +1,90 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Bug 1139297 - Implement CSP upgrade-insecure-requests directive</title>
+ <!-- style -->
+ <link rel='stylesheet' type='text/css' href='http://example.com/tests/dom/security/test/csp/file_upgrade_insecure_server.sjs?style' media='screen' />
+
+ <!-- font -->
+ <style>
+ @font-face {
+ font-family: "foofont";
+ src: url('http://example.com/tests/dom/security/test/csp/file_upgrade_insecure_server.sjs?font');
+ }
+ .div_foo { font-family: "foofont"; }
+ </style>
+</head>
+<body>
+
+ <!-- images: -->
+ <img src="http://example.com/tests/dom/security/test/csp/file_upgrade_insecure_server.sjs?img"></img>
+
+ <!-- redirects: upgrade http:// to https:// redirect to http:// and then upgrade to https:// again -->
+ <img src="http://example.com/tests/dom/security/test/csp/file_upgrade_insecure_server.sjs?redirect-image"></img>
+
+ <!-- script: -->
+ <script src="http://example.com/tests/dom/security/test/csp/file_upgrade_insecure_server.sjs?script"></script>
+
+ <!-- media: -->
+ <audio src="http://example.com/tests/dom/security/test/csp/file_upgrade_insecure_server.sjs?media"></audio>
+
+ <!-- objects: -->
+ <object width="10" height="10" data="http://example.com/tests/dom/security/test/csp/file_upgrade_insecure_server.sjs?object"></object>
+
+ <!-- font: (apply font loaded in header to div) -->
+ <div class="div_foo">foo</div>
+
+ <!-- iframe: (same origin) -->
+ <iframe src="http://example.com/tests/dom/security/test/csp/file_upgrade_insecure_server.sjs?iframe">
+ <!-- within that iframe we load an image over http and make sure the requested gets upgraded to https -->
+ </iframe>
+
+ <!-- xhr: -->
+ <script type="application/javascript">
+ var myXHR = new XMLHttpRequest();
+ myXHR.open("GET", "http://example.com/tests/dom/security/test/csp/file_upgrade_insecure_server.sjs?xhr");
+ myXHR.send(null);
+ </script>
+
+ <!-- websockets: upgrade ws:// to wss://-->
+ <script type="application/javascript">
+ // WebSocket tests are not supported on Android yet. Bug 1566168
+ const { AppConstants } = SpecialPowers.ChromeUtils.import(
+ "resource://gre/modules/AppConstants.jsm"
+ );
+ if (AppConstants.platform !== "android") {
+ var mySocket = new WebSocket("ws://example.com/tests/dom/security/test/csp/file_upgrade_insecure");
+ mySocket.onopen = function(e) {
+ if (mySocket.url.includes("wss://")) {
+ window.parent.postMessage({result: "websocket-ok"}, "*");
+ }
+ else {
+ window.parent.postMessage({result: "websocket-error"}, "*");
+ }
+ mySocket.close();
+ };
+ mySocket.onerror = function(e) {
+ // debug information for Bug 1316305
+ dump(" xxx mySocket.onerror: (mySocket): " + mySocket + "\n");
+ dump(" xxx mySocket.onerror: (mySocket.url): " + mySocket.url + "\n");
+ dump(" xxx mySocket.onerror: (e): " + e + "\n");
+ dump(" xxx mySocket.onerror: (e.message): " + e.message + "\n");
+ window.parent.postMessage({result: "websocket-unexpected-error"}, "*");
+ };
+ }
+ </script>
+
+ <!-- form action: (upgrade POST from http:// to https://) -->
+ <iframe name='formFrame' id='formFrame'></iframe>
+ <form target="formFrame" action="http://example.com/tests/dom/security/test/csp/file_upgrade_insecure_server.sjs?form" method="POST">
+ <input name="foo" value="foo">
+ <input type="submit" id="submitButton" formenctype='multipart/form-data' value="Submit form">
+ </form>
+ <script type="text/javascript">
+ var submitButton = document.getElementById('submitButton');
+ submitButton.click();
+ </script>
+
+</body>
+</html>
diff --git a/dom/security/test/csp/file_upgrade_insecure_cors.html b/dom/security/test/csp/file_upgrade_insecure_cors.html
new file mode 100644
index 0000000000..e675c62e9f
--- /dev/null
+++ b/dom/security/test/csp/file_upgrade_insecure_cors.html
@@ -0,0 +1,49 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Bug 1139297 - Implement CSP upgrade-insecure-requests directive</title>
+</head>
+<body>
+
+<script type="text/javascript">
+ // === TEST 1
+ var url1 = "http://test1.example.com/tests/dom/security/test/csp/file_upgrade_insecure_cors_server.sjs?test1";
+ var xhr1 = new XMLHttpRequest();
+ xhr1.open("GET", url1, true);
+ xhr1.onload = function() {
+ window.parent.postMessage(xhr1.response, "*");
+ };
+ xhr1.onerror = function() {
+ window.parent.postMessage("test1-failed", "*");
+ };
+ xhr1.send();
+
+ // === TEST 2
+ var url2 = "http://test1.example.com/tests/dom/security/test/csp/file_upgrade_insecure_cors_server.sjs?test2";
+ var xhr2 = new XMLHttpRequest();
+ xhr2.open("GET", url2, true);
+ xhr2.onload = function() {
+ window.parent.postMessage(xhr2.response, "*");
+ };
+ xhr2.onerror = function() {
+ window.parent.postMessage("test2-failed", "*");
+ };
+ xhr2.send();
+
+ // === TEST 3
+ var url3 = "http://test2.example.com/tests/dom/security/test/csp/file_upgrade_insecure_cors_server.sjs?test3";
+ var xhr3 = new XMLHttpRequest();
+ xhr3.open("GET", url3, true);
+ xhr3.onload = function() {
+ window.parent.postMessage(xhr3.response, "*");
+ };
+ xhr3.onerror = function() {
+ window.parent.postMessage("test3-failed", "*");
+ };
+ xhr3.send();
+
+</script>
+
+</body>
+</html>
diff --git a/dom/security/test/csp/file_upgrade_insecure_cors_server.sjs b/dom/security/test/csp/file_upgrade_insecure_cors_server.sjs
new file mode 100644
index 0000000000..83957560c3
--- /dev/null
+++ b/dom/security/test/csp/file_upgrade_insecure_cors_server.sjs
@@ -0,0 +1,61 @@
+// Custom *.sjs file specifically for the needs of Bug:
+// Bug 1139297 - Implement CSP upgrade-insecure-requests directive
+
+function handleRequest(request, response) {
+ // avoid confusing cache behaviors
+ response.setHeader("Cache-Control", "no-cache", false);
+
+ // perform sanity check and make sure that all requests get upgraded to use https
+ if (request.scheme !== "https") {
+ response.write("request not https");
+ return;
+ }
+
+ var queryString = request.queryString;
+
+ // TEST 1
+ if (queryString === "test1") {
+ var newLocation =
+ "http://test1.example.com/tests/dom/security/test/csp/file_upgrade_insecure_cors_server.sjs?redir-test1";
+ response.setStatusLine("1.1", 302, "Found");
+ response.setHeader("Location", newLocation, false);
+ return;
+ }
+ if (queryString === "redir-test1") {
+ response.write("test1-no-cors-ok");
+ return;
+ }
+
+ // TEST 2
+ if (queryString === "test2") {
+ var newLocation =
+ "http://test1.example.com:443/tests/dom/security/test/csp/file_upgrade_insecure_cors_server.sjs?redir-test2";
+ response.setStatusLine("1.1", 302, "Found");
+ response.setHeader("Location", newLocation, false);
+ return;
+ }
+ if (queryString === "redir-test2") {
+ response.write("test2-no-cors-diffport-ok");
+ return;
+ }
+
+ // TEST 3
+ response.setHeader("Access-Control-Allow-Headers", "content-type", false);
+ response.setHeader("Access-Control-Allow-Methods", "POST, GET", false);
+ response.setHeader("Access-Control-Allow-Origin", "*", false);
+
+ if (queryString === "test3") {
+ var newLocation =
+ "http://test1.example.com/tests/dom/security/test/csp/file_upgrade_insecure_cors_server.sjs?redir-test3";
+ response.setStatusLine("1.1", 302, "Found");
+ response.setHeader("Location", newLocation, false);
+ return;
+ }
+ if (queryString === "redir-test3") {
+ response.write("test3-cors-ok");
+ return;
+ }
+
+ // we should not get here, but just in case return something unexpected
+ response.write("d'oh");
+}
diff --git a/dom/security/test/csp/file_upgrade_insecure_docwrite_iframe.sjs b/dom/security/test/csp/file_upgrade_insecure_docwrite_iframe.sjs
new file mode 100644
index 0000000000..a7fb0a2176
--- /dev/null
+++ b/dom/security/test/csp/file_upgrade_insecure_docwrite_iframe.sjs
@@ -0,0 +1,55 @@
+// custom *.sjs for Bug 1273430
+// META CSP: upgrade-insecure-requests
+
+// important: the IFRAME_URL is *http* and needs to be upgraded to *https* by upgrade-insecure-requests
+const IFRAME_URL =
+ "http://example.com/tests/dom/security/test/csp/file_upgrade_insecure_docwrite_iframe.sjs?docwriteframe";
+
+const TEST_FRAME =
+ `
+ <!DOCTYPE HTML>
+ <html><head><meta charset="utf-8">
+ <title>TEST_FRAME</title>
+ <meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">
+ </head>
+ <body>
+ <script type="text/javascript">
+ document.write('<iframe src="` +
+ IFRAME_URL +
+ `"/>');
+ </script>
+ </body>
+ </html>`;
+
+// doc.write(iframe) sends a post message to the parent indicating the current
+// location so the parent can make sure the request was upgraded to *https*.
+const DOC_WRITE_FRAME = `
+ <!DOCTYPE HTML>
+ <html><head><meta charset="utf-8">
+ <title>DOC_WRITE_FRAME</title>
+ </head>
+ <body onload="window.parent.parent.postMessage({result: document.location.href}, '*');">
+ </body>
+ </html>`;
+
+function handleRequest(request, response) {
+ // avoid confusing cache behaviors
+ response.setHeader("Cache-Control", "no-cache", false);
+ response.setHeader("Content-Type", "text/html", false);
+
+ var queryString = request.queryString;
+
+ if (queryString === "testframe") {
+ response.write(TEST_FRAME);
+ return;
+ }
+
+ if (queryString === "docwriteframe") {
+ response.write(DOC_WRITE_FRAME);
+ return;
+ }
+
+ // we should never get here, but just in case
+ // return something unexpected
+ response.write("do'h");
+}
diff --git a/dom/security/test/csp/file_upgrade_insecure_loopback.html b/dom/security/test/csp/file_upgrade_insecure_loopback.html
new file mode 100644
index 0000000000..b824604b6e
--- /dev/null
+++ b/dom/security/test/csp/file_upgrade_insecure_loopback.html
@@ -0,0 +1,25 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Bug 1447784 - Implement CSP upgrade-insecure-requests directive</title>
+</head>
+<body>
+
+<script type="text/javascript">
+ // === TEST 1
+ var url1 = "http://127.0.0.1:8888/tests/dom/security/test/csp/file_upgrade_insecure_loopback_server.sjs?test1";
+ var xhr1 = new XMLHttpRequest();
+ xhr1.open("GET", url1, true);
+ xhr1.onload = function() {
+ window.parent.postMessage(xhr1.response, "*");
+ };
+ xhr1.onerror = function() {
+ window.parent.postMessage("test1-failed", "*");
+ };
+ xhr1.send();
+
+</script>
+
+</body>
+</html>
diff --git a/dom/security/test/csp/file_upgrade_insecure_loopback_form.html b/dom/security/test/csp/file_upgrade_insecure_loopback_form.html
new file mode 100644
index 0000000000..ed6b3b8542
--- /dev/null
+++ b/dom/security/test/csp/file_upgrade_insecure_loopback_form.html
@@ -0,0 +1,17 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Bug 1661423 - don't apply upgrade-insecure-requests on form submissions to localhost</title>
+</head>
+<body>
+
+<form id="form" action="http://127.0.0.1/bug-1661423-dont-upgrade-localhost">
+ <input type="submit">
+</form>>
+<script type="text/javascript">
+
+ form.submit();
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/file_upgrade_insecure_loopback_server.sjs b/dom/security/test/csp/file_upgrade_insecure_loopback_server.sjs
new file mode 100644
index 0000000000..ff7931a1d4
--- /dev/null
+++ b/dom/security/test/csp/file_upgrade_insecure_loopback_server.sjs
@@ -0,0 +1,22 @@
+// Custom *.sjs file specifically for the needs of Bug:
+// Bug 1447784 - Implement CSP upgrade-insecure-requests directive
+
+function handleRequest(request, response) {
+ response.setHeader("Access-Control-Allow-Headers", "content-type", false);
+ response.setHeader("Access-Control-Allow-Methods", "GET", false);
+ response.setHeader("Access-Control-Allow-Origin", "*", false);
+
+ // avoid confusing cache behaviors
+ response.setHeader("Cache-Control", "no-cache", false);
+
+ // perform sanity check and make sure that all requests get upgraded to use https
+ if (request.scheme !== "https") {
+ response.write("request-not-https");
+ return;
+ } else {
+ response.write("request-is-https");
+ }
+
+ // we should not get here, but just in case return something unexpected
+ response.write("d'oh");
+}
diff --git a/dom/security/test/csp/file_upgrade_insecure_meta.html b/dom/security/test/csp/file_upgrade_insecure_meta.html
new file mode 100644
index 0000000000..a84a8c254d
--- /dev/null
+++ b/dom/security/test/csp/file_upgrade_insecure_meta.html
@@ -0,0 +1,86 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests; default-src https: wss: 'unsafe-inline'; form-action https:;">
+ <meta charset="utf-8">
+ <title>Bug 1139297 - Implement CSP upgrade-insecure-requests directive</title>
+ <!-- style -->
+ <link rel='stylesheet' type='text/css' href='http://example.com/tests/dom/security/test/csp/file_upgrade_insecure_server.sjs?style' media='screen' />
+
+ <!-- font -->
+ <style>
+ @font-face {
+ font-family: "foofont";
+ src: url('http://example.com/tests/dom/security/test/csp/file_upgrade_insecure_server.sjs?font');
+ }
+ .div_foo { font-family: "foofont"; }
+ </style>
+</head>
+<body>
+
+ <!-- images: -->
+ <img src="http://example.com/tests/dom/security/test/csp/file_upgrade_insecure_server.sjs?img"></img>
+
+ <!-- redirects: upgrade http:// to https:// redirect to http:// and then upgrade to https:// again -->
+ <img src="http://example.com/tests/dom/security/test/csp/file_upgrade_insecure_server.sjs?redirect-image"></img>
+
+ <!-- script: -->
+ <script src="http://example.com/tests/dom/security/test/csp/file_upgrade_insecure_server.sjs?script"></script>
+
+ <!-- media: -->
+ <audio src="http://example.com/tests/dom/security/test/csp/file_upgrade_insecure_server.sjs?media"></audio>
+
+ <!-- objects: -->
+ <object width="10" height="10" data="http://example.com/tests/dom/security/test/csp/file_upgrade_insecure_server.sjs?object"></object>
+
+ <!-- font: (apply font loaded in header to div) -->
+ <div class="div_foo">foo</div>
+
+ <!-- iframe: (same origin) -->
+ <iframe src="http://example.com/tests/dom/security/test/csp/file_upgrade_insecure_server.sjs?iframe">
+ <!-- within that iframe we load an image over http and make sure the requested gets upgraded to https -->
+ </iframe>
+
+ <!-- xhr: -->
+ <script type="application/javascript">
+ var myXHR = new XMLHttpRequest();
+ myXHR.open("GET", "http://example.com/tests/dom/security/test/csp/file_upgrade_insecure_server.sjs?xhr");
+ myXHR.send(null);
+ </script>
+
+ <!-- websockets: upgrade ws:// to wss://-->
+ <script type="application/javascript">
+ // WebSocket tests are not supported on Android Yet. Bug 1566168.
+ const { AppConstants } = SpecialPowers.ChromeUtils.import(
+ "resource://gre/modules/AppConstants.jsm"
+ );
+ if (AppConstants.platform !== "android") {
+ var mySocket = new WebSocket("ws://example.com/tests/dom/security/test/csp/file_upgrade_insecure");
+ mySocket.onopen = function(e) {
+ if (mySocket.url.includes("wss://")) {
+ window.parent.postMessage({result: "websocket-ok"}, "*");
+ }
+ else {
+ window.parent.postMessage({result: "websocket-error"}, "*");
+ }
+ mySocket.close();
+ };
+ mySocket.onerror = function(e) {
+ window.parent.postMessage({result: "websocket-unexpected-error"}, "*");
+ };
+ }
+ </script>
+
+ <!-- form action: (upgrade POST from http:// to https://) -->
+ <iframe name='formFrame' id='formFrame'></iframe>
+ <form target="formFrame" action="http://example.com/tests/dom/security/test/csp/file_upgrade_insecure_server.sjs?form" method="POST">
+ <input name="foo" value="foo">
+ <input type="submit" id="submitButton" formenctype='multipart/form-data' value="Submit form">
+ </form>
+ <script type="text/javascript">
+ var submitButton = document.getElementById('submitButton');
+ submitButton.click();
+ </script>
+
+</body>
+</html>
diff --git a/dom/security/test/csp/file_upgrade_insecure_navigation.sjs b/dom/security/test/csp/file_upgrade_insecure_navigation.sjs
new file mode 100644
index 0000000000..51afa39bf7
--- /dev/null
+++ b/dom/security/test/csp/file_upgrade_insecure_navigation.sjs
@@ -0,0 +1,79 @@
+// Custom *.sjs file specifically for the needs of
+// https://bugzilla.mozilla.org/show_bug.cgi?id=1271173
+
+"use strict";
+Components.utils.importGlobalProperties(["URLSearchParams"]);
+
+const TEST_NAVIGATIONAL_UPGRADE = `
+ <!DOCTYPE html>
+ <html>
+ <head><meta charset="utf-8"></head>
+ <body>
+ <a href="http://example.com/tests/dom/security/test/csp/file_upgrade_insecure_navigation.sjs?action=framenav" id="testlink">clickme</a>
+ <script type="text/javascript">
+ // before navigating the current frame we open the window and check that uir applies
+ var myWin = window.open("http://example.com/tests/dom/security/test/csp/file_upgrade_insecure_navigation.sjs?action=docnav");
+
+ window.addEventListener("message", receiveMessage, false);
+ function receiveMessage(event) {
+ myWin.close();
+ var link = document.getElementById('testlink');
+ link.click();
+ }
+ </script>
+ </body>
+ </html>`;
+
+const FRAME_NAV = `
+ <!DOCTYPE html>
+ <html>
+ <head><meta charset="utf-8"></head>
+ <body>
+ <script type="text/javascript">
+ parent.postMessage({result: document.documentURI}, "*");
+ </script>
+ </body>
+ </html>`;
+
+const DOC_NAV = `
+ <!DOCTYPE html>
+ <html>
+ <head><meta charset="utf-8"></head>
+ <body>
+ <script type="text/javascript">
+ // call back to the main testpage signaling whether the upgraded succeeded
+ window.opener.parent.postMessage({result: document.documentURI}, "*");
+ // let the opener (iframe) now that we can now close the window and move on with the test.
+ window.opener.postMessage({result: "readyToMoveOn"}, "*");
+ </script>
+ </body>
+ </html>`;
+
+function handleRequest(request, response) {
+ const query = new URLSearchParams(request.queryString);
+
+ response.setHeader("Cache-Control", "no-cache", false);
+ response.setHeader("Content-Type", "text/html", false);
+ if (query.get("csp")) {
+ response.setHeader("Content-Security-Policy", query.get("csp"), false);
+ }
+
+ if (query.get("action") === "perform_navigation") {
+ response.write(TEST_NAVIGATIONAL_UPGRADE);
+ return;
+ }
+
+ if (query.get("action") === "framenav") {
+ response.write(FRAME_NAV);
+ return;
+ }
+
+ if (query.get("action") === "docnav") {
+ response.write(DOC_NAV);
+ return;
+ }
+
+ // we should never get here, but just in case
+ // return something unexpected
+ response.write("do'h");
+}
diff --git a/dom/security/test/csp/file_upgrade_insecure_navigation_redirect.sjs b/dom/security/test/csp/file_upgrade_insecure_navigation_redirect.sjs
new file mode 100644
index 0000000000..3f7f8158e0
--- /dev/null
+++ b/dom/security/test/csp/file_upgrade_insecure_navigation_redirect.sjs
@@ -0,0 +1,50 @@
+"use strict";
+
+const FINAL_DOCUMENT = `
+ <html>
+ <body>
+ final document
+ <script>
+ window.onload = function() {
+ let docURI = document.documentURI;
+ window.opener.parent.postMessage({docURI}, "*");
+ window.close();
+ }
+ </script>
+ </body>
+ </html>`;
+
+function handleRequest(request, response) {
+ response.setHeader("Cache-Control", "no-cache", false);
+ response.setHeader("Content-Type", "text/html", false);
+
+ const query = request.queryString;
+
+ if (query === "same_origin_redirect") {
+ let newLocation =
+ "http://example.com/tests/dom/security/test/csp/file_upgrade_insecure_navigation_redirect.sjs?finaldoc_same_origin_redirect";
+ response.setStatusLine("1.1", 302, "Found");
+ response.setHeader("Location", newLocation, false);
+ return;
+ }
+
+ if (query === "cross_origin_redirect") {
+ let newLocation =
+ "http://test1.example.com/tests/dom/security/test/csp/file_upgrade_insecure_navigation_redirect.sjs?finaldoc_cross_origin_redirect";
+ response.setStatusLine("1.1", 302, "Found");
+ response.setHeader("Location", newLocation, false);
+ return;
+ }
+
+ if (
+ query === "finaldoc_same_origin_redirect" ||
+ query === "finaldoc_cross_origin_redirect"
+ ) {
+ response.write(FINAL_DOCUMENT);
+ return;
+ }
+
+ // we should never get here, but just in case
+ // return something unexpected
+ response.write("do'h");
+}
diff --git a/dom/security/test/csp/file_upgrade_insecure_navigation_redirect_cross_origin.html b/dom/security/test/csp/file_upgrade_insecure_navigation_redirect_cross_origin.html
new file mode 100644
index 0000000000..dff2c9faf3
--- /dev/null
+++ b/dom/security/test/csp/file_upgrade_insecure_navigation_redirect_cross_origin.html
@@ -0,0 +1,10 @@
+<html>
+<head>
+ <meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests" />
+</head>
+<body>
+<script>
+ window.open("http://example.com/tests/dom/security/test/csp/file_upgrade_insecure_navigation_redirect.sjs?cross_origin_redirect");
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/file_upgrade_insecure_navigation_redirect_same_origin.html b/dom/security/test/csp/file_upgrade_insecure_navigation_redirect_same_origin.html
new file mode 100644
index 0000000000..811850e08c
--- /dev/null
+++ b/dom/security/test/csp/file_upgrade_insecure_navigation_redirect_same_origin.html
@@ -0,0 +1,10 @@
+<html>
+<head>
+ <meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests" />
+</head>
+<body>
+<script>
+ window.open("http://example.com/tests/dom/security/test/csp/file_upgrade_insecure_navigation_redirect.sjs?same_origin_redirect");
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/file_upgrade_insecure_reporting.html b/dom/security/test/csp/file_upgrade_insecure_reporting.html
new file mode 100644
index 0000000000..c78e9a784d
--- /dev/null
+++ b/dom/security/test/csp/file_upgrade_insecure_reporting.html
@@ -0,0 +1,23 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Bug 1139297 - Implement CSP upgrade-insecure-requests directive</title>
+</head>
+<body>
+
+ <!-- upgrade img from http:// to https:// -->
+ <img id="testimage" src="http://example.com/tests/dom/security/test/csp/file_upgrade_insecure_reporting_server.sjs?img"></img>
+
+ <script type="application/javascript">
+ var myImg = document.getElementById("testimage");
+ myImg.onload = function(e) {
+ window.parent.postMessage({result: "img-ok"}, "*");
+ };
+ myImg.onerror = function(e) {
+ window.parent.postMessage({result: "img-error"}, "*");
+ };
+ </script>
+
+</body>
+</html>
diff --git a/dom/security/test/csp/file_upgrade_insecure_reporting_server.sjs b/dom/security/test/csp/file_upgrade_insecure_reporting_server.sjs
new file mode 100644
index 0000000000..e5ea844bba
--- /dev/null
+++ b/dom/security/test/csp/file_upgrade_insecure_reporting_server.sjs
@@ -0,0 +1,87 @@
+// Custom *.sjs specifically for the needs of Bug
+// Bug 1139297 - Implement CSP upgrade-insecure-requests directive
+
+const { NetUtil } = ChromeUtils.import("resource://gre/modules/NetUtil.jsm");
+
+// small red image
+const IMG_BYTES = atob(
+ "iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12" +
+ "P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=="
+);
+
+const REPORT_URI =
+ "https://example.com/tests/dom/security/test/csp/file_upgrade_insecure_reporting_server.sjs?report";
+const POLICY = "upgrade-insecure-requests; default-src https: 'unsafe-inline'";
+const POLICY_RO =
+ "default-src https: 'unsafe-inline'; report-uri " + REPORT_URI;
+
+function loadHTMLFromFile(path) {
+ // Load the HTML to return in the response from file.
+ // Since it's relative to the cwd of the test runner, we start there and
+ // append to get to the actual path of the file.
+ var testHTMLFile = Components.classes["@mozilla.org/file/directory_service;1"]
+ .getService(Components.interfaces.nsIProperties)
+ .get("CurWorkD", Components.interfaces.nsIFile);
+ var dirs = path.split("/");
+ for (var i = 0; i < dirs.length; i++) {
+ testHTMLFile.append(dirs[i]);
+ }
+ var testHTMLFileStream = Components.classes[
+ "@mozilla.org/network/file-input-stream;1"
+ ].createInstance(Components.interfaces.nsIFileInputStream);
+ testHTMLFileStream.init(testHTMLFile, -1, 0, 0);
+ var testHTML = NetUtil.readInputStreamToString(
+ testHTMLFileStream,
+ testHTMLFileStream.available()
+ );
+ return testHTML;
+}
+
+function handleRequest(request, response) {
+ // avoid confusing cache behaviors
+ response.setHeader("Cache-Control", "no-cache", false);
+
+ // (1) Store the query that will report back whether the violation report was received
+ if (request.queryString == "queryresult") {
+ response.processAsync();
+ setObjectState("queryResult", response);
+ return;
+ }
+
+ // (2) We load a page using a CSP and a report only CSP
+ if (request.queryString == "toplevel") {
+ response.setHeader("Content-Security-Policy", POLICY, false);
+ response.setHeader("Content-Security-Policy-Report-Only", POLICY_RO, false);
+ response.setHeader("Content-Type", "text/html", false);
+ response.write(
+ loadHTMLFromFile(
+ "tests/dom/security/test/csp/file_upgrade_insecure_reporting.html"
+ )
+ );
+ return;
+ }
+
+ // (3) Return the image back to the client
+ if (request.queryString == "img") {
+ response.setHeader("Content-Type", "image/png");
+ response.write(IMG_BYTES);
+ return;
+ }
+
+ // (4) Finally we receive the report, let's return the request from (1)
+ // signaling that we received the report correctly
+ if (request.queryString == "report") {
+ getObjectState("queryResult", function (queryResponse) {
+ if (!queryResponse) {
+ return;
+ }
+ queryResponse.write("report-ok");
+ queryResponse.finish();
+ });
+ return;
+ }
+
+ // we should never get here, but just in case ...
+ response.setHeader("Content-Type", "text/plain");
+ response.write("doh!");
+}
diff --git a/dom/security/test/csp/file_upgrade_insecure_server.sjs b/dom/security/test/csp/file_upgrade_insecure_server.sjs
new file mode 100644
index 0000000000..05d027c078
--- /dev/null
+++ b/dom/security/test/csp/file_upgrade_insecure_server.sjs
@@ -0,0 +1,112 @@
+// Custom *.sjs file specifically for the needs of Bug:
+// Bug 1139297 - Implement CSP upgrade-insecure-requests directive
+
+const TOTAL_EXPECTED_REQUESTS = 11;
+
+const IFRAME_CONTENT =
+ "<!DOCTYPE HTML>" +
+ "<html>" +
+ "<head><meta charset='utf-8'>" +
+ "<title>Bug 1139297 - Implement CSP upgrade-insecure-requests directive</title>" +
+ "</head>" +
+ "<body>" +
+ "<img src='http://example.com/tests/dom/security/test/csp/file_upgrade_insecure_server.sjs?nested-img'></img>" +
+ "</body>" +
+ "</html>";
+
+const expectedQueries = [
+ "script",
+ "style",
+ "img",
+ "iframe",
+ "form",
+ "xhr",
+ "media",
+ "object",
+ "font",
+ "img-redir",
+ "nested-img",
+];
+
+function handleRequest(request, response) {
+ // avoid confusing cache behaviors
+ response.setHeader("Cache-Control", "no-cache", false);
+ var queryString = request.queryString;
+
+ // initialize server variables and save the object state
+ // of the initial request, which returns async once the
+ // server has processed all requests.
+ if (queryString == "queryresult") {
+ setState("totaltests", TOTAL_EXPECTED_REQUESTS.toString());
+ setState("receivedQueries", "");
+ response.processAsync();
+ setObjectState("queryResult", response);
+ return;
+ }
+
+ // handle img redirect (https->http)
+ if (queryString == "redirect-image") {
+ var newLocation =
+ "http://example.com/tests/dom/security/test/csp/file_upgrade_insecure_server.sjs?img-redir";
+ response.setStatusLine("1.1", 302, "Found");
+ response.setHeader("Location", newLocation, false);
+ return;
+ }
+
+ // just in case error handling for unexpected queries
+ if (expectedQueries.indexOf(queryString) == -1) {
+ response.write("doh!");
+ return;
+ }
+
+ // make sure all the requested queries are indeed https
+ queryString += request.scheme == "https" ? "-ok" : "-error";
+
+ var receivedQueries = getState("receivedQueries");
+
+ // images, scripts, etc. get queried twice, do not
+ // confuse the server by storing the preload as
+ // well as the actual load. If either the preload
+ // or the actual load is not https, then we would
+ // append "-error" in the array and the test would
+ // fail at the end.
+ if (receivedQueries.includes(queryString)) {
+ return;
+ }
+
+ // append the result to the total query string array
+ if (receivedQueries != "") {
+ receivedQueries += ",";
+ }
+ receivedQueries += queryString;
+ setState("receivedQueries", receivedQueries);
+
+ // keep track of how many more requests the server
+ // is expecting
+ var totaltests = parseInt(getState("totaltests"));
+ totaltests -= 1;
+ setState("totaltests", totaltests.toString());
+
+ // return content (img) for the nested iframe to test
+ // that subresource requests within nested contexts
+ // get upgraded as well. We also have to return
+ // the iframe context in case of an error so we
+ // can test both, using upgrade-insecure as well
+ // as the base case of not using upgrade-insecure.
+ if (queryString == "iframe-ok" || queryString == "iframe-error") {
+ response.write(IFRAME_CONTENT);
+ }
+
+ // if we have received all the requests, we return
+ // the result back.
+ if (totaltests == 0) {
+ getObjectState("queryResult", function (queryResponse) {
+ if (!queryResponse) {
+ return;
+ }
+ var receivedQueries = getState("receivedQueries");
+ queryResponse.write(receivedQueries);
+ queryResponse.finish();
+ });
+ }
+}
diff --git a/dom/security/test/csp/file_upgrade_insecure_wsh.py b/dom/security/test/csp/file_upgrade_insecure_wsh.py
new file mode 100644
index 0000000000..b7159c742b
--- /dev/null
+++ b/dom/security/test/csp/file_upgrade_insecure_wsh.py
@@ -0,0 +1,6 @@
+def web_socket_do_extra_handshake(request):
+ pass
+
+
+def web_socket_transfer_data(request):
+ pass
diff --git a/dom/security/test/csp/file_web_manifest.html b/dom/security/test/csp/file_web_manifest.html
new file mode 100644
index 0000000000..0f6a67460e
--- /dev/null
+++ b/dom/security/test/csp/file_web_manifest.html
@@ -0,0 +1,6 @@
+<!doctype html>
+<meta charset=utf-8>
+<head>
+<link rel="manifest" href="file_web_manifest.json">
+</head>
+<h1>Support Page for Web Manifest Tests</h1> \ No newline at end of file
diff --git a/dom/security/test/csp/file_web_manifest.json b/dom/security/test/csp/file_web_manifest.json
new file mode 100644
index 0000000000..eb88b50445
--- /dev/null
+++ b/dom/security/test/csp/file_web_manifest.json
@@ -0,0 +1 @@
+{ "name": "loaded" }
diff --git a/dom/security/test/csp/file_web_manifest.json^headers^ b/dom/security/test/csp/file_web_manifest.json^headers^
new file mode 100644
index 0000000000..e0e00c4be0
--- /dev/null
+++ b/dom/security/test/csp/file_web_manifest.json^headers^
@@ -0,0 +1 @@
+Access-Control-Allow-Origin: http://example.org \ No newline at end of file
diff --git a/dom/security/test/csp/file_web_manifest_https.html b/dom/security/test/csp/file_web_manifest_https.html
new file mode 100644
index 0000000000..b0ff9ef853
--- /dev/null
+++ b/dom/security/test/csp/file_web_manifest_https.html
@@ -0,0 +1,4 @@
+<!doctype html>
+<meta charset=utf-8>
+<link rel="manifest" href="https://example.com:443/tests/dom/security/test/csp/file_web_manifest_https.json">
+<h1>Support Page for Web Manifest Tests</h1> \ No newline at end of file
diff --git a/dom/security/test/csp/file_web_manifest_https.json b/dom/security/test/csp/file_web_manifest_https.json
new file mode 100644
index 0000000000..eb88b50445
--- /dev/null
+++ b/dom/security/test/csp/file_web_manifest_https.json
@@ -0,0 +1 @@
+{ "name": "loaded" }
diff --git a/dom/security/test/csp/file_web_manifest_mixed_content.html b/dom/security/test/csp/file_web_manifest_mixed_content.html
new file mode 100644
index 0000000000..55f17c0f92
--- /dev/null
+++ b/dom/security/test/csp/file_web_manifest_mixed_content.html
@@ -0,0 +1,9 @@
+<!doctype html>
+<meta charset=utf-8>
+<head>
+<link
+ rel="manifest"
+ href="http://example.org/tests/dom/security/test/csp/file_testserver.sjs?file=/test/dom/security/test/csp/file_web_manifest.json&amp;cors=*">
+</head>
+<h1>Support Page for Web Manifest Tests</h1>
+<p>Used to try to load a resource over an insecure connection to trigger mixed content blocking.</p> \ No newline at end of file
diff --git a/dom/security/test/csp/file_web_manifest_remote.html b/dom/security/test/csp/file_web_manifest_remote.html
new file mode 100644
index 0000000000..7ecf8eec43
--- /dev/null
+++ b/dom/security/test/csp/file_web_manifest_remote.html
@@ -0,0 +1,8 @@
+<!doctype html>
+<meta charset=utf-8>
+<link rel="manifest"
+ crossorigin
+ href="//mochi.test:8888/tests/dom/security/test/csp/file_testserver.sjs?file=/tests/dom/security/test/csp/file_web_manifest.json&amp;cors=*">
+
+<h1>Support Page for Web Manifest Tests</h1>
+<p>Loads a manifest from mochi.test:8888 with CORS set to "*".</p> \ No newline at end of file
diff --git a/dom/security/test/csp/file_websocket_csp_upgrade.html b/dom/security/test/csp/file_websocket_csp_upgrade.html
new file mode 100644
index 0000000000..9302a6e637
--- /dev/null
+++ b/dom/security/test/csp/file_websocket_csp_upgrade.html
@@ -0,0 +1,20 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Bug 1729897: Allow unsecure websocket from localhost page with CSP: upgrade-insecure </title>
+ <meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">
+</head>
+<body>
+ <script type="application/javascript">
+ /* load socket using ws */
+ var wsSocket = new WebSocket("ws://localhost/tests/dom/security/test/csp/file_websocket_self");
+ wsSocket.onopen = function(e) {
+ window.parent.postMessage({result: "self-ws-loaded", url: wsSocket.url}, "*");
+ };
+ wsSocket.onerror = function(e) {
+ window.parent.postMessage({result: "self-ws-blocked"}, "*");
+ };
+ </script>
+</body>
+</html>
diff --git a/dom/security/test/csp/file_websocket_explicit.html b/dom/security/test/csp/file_websocket_explicit.html
new file mode 100644
index 0000000000..51462ab741
--- /dev/null
+++ b/dom/security/test/csp/file_websocket_explicit.html
@@ -0,0 +1,31 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Bug 1345615: Allow websocket schemes when using 'self' in CSP</title>
+ <meta http-equiv="Content-Security-Policy" content="connect-src ws:">
+</head>
+<body>
+ <script type="application/javascript">
+ /* load socket using ws */
+ var wsSocket = new WebSocket("ws://example.com/tests/dom/security/test/csp/file_websocket_self");
+ wsSocket.onopen = function(e) {
+ window.parent.postMessage({result: "explicit-ws-loaded"}, "*");
+ wsSocket.close();
+ };
+ wsSocket.onerror = function(e) {
+ window.parent.postMessage({result: "explicit-ws-blocked"}, "*");
+ };
+
+ /* load socket using wss */
+ var wssSocket = new WebSocket("wss://example.com/tests/dom/security/test/csp/file_websocket_self");
+ wssSocket.onopen = function(e) {
+ window.parent.postMessage({result: "explicit-wss-loaded"}, "*");
+ wssSocket.close();
+ };
+ wssSocket.onerror = function(e) {
+ window.parent.postMessage({result: "explicit-wss-blocked"}, "*");
+ };
+ </script>
+</body>
+</html>
diff --git a/dom/security/test/csp/file_websocket_self.html b/dom/security/test/csp/file_websocket_self.html
new file mode 100644
index 0000000000..3ff5f05580
--- /dev/null
+++ b/dom/security/test/csp/file_websocket_self.html
@@ -0,0 +1,31 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Bug 1345615: Allow websocket schemes when using 'self' in CSP</title>
+ <meta http-equiv="Content-Security-Policy" content="connect-src 'self'">
+</head>
+<body>
+ <script type="application/javascript">
+ /* load socket using ws */
+ var wsSocket = new WebSocket("ws://example.com/tests/dom/security/test/csp/file_websocket_self");
+ wsSocket.onopen = function(e) {
+ window.parent.postMessage({result: "self-ws-loaded"}, "*");
+ wsSocket.close();
+ };
+ wsSocket.onerror = function(e) {
+ window.parent.postMessage({result: "self-ws-blocked"}, "*");
+ };
+
+ /* load socket using wss */
+ var wssSocket = new WebSocket("wss://example.com/tests/dom/security/test/csp/file_websocket_self");
+ wssSocket.onopen = function(e) {
+ window.parent.postMessage({result: "self-wss-loaded"}, "*");
+ wssSocket.close();
+ };
+ wssSocket.onerror = function(e) {
+ window.parent.postMessage({result: "self-wss-blocked"}, "*");
+ };
+ </script>
+</body>
+</html>
diff --git a/dom/security/test/csp/file_websocket_self_wsh.py b/dom/security/test/csp/file_websocket_self_wsh.py
new file mode 100644
index 0000000000..eb45e224f3
--- /dev/null
+++ b/dom/security/test/csp/file_websocket_self_wsh.py
@@ -0,0 +1,6 @@
+def web_socket_do_extra_handshake(request):
+ pass
+
+
+def web_socket_transfer_data(request):
+ pass
diff --git a/dom/security/test/csp/file_win_open_blocked.html b/dom/security/test/csp/file_win_open_blocked.html
new file mode 100644
index 0000000000..2d0828a872
--- /dev/null
+++ b/dom/security/test/csp/file_win_open_blocked.html
@@ -0,0 +1,3 @@
+<script>
+ window.opener.postMessage('window-opened', '*');
+</script>
diff --git a/dom/security/test/csp/file_windowwatcher_frameA.html b/dom/security/test/csp/file_windowwatcher_frameA.html
new file mode 100644
index 0000000000..9e544142ce
--- /dev/null
+++ b/dom/security/test/csp/file_windowwatcher_frameA.html
@@ -0,0 +1,17 @@
+<!DOCTYPE HTML>
+<html>
+<body>
+frame A<br/>
+<iframe name='frameB' src="http://example.com/tests/dom/security/test/csp/file_windowwatcher_subframeB.html"></iframe>
+<iframe name='frameC' src="http://example.com/tests/dom/security/test/csp/file_windowwatcher_subframeC.html"></iframe>
+<iframe name='frameD' src="http://example.com/tests/dom/security/test/csp/file_windowwatcher_subframeD.html"></iframe>
+
+<script class="testbody" type="text/javascript">
+
+window.onload = function() {
+ frameB.openWin();
+}
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/file_windowwatcher_subframeB.html b/dom/security/test/csp/file_windowwatcher_subframeB.html
new file mode 100644
index 0000000000..e7ef422313
--- /dev/null
+++ b/dom/security/test/csp/file_windowwatcher_subframeB.html
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML>
+<html>
+<body>
+subFrame B
+
+<script>
+function openWin() {
+ parent.frameC.open.call(parent.frameD, "http://example.com/tests/dom/security/test/csp/file_windowwatcher_win_open.html");
+}
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/file_windowwatcher_subframeC.html b/dom/security/test/csp/file_windowwatcher_subframeC.html
new file mode 100644
index 0000000000..b97c40432e
--- /dev/null
+++ b/dom/security/test/csp/file_windowwatcher_subframeC.html
@@ -0,0 +1,9 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">
+</head>
+<body>
+subFrame C
+</body>
+</html>
diff --git a/dom/security/test/csp/file_windowwatcher_subframeD.html b/dom/security/test/csp/file_windowwatcher_subframeD.html
new file mode 100644
index 0000000000..2f778ea4cd
--- /dev/null
+++ b/dom/security/test/csp/file_windowwatcher_subframeD.html
@@ -0,0 +1,6 @@
+<!DOCTYPE HTML>
+<html>
+<body>
+subFrame D
+</body>
+</html>
diff --git a/dom/security/test/csp/file_windowwatcher_win_open.html b/dom/security/test/csp/file_windowwatcher_win_open.html
new file mode 100644
index 0000000000..0237e49377
--- /dev/null
+++ b/dom/security/test/csp/file_windowwatcher_win_open.html
@@ -0,0 +1,15 @@
+<!DOCTYPE HTML>
+<html>
+<body>
+Opened Window<br/>
+
+<script>
+
+window.onload = function() {
+ window.opener.parent.parent.postMessage({result: window.location.href}, "*");
+ window.close();
+}
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/file_worker_src.js b/dom/security/test/csp/file_worker_src.js
new file mode 100644
index 0000000000..ce60379fef
--- /dev/null
+++ b/dom/security/test/csp/file_worker_src.js
@@ -0,0 +1,73 @@
+var mySharedWorker = new SharedWorker("file_spawn_shared_worker.js");
+mySharedWorker.port.onmessage = function (ev) {
+ parent.postMessage(
+ {
+ result: "shared-worker-allowed",
+ href: document.location.href,
+ },
+ "*"
+ );
+ mySharedWorker.port.close();
+};
+mySharedWorker.onerror = function (evt) {
+ evt.preventDefault();
+ parent.postMessage(
+ {
+ result: "shared-worker-blocked",
+ href: document.location.href,
+ },
+ "*"
+ );
+ mySharedWorker.port.close();
+};
+mySharedWorker.port.start();
+mySharedWorker.port.postMessage("foo");
+
+// --------------------------------------------
+
+let myWorker = new Worker("file_spawn_worker.js");
+myWorker.onmessage = function (event) {
+ parent.postMessage(
+ {
+ result: "worker-allowed",
+ href: document.location.href,
+ },
+ "*"
+ );
+};
+myWorker.onerror = function (event) {
+ parent.postMessage(
+ {
+ result: "worker-blocked",
+ href: document.location.href,
+ },
+ "*"
+ );
+};
+
+// --------------------------------------------
+
+navigator.serviceWorker
+ .register("file_spawn_service_worker.js")
+ .then(function (reg) {
+ // registration worked
+ reg.unregister().then(function () {
+ parent.postMessage(
+ {
+ result: "service-worker-allowed",
+ href: document.location.href,
+ },
+ "*"
+ );
+ });
+ })
+ .catch(function (error) {
+ // registration failed
+ parent.postMessage(
+ {
+ result: "service-worker-blocked",
+ href: document.location.href,
+ },
+ "*"
+ );
+ });
diff --git a/dom/security/test/csp/file_worker_src_child_governs.html b/dom/security/test/csp/file_worker_src_child_governs.html
new file mode 100644
index 0000000000..ca8a683aac
--- /dev/null
+++ b/dom/security/test/csp/file_worker_src_child_governs.html
@@ -0,0 +1,9 @@
+<html>
+<head>
+ <meta charset="utf-8">
+ <meta http-equiv="Content-Security-Policy" content="child-src https://example.com; script-src 'nonce-foo'">";
+</head>
+<body>
+<script type="text/javascript" src="file_worker_src.js" nonce="foo"></script>
+</body>
+</html>
diff --git a/dom/security/test/csp/file_worker_src_script_governs.html b/dom/security/test/csp/file_worker_src_script_governs.html
new file mode 100644
index 0000000000..0385fee57c
--- /dev/null
+++ b/dom/security/test/csp/file_worker_src_script_governs.html
@@ -0,0 +1,9 @@
+<html>
+<head>
+ <meta charset="utf-8">
+ <meta http-equiv="Content-Security-Policy" content="script-src 'nonce-foo' https://example.com">";
+</head>
+<body>
+<script type="text/javascript" src="file_worker_src.js" nonce="foo"></script>
+</body>
+</html>
diff --git a/dom/security/test/csp/file_worker_src_worker_governs.html b/dom/security/test/csp/file_worker_src_worker_governs.html
new file mode 100644
index 0000000000..93c8f61225
--- /dev/null
+++ b/dom/security/test/csp/file_worker_src_worker_governs.html
@@ -0,0 +1,9 @@
+<html>
+<head>
+ <meta charset="utf-8">
+ <meta http-equiv="Content-Security-Policy" content="worker-src https://example.com; child-src 'none'; script-src 'nonce-foo'">";
+</head>
+<body>
+<script type="text/javascript" src="file_worker_src.js" nonce="foo"></script>
+</body>
+</html>
diff --git a/dom/security/test/csp/file_xslt_inherits_csp.xml b/dom/security/test/csp/file_xslt_inherits_csp.xml
new file mode 100644
index 0000000000..a6d99c3081
--- /dev/null
+++ b/dom/security/test/csp/file_xslt_inherits_csp.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?xml-stylesheet type="text/xsl" href="file_xslt_inherits_csp.xsl"?>
+
+<root>
+ <t>This is some Title</t>
+</root>
diff --git a/dom/security/test/csp/file_xslt_inherits_csp.xml^headers^ b/dom/security/test/csp/file_xslt_inherits_csp.xml^headers^
new file mode 100644
index 0000000000..635af0a4d9
--- /dev/null
+++ b/dom/security/test/csp/file_xslt_inherits_csp.xml^headers^
@@ -0,0 +1,2 @@
+Content-Security-Policy: script-src 'self'
+Cache-Control: no-cache
diff --git a/dom/security/test/csp/file_xslt_inherits_csp.xsl b/dom/security/test/csp/file_xslt_inherits_csp.xsl
new file mode 100644
index 0000000000..82a4b0ad97
--- /dev/null
+++ b/dom/security/test/csp/file_xslt_inherits_csp.xsl
@@ -0,0 +1,26 @@
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.1">
+ <xsl:output method="html"/>
+ <xsl:variable name="title" select="/root/t"/>
+ <xsl:template match="/">
+ <html>
+ <head>
+ <title>
+ <xsl:value-of select="$title"/>
+ </title>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
+ </head>
+ <body>
+ <p>
+ Below is some inline JavaScript generating some red text.
+ </p>
+
+ <p id="bug"/>
+ <script>
+ document.body.append("JS DID EXCECUTE");
+ </script>
+
+ <a onClick='document.body.append("JS DID EXCECUTE");' href="#">link with lineOnClick</a>
+ </body>
+ </html>
+ </xsl:template>
+</xsl:stylesheet>
diff --git a/dom/security/test/csp/main_csp_worker.html b/dom/security/test/csp/main_csp_worker.html
new file mode 100644
index 0000000000..8957e3fd25
--- /dev/null
+++ b/dom/security/test/csp/main_csp_worker.html
@@ -0,0 +1,439 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title>Bug 1475849: Test CSP worker inheritance</title>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="worker_helper.js"></script>
+
+ </head>
+ <body>
+ <script type="application/javascript">
+ const SJS = "worker.sjs";
+ const SAME_BASE = "http://mochi.test:8888/tests/dom/security/test/csp/file_CSP.sjs";
+ const CROSS_BASE = "http://example.com/tests/dom/security/test/csp/file_CSP.sjs";
+
+ SimpleTest.waitForExplicitFinish();
+ /* test data format :
+ {
+ id: test id, short description of test,
+ base: URL of the request in worker,
+ action: type of request in worker (fetch, xhr, importscript)
+ type: how do we create the worker, from URL or Blob,
+ csp: csp of worker,
+ child: how do we create the child worker, from URL or Blob,
+ childCsp: csp of child worker
+ expectedBlock: result when CSP policy, true or false
+ }
+ */
+
+ // Document's CSP is defined in main_csp_worker.html^headers^
+ // Content-Security-Policy: default-src 'self' blob: 'unsafe-inline'
+ var tests = [
+ // create new Worker(url), worker's csp should be deliveried from header.
+ // csp should be: default-src 'self' blob: ; connect-src CROSS_BASE
+ {
+ id: "worker_url_fetch_same_bad",
+ base: SAME_BASE,
+ action: "fetch",
+ type: "url",
+ csp: "default-src 'self' blob: ; connect-src http://example.com",
+ expectBlocked: true
+ },
+ {
+ id: "worker_url_importScripts_same_good",
+ base: SAME_BASE,
+ action: "importScripts",
+ type: "url",
+ csp: "default-src 'self' blob: ; connect-src http://example.com",
+ expectBlocked: false
+ },
+ {
+ id: "worker_url_xhr_same_bad",
+ base: SAME_BASE,
+ action: "xhr",
+ type: "url",
+ csp: "default-src 'self' blob: ; connect-src http://example.com",
+ expectBlocked: true
+ },
+ {
+ id: "worker_url_fetch_cross_good",
+ base: CROSS_BASE,
+ action: "fetch",
+ type: "url",
+ csp: "default-src 'self' blob: ; connect-src http://example.com",
+ expectBlocked: false
+ },
+ {
+ id: "worker_url_importScripts_cross_bad",
+ base: CROSS_BASE,
+ action: "importScripts",
+ type: "url",
+ csp: "default-src 'self' blob: ; connect-src http://example.com",
+ expectBlocked: true
+ },
+ {
+ id: "worker_url_xhr_cross_good",
+ base: CROSS_BASE,
+ action: "xhr",
+ type: "url",
+ csp: "default-src 'self' blob: ; connect-src http://example.com",
+ expectBlocked: false
+ },
+
+ // create new Worker(blob:), worker's csp should be inherited from
+ // document.
+ // csp should be : default-src 'self' blob: 'unsafe-inline'
+ {
+ id: "worker_blob_fetch_same_good",
+ base: SAME_BASE,
+ action: "fetch",
+ type: "blob",
+ csp: "default-src 'self' blob: ; connect-src http://example.com",
+ expectBlocked: false
+ },
+ {
+ id: "worker_blob_xhr_same_good",
+ base: SAME_BASE,
+ action: "xhr",
+ type: "blob",
+ csp: "default-src 'self' blob: ; connect-src http://example.com",
+ expectBlocked: false
+ },
+ {
+ id: "worker_blob_importScripts_same_good",
+ base: SAME_BASE,
+ action: "importScripts",
+ type: "blob",
+ csp: "default-src 'self' blob: ; connect-src http://example.com",
+ expectBlocked: false
+ },
+ {
+ id: "worker_blob_fetch_cross_bad",
+ base: CROSS_BASE,
+ action: "fetch",
+ type: "blob",
+ csp: "default-src 'self' blob: ; connect-src http://example.com",
+ expectBlocked: true
+ },
+ {
+ id: "worker_blob_xhr_cross_bad",
+ base: CROSS_BASE,
+ action: "xhr",
+ type: "blob",
+ csp: "default-src 'self' blob: ; connect-src http://example.com",
+ expectBlocked: true
+ },
+ {
+ id: "worker_blob_importScripts_cross_bad",
+ base: CROSS_BASE,
+ action: "importScripts",
+ type: "blob",
+ csp: "default-src 'self' blob: ; connect-src http://example.com",
+ expectBlocked: true
+ },
+
+ // create parent worker from url, child worker from blob,
+ // Parent delivery csp then propagate to child
+ // csp should be: "default-src 'self' blob: ; connect-src 'self' http://example.com",
+ {
+ id: "worker_url_child_blob_fetch_same_good",
+ base: SAME_BASE,
+ action: "fetch",
+ child: "blob",
+ childCsp: "default-src 'none'",
+ type: "url",
+ csp: "default-src 'self' blob: ; connect-src 'self' http://example.com",
+ expectBlocked: false
+ },
+ {
+ id: "worker_url_child_blob_importScripts_same_good",
+ base: SAME_BASE,
+ action: "importScripts",
+ child: "blob",
+ childCsp: "default-src 'none'",
+ type: "url",
+ csp: "default-src 'self' blob: ; connect-src 'self' http://example.com",
+ expectBlocked: false
+ },
+ {
+ id: "worker_url_child_blob_xhr_same_good",
+ base: SAME_BASE,
+ child: "blob",
+ childCsp: "default-src 'none'",
+ action: "xhr",
+ type: "url",
+ csp: "default-src 'self' blob: ; connect-src 'self' http://example.com",
+ expectBlocked: false
+ },
+ {
+ id: "worker_url_child_blob_fetch_cross_good",
+ base: CROSS_BASE,
+ action: "fetch",
+ child: "blob",
+ childCsp: "default-src 'none'",
+ type: "url",
+ csp: "default-src 'self' blob: ; connect-src 'self' http://example.com",
+ expectBlocked: false
+ },
+ {
+ id: "worker_url_child_blob_importScripts_cross_bad",
+ base: CROSS_BASE,
+ action: "importScripts",
+ child: "blob",
+ childCsp: "default-src 'none'",
+ type: "url",
+ csp: "default-src 'self' blob: ; connect-src 'self' http://example.com",
+ expectBlocked: true
+ },
+ {
+ id: "worker_url_child_blob_xhr_cross_godd",
+ base: CROSS_BASE,
+ child: "blob",
+ childCsp: "default-src 'none'",
+ action: "xhr",
+ type: "url",
+ csp: "default-src 'self' blob: ; connect-src 'self' http://example.com",
+ expectBlocked: false
+ },
+
+
+ // create parent worker from blob, child worker from blob,
+ // Csp: document->parent->child
+ // csp should be : default-src 'self' blob: 'unsafe-inline'
+ {
+ id: "worker_blob_child_blob_fetch_same_good",
+ base: SAME_BASE,
+ child: "blob",
+ childCsp: "default-src 'none'",
+ action: "fetch",
+ type: "blob",
+ csp: "default-src 'self' blob:",
+ expectBlocked: false
+ },
+ {
+ id: "worker_blob_child_blob_xhr_same_good",
+ base: SAME_BASE,
+ child: "blob",
+ childCsp: "default-src 'none'",
+ action: "xhr",
+ type: "blob",
+ csp: "default-src 'self' blob:",
+ expectBlocked: false
+ },
+ {
+ id: "worker_blob_child_blob_importScripts_same_good",
+ base: SAME_BASE,
+ action: "importScripts",
+ child: "blob",
+ childCsp: "default-src 'none'",
+ type: "blob",
+ csp: "default-src 'self' blob:",
+ expectBlocked: false
+ },
+ {
+ id: "worker_blob_child_blob_fetch_cross_bad",
+ base: CROSS_BASE,
+ child: "blob",
+ childCsp: "default-src 'none'",
+ action: "fetch",
+ type: "blob",
+ csp: "default-src 'self' blob:",
+ expectBlocked: true
+ },
+ {
+ id: "worker_blob_child_blob_xhr_cross_bad",
+ base: CROSS_BASE,
+ child: "blob",
+ childCsp: "default-src 'none'",
+ action: "xhr",
+ type: "blob",
+ csp: "default-src 'self' blob:",
+ expectBlocked: true
+ },
+ {
+ id: "worker_blob_child_blob_importScripts_cross_bad",
+ base: CROSS_BASE,
+ action: "importScripts",
+ child: "blob",
+ childCsp: "default-src 'none'",
+ type: "blob",
+ csp: "default-src 'self' blob:",
+ expectBlocked: true
+ },
+
+ // create parent worker from url, child worker from url,
+ // child delivery csp from header
+ // csp should be : default-src 'none'
+ {
+ id: "worker_url_child_url_fetch_cross_bad",
+ base: CROSS_BASE,
+ action: "fetch",
+ child: "url",
+ childCsp: "default-src 'none'",
+ type: "url",
+ csp: "default-src 'self' blob:",
+ expectBlocked: true
+ },
+ {
+ id: "worker_url_child_url_xhr_cross_bad",
+ base: CROSS_BASE,
+ child: "url",
+ childCsp: "default-src 'none'",
+ action: "xhr",
+ type: "url",
+ csp: "default-src 'self' blob:",
+ expectBlocked: true
+ },
+ {
+ id: "worker_url_child_url_importScripts_cross_bad",
+ base: CROSS_BASE,
+ action: "importScripts",
+ child: "url",
+ childCsp: "default-src 'none'",
+ type: "url",
+ csp: "default-src 'self' blob:",
+ expectBlocked: true
+ },
+ {
+ id: "worker_url_child_url_fetch_same_bad",
+ base: SAME_BASE,
+ action: "fetch",
+ child: "url",
+ childCsp: "default-src 'none'",
+ type: "url",
+ csp: "default-src 'self' blob:",
+ expectBlocked: true
+ },
+ {
+ id: "worker_url_child_url_xhr_same_bad",
+ base: SAME_BASE,
+ child: "url",
+ childCsp: "default-src 'none'",
+ action: "xhr",
+ type: "url",
+ csp: "default-src 'self' blob:",
+ expectBlocked: true
+ },
+ {
+ id: "worker_url_child_url_importScripts_same_bad",
+ base: SAME_BASE,
+ action: "importScripts",
+ child: "url",
+ childCsp: "default-src 'none'",
+ type: "url",
+ csp: "default-src 'self' blob:",
+ expectBlocked: true
+ },
+
+ // create parent worker from blob, child worker from url,
+ // child delivery csp from header
+ // csp should be : default-src 'none'
+ {
+ id: "worker_blob_child_url_fetch_cross_bad",
+ base: CROSS_BASE,
+ child: "url",
+ childCsp: "default-src 'none'",
+ action: "fetch",
+ type: "blob",
+ csp: "default-src 'self' blob:",
+ expectBlocked: true
+ },
+ {
+ id: "worker_blob_child_url_xhr_cross_bad",
+ base: CROSS_BASE,
+ child: "url",
+ childCsp: "default-src 'none'",
+ action: "xhr",
+ type: "blob",
+ csp: "default-src 'self' blob:",
+ expectBlocked: true
+ },
+ {
+ id: "worker_blob_child_url_importScripts_cross_bad",
+ base: CROSS_BASE,
+ action: "importScripts",
+ child: "url",
+ childCsp: "default-src 'none'",
+ type: "blob",
+ csp: "default-src 'self' blob:",
+ expectBlocked: true
+ },
+ {
+ id: "worker_blob_child_url_fetch_same_bad",
+ base: SAME_BASE,
+ child: "url",
+ childCsp: "default-src 'none'",
+ action: "fetch",
+ type: "blob",
+ csp: "default-src 'self' blob:",
+ expectBlocked: true
+ },
+ {
+ id: "worker_blob_child_url_xhr_same_bad",
+ base: SAME_BASE,
+ child: "url",
+ childCsp: "default-src 'none'",
+ action: "xhr",
+ type: "blob",
+ csp: "default-src 'self' blob:",
+ expectBlocked: true
+ },
+ {
+ id: "worker_blob_child_url_importScripts_same_bad",
+ base: SAME_BASE,
+ action: "importScripts",
+ child: "url",
+ childCsp: "default-src 'none'",
+ type: "blob",
+ csp: "default-src 'self' blob:",
+ expectBlocked: true
+ },
+
+
+ ];
+
+ async function runWorkerTest(data) {
+ let src = SJS;
+ src += "?base=" + escape(data.base);
+ src += "&action=" + escape(data.action);
+ src += "&csp=" + escape(data.csp);
+ src += "&id=" + escape(data.id);
+
+ if (data.child) {
+ src += "&child=" + escape(data.child);
+ }
+
+ if (data.childCsp) {
+ src += "&childCsp=" + escape(data.childCsp);
+ }
+
+ switch (data.type) {
+ case "url":
+ new Worker(src);
+ break;
+
+ case "blob":
+ new Worker(URL.createObjectURL(await doXHRGetBlob(src)));
+ break;
+
+ default:
+ throw "Unsupport type";
+ }
+
+ let checkUri = data.base + "?id=" + data.id;
+ await assertCSPBlock(checkUri, data.expectBlocked);
+ runNextTest();
+ };
+
+ tests.forEach(function(test) {
+ addAsyncTest(async function() {
+ runWorkerTest(test);
+ });
+ });
+
+ runNextTest();
+ </script>
+
+ </body>
+</html>
diff --git a/dom/security/test/csp/main_csp_worker.html^headers^ b/dom/security/test/csp/main_csp_worker.html^headers^
new file mode 100644
index 0000000000..4597e01040
--- /dev/null
+++ b/dom/security/test/csp/main_csp_worker.html^headers^
@@ -0,0 +1 @@
+Content-Security-Policy: default-src 'self' blob: 'unsafe-inline'
diff --git a/dom/security/test/csp/mochitest.ini b/dom/security/test/csp/mochitest.ini
new file mode 100644
index 0000000000..a19aa9d2ca
--- /dev/null
+++ b/dom/security/test/csp/mochitest.ini
@@ -0,0 +1,755 @@
+[DEFAULT]
+support-files =
+ file_base_uri_server.sjs
+ file_blob_data_schemes.html
+ file_blob_uri_blocks_modals.html
+ file_blob_uri_blocks_modals.html^headers^
+ file_blob_top_nav_block_modals.html
+ file_blob_top_nav_block_modals.html^headers^
+ file_connect-src.html
+ file_connect-src-fetch.html
+ file_CSP.css
+ file_CSP.sjs
+ file_dummy_pixel.png
+ file_allow_https_schemes.html
+ file_bug663567.xsl
+ file_bug663567_allows.xml
+ file_bug663567_allows.xml^headers^
+ file_bug663567_blocks.xml
+ file_bug663567_blocks.xml^headers^
+ file_bug802872.html
+ file_bug802872.html^headers^
+ file_bug802872.js
+ file_bug802872.sjs
+ file_bug885433_allows.html
+ file_bug885433_allows.html^headers^
+ file_bug885433_blocks.html
+ file_bug885433_blocks.html^headers^
+ file_bug888172.html
+ file_bug888172.sjs
+ file_evalscript_main.js
+ file_evalscript_main_allowed.js
+ file_evalscript_main.html
+ file_evalscript_main.html^headers^
+ file_evalscript_main_allowed.html
+ file_evalscript_main_allowed.html^headers^
+ file_frameancestors_main.html
+ file_frameancestors_main.js
+ file_frameancestors.sjs
+ file_frameancestors_userpass.html
+ file_frameancestors_userpass_frame_a.html
+ file_frameancestors_userpass_frame_b.html
+ file_frameancestors_userpass_frame_c.html
+ file_frameancestors_userpass_frame_c.html^headers^
+ file_frameancestors_userpass_frame_d.html
+ file_frameancestors_userpass_frame_d.html^headers^
+ file_inlinescript.html
+ file_inlinestyle_main.html
+ file_inlinestyle_main.html^headers^
+ file_inlinestyle_main_allowed.html
+ file_inlinestyle_main_allowed.html^headers^
+ file_invalid_source_expression.html
+ file_main.html
+ file_main.html^headers^
+ file_main.js
+ file_web_manifest.html
+ file_web_manifest_remote.html
+ file_web_manifest_https.html
+ file_web_manifest.json
+ file_web_manifest.json^headers^
+ file_web_manifest_https.json
+ file_web_manifest_mixed_content.html
+ file_bug836922_npolicies.html
+ file_bug836922_npolicies.html^headers^
+ file_bug836922_npolicies_ro_violation.sjs
+ file_bug836922_npolicies_violation.sjs
+ file_bug886164.html
+ file_bug886164.html^headers^
+ file_bug886164_2.html
+ file_bug886164_2.html^headers^
+ file_bug886164_3.html
+ file_bug886164_3.html^headers^
+ file_bug886164_4.html
+ file_bug886164_4.html^headers^
+ file_bug886164_5.html
+ file_bug886164_5.html^headers^
+ file_bug886164_6.html
+ file_bug886164_6.html^headers^
+ file_redirects_main.html
+ file_redirects_page.sjs
+ file_redirects_resource.sjs
+ file_bug910139.sjs
+ file_bug910139.xml
+ file_bug910139.xsl
+ file_bug909029_star.html
+ file_bug909029_star.html^headers^
+ file_bug909029_none.html
+ file_bug909029_none.html^headers^
+ file_bug1229639.html
+ file_bug1229639.html^headers^
+ file_bug1312272.html
+ file_bug1312272.js
+ file_bug1312272.html^headers^
+ file_bug1452037.html
+ file_bug1505412.sjs
+ file_bug1505412_reporter.sjs
+ file_bug1505412_frame.html
+ file_bug1505412_frame.html^headers^
+ file_policyuri_regression_from_multipolicy.html
+ file_policyuri_regression_from_multipolicy.html^headers^
+ file_policyuri_regression_from_multipolicy_policy
+ file_nonce_source.html
+ file_nonce_source.html^headers^
+ file_nonce_redirects.html
+ file_nonce_redirector.sjs
+ file_bug941404.html
+ file_bug941404_xhr.html
+ file_bug941404_xhr.html^headers^
+ file_frame_ancestors_ro.html
+ file_frame_ancestors_ro.html^headers^
+ file_hash_source.html
+ file_dual_header_testserver.sjs
+ file_hash_source.html^headers^
+ file_scheme_relative_sources.js
+ file_scheme_relative_sources.sjs
+ file_ignore_unsafe_inline.html
+ file_ignore_unsafe_inline_multiple_policies_server.sjs
+ file_self_none_as_hostname_confusion.html
+ file_self_none_as_hostname_confusion.html^headers^
+ file_empty_directive.html
+ file_empty_directive.html^headers^
+ file_path_matching.html
+ file_path_matching_incl_query.html
+ file_path_matching.js
+ file_path_matching_redirect.html
+ file_path_matching_redirect_server.sjs
+ file_testserver.sjs
+ file_report_uri_missing_in_report_only_header.html
+ file_report_uri_missing_in_report_only_header.html^headers^
+ file_report.html
+ file_report_chromescript.js
+ file_redirect_content.sjs
+ file_redirect_report.sjs
+ file_subframe_run_js_if_allowed.html
+ file_subframe_run_js_if_allowed.html^headers^
+ file_leading_wildcard.html
+ file_multi_policy_injection_bypass.html
+ file_multi_policy_injection_bypass.html^headers^
+ file_multi_policy_injection_bypass_2.html
+ file_multi_policy_injection_bypass_2.html^headers^
+ file_null_baseuri.html
+ file_form-action.html
+ referrerdirective.sjs
+ file_upgrade_insecure.html
+ file_upgrade_insecure_meta.html
+ file_upgrade_insecure_server.sjs
+ file_upgrade_insecure_wsh.py
+ file_upgrade_insecure_reporting.html
+ file_upgrade_insecure_reporting_server.sjs
+ file_upgrade_insecure_cors.html
+ file_upgrade_insecure_cors_server.sjs
+ file_upgrade_insecure_loopback.html
+ file_upgrade_insecure_loopback_form.html
+ file_upgrade_insecure_loopback_server.sjs
+ file_report_for_import.css
+ file_report_for_import.html
+ file_report_for_import_server.sjs
+ file_service_worker.html
+ file_service_worker.js
+ file_child-src_iframe.html
+ file_child-src_inner_frame.html
+ file_child-src_worker.html
+ file_child-src_worker_data.html
+ file_child-src_worker-redirect.html
+ file_child-src_worker.js
+ file_child-src_service_worker.html
+ file_child-src_service_worker.js
+ file_child-src_shared_worker.html
+ file_child-src_shared_worker_data.html
+ file_child-src_shared_worker-redirect.html
+ file_child-src_shared_worker.js
+ file_redirect_worker.sjs
+ file_meta_element.html
+ file_meta_header_dual.sjs
+ file_docwrite_meta.html
+ file_doccomment_meta.html
+ file_docwrite_meta.css
+ file_docwrite_meta.js
+ file_multipart_testserver.sjs
+ file_fontloader.sjs
+ file_fontloader.woff
+ file_block_all_mcb.sjs
+ file_block_all_mixed_content_frame_navigation1.html
+ file_block_all_mixed_content_frame_navigation2.html
+ file_form_action_server.sjs
+ !/image/test/mochitest/blue.png
+ file_meta_whitespace_skipping.html
+ file_ping.html
+ test_iframe_sandbox_top_1.html^headers^
+ file_iframe_sandbox_document_write.html
+ file_sandbox_pass.js
+ file_sandbox_fail.js
+ file_sandbox_1.html
+ file_sandbox_2.html
+ file_sandbox_3.html
+ file_sandbox_4.html
+ file_sandbox_5.html
+ file_sandbox_6.html
+ file_sandbox_7.html
+ file_sandbox_8.html
+ file_sandbox_9.html
+ file_sandbox_10.html
+ file_sandbox_11.html
+ file_sandbox_12.html
+ file_sandbox_13.html
+ file_sendbeacon.html
+ file_upgrade_insecure_docwrite_iframe.sjs
+ file_data-uri_blocked.html
+ file_data-uri_blocked.html^headers^
+ file_strict_dynamic_js_url.html
+ file_strict_dynamic_script_events.html
+ file_strict_dynamic_script_events_marquee.html
+ file_strict_dynamic_script_inline.html
+ file_strict_dynamic_script_extern.html
+ file_strict_dynamic.js
+ file_strict_dynamic_parser_inserted_doc_write.html
+ file_strict_dynamic_parser_inserted_doc_write_correct_nonce.html
+ file_strict_dynamic_non_parser_inserted.html
+ file_strict_dynamic_non_parser_inserted_inline.html
+ file_strict_dynamic_unsafe_eval.html
+ file_strict_dynamic_default_src.html
+ file_strict_dynamic_default_src.js
+ file_upgrade_insecure_navigation.sjs
+ file_punycode_host_src.sjs
+ file_punycode_host_src.js
+ file_iframe_srcdoc.sjs
+ file_iframe_sandbox_srcdoc.html
+ file_iframe_sandbox_srcdoc.html^headers^
+ file_websocket_self.html
+ file_websocket_csp_upgrade.html
+ file_websocket_explicit.html
+ file_websocket_self_wsh.py
+ file_win_open_blocked.html
+ file_image_nonce.html
+ file_image_nonce.html^headers^
+ file_ignore_xfo.html
+ file_ignore_xfo.html^headers^
+ file_ro_ignore_xfo.html
+ file_ro_ignore_xfo.html^headers^
+ file_no_log_ignore_xfo.html
+ file_no_log_ignore_xfo.html^headers^
+ file_data_csp_inheritance.html
+ file_data_csp_merge.html
+ file_data_doc_ignore_meta_csp.html
+ file_report_font_cache-1.html
+ file_report_font_cache-2.html
+ file_report_font_cache-2.html^headers^
+ Ahem.ttf
+ file_independent_iframe_csp.html
+prefs =
+ security.mixed_content.upgrade_display_content=false
+ javascript.options.experimental.shadow_realms=true
+
+[test_base-uri.html]
+skip-if =
+ http3
+ fission && os == "android" # Bug 1827756
+[test_blob_data_schemes.html]
+skip-if =
+ fission && os == "android" # Bug 1827756
+[test_blob_uri_blocks_modals.html]
+skip-if =
+ xorigin
+ os == "linux"
+ (asan || tsan) # alert should be blocked by CSP - got false, expected true
+ http3
+ fission && os == "android" # Bug 1827756
+[test_bug1764343.html]
+support-files = file_bug1764343.html
+[test_bug1777572.html]
+support-files = file_bug1777572.html
+skip-if =
+ toolkit == 'android' # This unusual window.close/open test times out on Android.
+[test_connect-src.html]
+skip-if =
+ fission && os == "android" # Bug 1827756
+[test_CSP.html]
+skip-if =
+ http3
+ fission && os == "android" # Bug 1827756
+[test_bug1452037.html]
+skip-if =
+ fission && os == "android" # Bug 1827756
+[test_allow_https_schemes.html]
+skip-if =
+ fission && os == "android" # Bug 1827756
+[test_bug663567.html]
+skip-if =
+ fission && xorigin && debug && os == "win" # Bug 1716406 - New fission platform triage
+ fission && os == "android" # Bug 1827314
+[test_bug802872.html]
+skip-if =
+ http3
+ fission && os == "android" # Bug 1827756
+[test_bug885433.html]
+skip-if =
+ fission && os == "android" # Bug 1827756
+[test_bug888172.html]
+skip-if =
+ fission && os == "android" # Bug 1827756
+[test_bug1505412.html]
+skip-if =
+ !debug
+ fission && os == "android" # Bug 1827967
+[test_evalscript.html]
+skip-if =
+ fission && os == "android" # Bug 1827756
+[test_evalscript_blocked_by_strict_dynamic.html]
+skip-if =
+ fission && os == "android" # Bug 1827756
+[test_evalscript_allowed_by_strict_dynamic.html]
+skip-if =
+ fission && os == "android" # Bug 1827756
+[test_frameancestors.html]
+skip-if =
+ xorigin # JavaScript error: http://mochi.xorigin-test:8888/tests/SimpleTest/TestRunner.js, line 157: SecurityError: Permission denied to access property "wrappedJSObject" on cross-origin object
+ http3
+ fission && os == "android" # Bug 1827756
+[test_frameancestors_userpass.html]
+skip-if =
+ http3
+ fission && os == "android" # Bug 1827756
+[test_inlinescript.html]
+skip-if =
+ fission && os == "android" # Bug 1827756
+[test_inlinestyle.html]
+skip-if =
+ fission && os == "android" # Bug 1827756
+[test_invalid_source_expression.html]
+skip-if =
+ fission && os == "android" # Bug 1827756
+[test_bug836922_npolicies.html]
+skip-if =
+ verify
+ http3
+ fission && os == "android" # Bug 1827756
+[test_bug886164.html]
+skip-if =
+ fission && os == "android" # Bug 1827756
+[test_redirects.html]
+skip-if =
+ http3
+ fission && os == "android" # Bug 1827756
+[test_bug910139.html]
+skip-if =
+ verify
+ fission && os == "android" # Bug 1827756
+[test_bug909029.html]
+skip-if =
+ fission && os == "android" # Bug 1827756
+[test_bug1229639.html]
+skip-if =
+ http3
+ fission && os == "android" # Bug 1827324
+[test_bug1579094.html]
+skip-if =
+ fission && os == "android" # Bug 1828011
+[test_frame_ancestors_ro.html]
+skip-if =
+ http3
+[test_policyuri_regression_from_multipolicy.html]
+skip-if =
+ fission && os == "android" # Bug 1827756
+[test_nonce_source.html]
+skip-if =
+ http3
+ fission && os == "android" # Bug 1827756
+[test_nonce_redirects.html]
+skip-if =
+ fission && os == "android" # Bug 1827756
+[test_bug941404.html]
+skip-if =
+ fission && os == "android" # Bug 1827756
+[test_form-action.html]
+skip-if =
+ fission && os == "android" # Bug 1827756
+[test_hash_source.html]
+skip-if =
+ fission && xorigin && debug # Bug 1716406 - New fission platform triage
+[test_scheme_relative_sources.html]
+skip-if =
+ http3
+ fission && os == "android" # Bug 1827756
+[test_ignore_unsafe_inline.html]
+skip-if =
+ xorigin # JavaScript error: http://mochi.xorigin-test:8888/tests/SimpleTest/TestRunner.js, line 157: SecurityError: Permission denied to access property "wrappedJSObject" on cross-origin object, [Child 3789, Main Thread] WARNING: NS_ENSURE_TRUE(request) failed: file /builds/worker/checkouts/gecko/netwerk/base/nsLoadGroup.cpp, line 591
+ fission && os == "android" # Bug 1827756
+[test_self_none_as_hostname_confusion.html]
+skip-if =
+ fission && os == "android" # Bug 1827756
+[test_empty_directive.html]
+skip-if =
+ fission && os == "android" # Bug 1827756
+[test_path_matching.html]
+skip-if =
+ http3
+ fission && os == "android" # Bug 1827756
+[test_path_matching_redirect.html]
+skip-if =
+ http3
+ fission && os == "android" # Bug 1827756
+[test_report_uri_missing_in_report_only_header.html]
+skip-if =
+ fission && os == "android" # Bug 1827756
+[test_report.html]
+fail-if = xorigin
+skip-if =
+ http3
+ fission && os == "android" # Bug 1827756
+[test_301_redirect.html]
+skip-if =
+ http3
+ fission && os == "android" # Bug 1827756
+[test_302_redirect.html]
+skip-if =
+ http3
+ fission && os == "android" # Bug 1827756
+[test_303_redirect.html]
+skip-if =
+ http3
+ fission && os == "android" # Bug 1827756
+[test_307_redirect.html]
+skip-if =
+ http3
+ fission && os == "android" # Bug 1827756
+[test_subframe_run_js_if_allowed.html]
+skip-if =
+ fission && os == "android" # Bug 1827756
+[test_leading_wildcard.html]
+skip-if =
+ http3
+ fission && os == "android" # Bug 1827756
+[test_multi_policy_injection_bypass.html]
+skip-if =
+ fission && os == "android" # Bug 1827756
+[test_null_baseuri.html]
+skip-if =
+ http3
+ fission && os == "android" # Bug 1827756
+[test_dual_header.html]
+skip-if =
+ fission && os == "android" # Bug 1827756
+[test_win_open_blocked.html]
+skip-if =
+ fission && os == "android" # Bug 1827756
+[test_upgrade_insecure.html]
+skip-if =
+ os == 'linux' && bits == 64 # Bug 1620516
+ os == "android" # Bug 1777028
+[test_upgrade_insecure_reporting.html]
+skip-if =
+ http3
+ fission && os == "android" # Bug 1827756
+[test_upgrade_insecure_cors.html]
+skip-if =
+ http3
+ fission && os == "android" # Bug 1827756
+[test_upgrade_insecure_loopback.html]
+skip-if =
+ fission && os == "android" # Bug 1827756
+[test_report_for_import.html]
+fail-if = xorigin
+skip-if =
+ http3
+ fission && os == "android" # Bug 1827756
+[test_blocked_uri_in_reports.html]
+skip-if =
+ http3
+ fission && os == "android" # Bug 1827756
+[test_service_worker.html]
+skip-if =
+ fission && os == "android" # Bug 1827756
+[test_child-src_worker.html]
+skip-if =
+ http3
+ fission && os == "android" # Bug 1827756
+[test_child-src_worker_data.html]
+skip-if =
+ http3
+[test_child-src_worker-redirect.html]
+skip-if =
+ http3
+ fission && os == "android" # Bug 1827756
+[test_child-src_iframe.html]
+skip-if =
+ http3
+ fission && os == "android" # Bug 1827756
+[test_meta_element.html]
+skip-if =
+ fission && os == "android" # Bug 1827756
+[test_meta_header_dual.html]
+skip-if =
+ fission && os == "android" # Bug 1827756
+[test_docwrite_meta.html]
+skip-if =
+ fission && os == "android" # Bug 1827756
+[test_multipartchannel.html]
+skip-if =
+ http3
+ fission && os == "android" # Bug 1827756
+[test_fontloader.html]
+skip-if =
+ fission && os == "android" # Bug 1827756
+[test_block_all_mixed_content.html]
+tags = mcb
+skip-if =
+ fission && os == "android" # Bug 1827756
+[test_block_all_mixed_content_frame_navigation.html]
+tags = mcb
+skip-if =
+ http3
+ fission && os == "android" # Bug 1827756
+[test_form_action_blocks_url.html]
+skip-if =
+ fission && os == "android" # Bug 1827756
+[test_meta_whitespace_skipping.html]
+skip-if =
+ fission && os == "android" # Bug 1827756
+[test_iframe_sandbox.html]
+skip-if =
+ fission && xorigin && debug && (os == "win" || os == "linux") # Bug 1716406 - New fission platform triage
+ http3
+[test_iframe_sandbox_top_1.html]
+skip-if =
+ fission && os == "android" # Bug 1827756
+[test_sandbox.html]
+skip-if = true # Bug 1657934
+[test_ping.html]
+skip-if =
+ http3
+ fission && os == "android" # Bug 1827756
+[test_sendbeacon.html]
+skip-if =
+ fission && os == "android" # Bug 1827756
+[test_upgrade_insecure_docwrite_iframe.html]
+skip-if =
+ fission && os == "android" # Bug 1827756
+[test_bug1242019.html]
+skip-if =
+ http3
+ fission && os == "android" # Bug 1827677
+[test_bug1312272.html]
+skip-if =
+ fission && os == "android" # Bug 1827729
+[test_strict_dynamic.html]
+skip-if =
+ http3
+ fission && os == "android" # Bug 1827756
+[test_strict_dynamic_parser_inserted.html]
+skip-if =
+ http3
+ fission && os == "android" # Bug 1827756
+[test_strict_dynamic_default_src.html]
+skip-if =
+ http3
+ fission && os == "android" # Bug 1827756
+[test_upgrade_insecure_navigation.html]
+skip-if =
+ http3
+ fission && os == "android" # Bug 1827756
+[test_punycode_host_src.html]
+skip-if =
+ http3
+ fission && os == "android" # Bug 1827756
+[test_iframe_sandbox_srcdoc.html]
+skip-if =
+ fission && xorigin && debug && os == "win" # Bug 1716406 - New fission platform triage
+[test_iframe_srcdoc.html]
+skip-if =
+ fission && os == "android" # Bug 1827756
+[test_image_nonce.html]
+skip-if =
+ fission && os == "android" # Bug 1827756
+[test_websocket_self.html]
+skip-if =
+ toolkit == 'android' # no websocket support Bug 982828
+ http3
+[test_websocket_localhost.html]
+skip-if =
+ toolkit == 'android' # no websocket support Bug 982828
+ http3
+[test_ignore_xfo.html]
+skip-if =
+ xorigin # JavaScript error: http://mochi.xorigin-test:8888/tests/SimpleTest/TestRunner.js, line 157: SecurityError: Permission denied to access property "wrappedJSObject" on cross-origin object
+ http3
+ fission && os == "android" # Bug 1827756
+[test_data_csp_inheritance.html]
+skip-if =
+ fission && os == "android" # Bug 1827756
+[test_data_csp_merge.html]
+skip-if =
+ fission && os == "android" # Bug 1827756
+[test_report_font_cache.html]
+skip-if =
+ http3
+ fission && os == "android" # Bug 1827756
+[test_data_doc_ignore_meta_csp.html]
+skip-if =
+ fission && os == "android" # Bug 1827756
+[test_meta_csp_self.html]
+skip-if =
+ fission && os == "android" # Bug 1827756
+[test_uir_top_nav.html]
+support-files =
+ file_uir_top_nav.html
+ file_uir_top_nav_dummy.html
+skip-if =
+ http3
+ fission && os == "android" # Bug 1827756
+[test_sandbox_allow_scripts.html]
+support-files =
+ file_sandbox_allow_scripts.html
+ file_sandbox_allow_scripts.html^headers^
+skip-if =
+ fission && os == "android" # Bug 1827756
+[test_worker_src.html]
+support-files =
+ file_worker_src_worker_governs.html
+ file_worker_src_child_governs.html
+ file_worker_src_script_governs.html
+ file_worker_src.js
+ file_spawn_worker.js
+ file_spawn_shared_worker.js
+ file_spawn_service_worker.js
+skip-if =
+ http3
+ fission && os == "android" # Bug 1827756
+[test_frame_src.html]
+support-files =
+ file_frame_src_frame_governs.html
+ file_frame_src_child_governs.html
+ file_frame_src.js
+ file_frame_src_inner.html
+skip-if =
+ http3
+ fission && os == "android" # Bug 1827756
+[test_security_policy_violation_event.html]
+skip-if =
+ fission && os == "android" # Bug 1827756
+[test_csp_worker_inheritance.html]
+support-files =
+ worker.sjs
+ worker_helper.js
+ main_csp_worker.html
+ main_csp_worker.html^headers^
+skip-if =
+ http3
+ fission && os == "android" # Bug 1827756
+[test_nonce_snapshot.html]
+support-files =
+ file_nonce_snapshot.sjs
+skip-if =
+ fission && os == "android" # Bug 1827756
+[test_uir_windowwatcher.html]
+support-files =
+ file_windowwatcher_frameA.html
+ file_windowwatcher_subframeB.html
+ file_windowwatcher_subframeC.html
+ file_windowwatcher_subframeD.html
+ file_windowwatcher_win_open.html
+skip-if =
+ http3
+ fission && os == "android" # Bug 1827756
+[test_script_template.html]
+support-files =
+ file_script_template.html
+ file_script_template.js
+skip-if =
+ fission && os == "android" # Bug 1827756
+[test_parent_location_js.html]
+support-files =
+ file_parent_location_js.html
+ file_iframe_parent_location_js.html
+skip-if =
+ fission && os == "android" # Bug 1827756
+[test_navigate_to.html]
+support-files =
+ file_navigate_to.sjs
+ file_navigate_to_request.html
+skip-if =
+ http3
+ fission && os == "android" # Bug 1827756
+[test_independent_iframe_csp.html]
+skip-if =
+ fission && os == "android" # Bug 1827756
+[test_xslt_inherits_csp.html]
+support-files =
+ file_xslt_inherits_csp.xml
+ file_xslt_inherits_csp.xml^headers^
+ file_xslt_inherits_csp.xsl
+skip-if =
+ fission && os == "android" # Bug 1827756
+[test_object_inherit.html]
+support-files =
+ file_object_inherit.html
+skip-if =
+ fission && os == "android" # Bug 1827756
+[test_link_rel_preload.html]
+support-files =
+ file_link_rel_preload.html
+skip-if =
+ fission && os == "android" # Bug 1827756
+[test_image_document.html]
+support-files =
+ file_image_document_pixel.png
+ file_image_document_pixel.png^headers^
+skip-if =
+ fission && os == "android" # Bug 1827756
+[test_svg_inline_style.html]
+support-files =
+ file_svg_inline_style_base.html
+ file_svg_inline_style_csp.html
+ file_svg_srcset_inline_style_base.html
+ file_svg_srcset_inline_style_csp.html
+ file_svg_inline_style_server.sjs
+skip-if =
+ fission && os == "android" # Bug 1827756
+[test_upgrade_insecure_navigation_redirect.html]
+support-files =
+ file_upgrade_insecure_navigation_redirect.sjs
+ file_upgrade_insecure_navigation_redirect_same_origin.html
+ file_upgrade_insecure_navigation_redirect_cross_origin.html
+skip-if =
+ http3
+ fission && os == "android" # Bug 1827756
+[test_csp_style_src_empty_hash.html]
+skip-if =
+ fission && os == "android" # Bug 1827756
+[test_csp_frame_ancestors_about_blank.html]
+support-files =
+ file_csp_frame_ancestors_about_blank.html
+ file_csp_frame_ancestors_about_blank.html^headers^
+skip-if =
+ fission && os == "android" # Bug 1827756
+[test_blocked_uri_redirect_frame_src.html]
+support-files =
+ file_blocked_uri_redirect_frame_src.html
+ file_blocked_uri_redirect_frame_src.html^headers^
+ file_blocked_uri_redirect_frame_src_server.sjs
+skip-if =
+ http3
+ fission && os == "android" # Bug 1827756
+[test_blocked_uri_in_violation_event_after_redirects.html]
+support-files =
+ file_blocked_uri_in_violation_event_after_redirects.html
+ file_blocked_uri_in_violation_event_after_redirects.sjs
+skip-if =
+ http3
+ fission && os == "android" # Bug 1827756
+[test_bug1738418.html]
+support-files =
+ file_bug1738418_parent.html
+ file_bug1738418_parent.html^headers^
+ file_bug1738418_child.html
+skip-if =
+ fission && os == "android" # Bug 1827314
diff --git a/dom/security/test/csp/referrerdirective.sjs b/dom/security/test/csp/referrerdirective.sjs
new file mode 100644
index 0000000000..267eaaede2
--- /dev/null
+++ b/dom/security/test/csp/referrerdirective.sjs
@@ -0,0 +1,40 @@
+// Used for bug 965727 to serve up really simple scripts reflecting the
+// referrer sent to load this back to the loader.
+
+function handleRequest(request, response) {
+ // skip speculative loads.
+
+ var splits = request.queryString.split("&");
+ var params = {};
+ splits.forEach(function (v) {
+ let parts = v.split("=");
+ params[parts[0]] = unescape(parts[1]);
+ });
+
+ var loadType = params.type;
+ var referrerLevel = "error";
+
+ if (request.hasHeader("Referer")) {
+ var referrer = request.getHeader("Referer");
+ if (referrer.indexOf("file_testserver.sjs") > -1) {
+ referrerLevel = "full";
+ } else {
+ referrerLevel = "origin";
+ }
+ } else {
+ referrerLevel = "none";
+ }
+
+ var theScript =
+ 'window.postResult("' + loadType + '", "' + referrerLevel + '");';
+ response.setHeader(
+ "Content-Type",
+ "application/javascript; charset=utf-8",
+ false
+ );
+ response.setHeader("Cache-Control", "no-cache", false);
+
+ if (request.method != "OPTIONS") {
+ response.write(theScript);
+ }
+}
diff --git a/dom/security/test/csp/test_301_redirect.html b/dom/security/test/csp/test_301_redirect.html
new file mode 100644
index 0000000000..0aaed5bcf2
--- /dev/null
+++ b/dom/security/test/csp/test_301_redirect.html
@@ -0,0 +1,74 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=650386
+Test that CSP violation reports are not sent when a 301 redirect is encountered
+-->
+<head>
+ <title>Test for Bug 650386</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=650386">Mozilla Bug 650386</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+<iframe id = "content_iframe"></iframe>
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 650386 **/
+
+// This is used to watch the redirect of the report POST get blocked
+function examiner() {
+ SpecialPowers.addObserver(this, "csp-on-violate-policy");
+ SpecialPowers.addObserver(this, "specialpowers-http-notify-request");
+}
+
+examiner.prototype = {
+ observe(subject, topic, data) {
+ if (topic === "specialpowers-http-notify-request") {
+ // this is used to fail the test - if we see the POST to the target of the redirect
+ // we know this is a fail
+ var uri = data;
+ if (uri == "http://example.com/some/fake/path")
+ window.done(false);
+ }
+
+ if(topic === "csp-on-violate-policy") {
+ // something was blocked, but we are looking specifically for the redirect being blocked
+ if (data == "denied redirect while sending violation report")
+ window.done(true);
+ }
+ },
+
+ // must eventually call this to remove the listener,
+ // or mochitests might get borked.
+ remove() {
+ SpecialPowers.removeObserver(this, "csp-on-violate-policy");
+ SpecialPowers.removeObserver(this, "specialpowers-http-notify-request");
+ }
+}
+
+window.examiner = new examiner();
+
+// result == true if we saw the redirect blocked notify, false if we saw the post
+// to the redirect target go out
+window.done = function(result) {
+ ok(result, "a 301 redirect when posting violation report should be blocked");
+
+ // clean up observers and finish the test
+ window.examiner.remove();
+ SimpleTest.finish();
+}
+
+SimpleTest.waitForExplicitFinish();
+
+// save this for last so that our listeners are registered.
+// ... this loads the testbed of good and bad requests.
+document.getElementById('content_iframe').src = 'file_redirect_content.sjs?301';
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_302_redirect.html b/dom/security/test/csp/test_302_redirect.html
new file mode 100644
index 0000000000..330c1a64e9
--- /dev/null
+++ b/dom/security/test/csp/test_302_redirect.html
@@ -0,0 +1,74 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=650386
+Test that CSP violation reports are not sent when a 302 redirect is encountered
+-->
+<head>
+ <title>Test for Bug 650386</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=650386">Mozilla Bug 650386</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+<iframe id = "content_iframe"></iframe>
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 650386 **/
+
+// This is used to watch the redirect of the report POST get blocked
+function examiner() {
+ SpecialPowers.addObserver(this, "csp-on-violate-policy");
+ SpecialPowers.addObserver(this, "specialpowers-http-notify-request");
+}
+
+examiner.prototype = {
+ observe(subject, topic, data) {
+ if (topic === "specialpowers-http-notify-request") {
+ // this is used to fail the test - if we see the POST to the target of the redirect
+ // we know this is a fail
+ var uri = data;
+ if (uri == "http://example.com/some/fake/path")
+ window.done(false);
+ }
+
+ if(topic === "csp-on-violate-policy") {
+ // something was blocked, but we are looking specifically for the redirect being blocked
+ if (data == "denied redirect while sending violation report")
+ window.done(true);
+ }
+ },
+
+ // must eventually call this to remove the listener,
+ // or mochitests might get borked.
+ remove() {
+ SpecialPowers.removeObserver(this, "csp-on-violate-policy");
+ SpecialPowers.removeObserver(this, "specialpowers-http-notify-request");
+ }
+}
+
+window.examiner = new examiner();
+
+// result == true if we saw the redirect blocked notify, false if we saw the post
+// to the redirect target go out
+window.done = function(result) {
+ ok(result, "a 302 redirect when posting violation report should be blocked");
+
+ // clean up observers and finish the test
+ window.examiner.remove();
+ SimpleTest.finish();
+}
+
+SimpleTest.waitForExplicitFinish();
+
+// save this for last so that our listeners are registered.
+// ... this loads the testbed of good and bad requests.
+document.getElementById('content_iframe').src = 'file_redirect_content.sjs?302';
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_303_redirect.html b/dom/security/test/csp/test_303_redirect.html
new file mode 100644
index 0000000000..ecff523967
--- /dev/null
+++ b/dom/security/test/csp/test_303_redirect.html
@@ -0,0 +1,74 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=650386
+Test that CSP violation reports are not sent when a 303 redirect is encountered
+-->
+<head>
+ <title>Test for Bug 650386</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=650386">Mozilla Bug 650386</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+<iframe id = "content_iframe"></iframe>
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 650386 **/
+
+// This is used to watch the redirect of the report POST get blocked
+function examiner() {
+ SpecialPowers.addObserver(this, "csp-on-violate-policy");
+ SpecialPowers.addObserver(this, "specialpowers-http-notify-request");
+}
+
+examiner.prototype = {
+ observe(subject, topic, data) {
+ if (topic === "specialpowers-http-notify-request") {
+ // this is used to fail the test - if we see the POST to the target of the redirect
+ // we know this is a fail
+ var uri = data;
+ if (uri == "http://example.com/some/fake/path")
+ window.done(false);
+ }
+
+ if(topic === "csp-on-violate-policy") {
+ // something was blocked, but we are looking specifically for the redirect being blocked
+ if (data == "denied redirect while sending violation report")
+ window.done(true);
+ }
+ },
+
+ // must eventually call this to remove the listener,
+ // or mochitests might get borked.
+ remove() {
+ SpecialPowers.removeObserver(this, "csp-on-violate-policy");
+ SpecialPowers.removeObserver(this, "specialpowers-http-notify-request");
+ }
+}
+
+window.examiner = new examiner();
+
+// result == true if we saw the redirect blocked notify, false if we saw the post
+// to the redirect target go out
+window.done = function(result) {
+ ok(result, "a 303 redirect when posting violation report should be blocked");
+
+ // clean up observers and finish the test
+ window.examiner.remove();
+ SimpleTest.finish();
+}
+
+SimpleTest.waitForExplicitFinish();
+
+// save this for last so that our listeners are registered.
+// ... this loads the testbed of good and bad requests.
+document.getElementById('content_iframe').src = 'file_redirect_content.sjs?303';
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_307_redirect.html b/dom/security/test/csp/test_307_redirect.html
new file mode 100644
index 0000000000..40ebd592b3
--- /dev/null
+++ b/dom/security/test/csp/test_307_redirect.html
@@ -0,0 +1,75 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=650386
+Test that CSP violation reports are not sent when a 307 redirect is encountered
+-->
+<head>
+ <title>Test for Bug 650386</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=650386">Mozilla Bug 650386</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+<iframe id = "content_iframe"></iframe>
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 650386 **/
+
+// This is used to watch the redirect of the report POST get blocked
+function examiner() {
+ SpecialPowers.addObserver(this, "csp-on-violate-policy");
+ SpecialPowers.addObserver(this, "specialpowers-http-notify-request");
+}
+
+examiner.prototype = {
+ observe(subject, topic, data) {
+ if (topic === "specialpowers-http-notify-request") {
+ // this is used to fail the test - if we see the POST to the target of the redirect
+ // we know this is a fail
+ var uri = data;
+ if (uri == "http://example.com/some/fake/path")
+ window.done(false);
+ }
+
+ if(topic === "csp-on-violate-policy") {
+ // something was blocked, but we are looking specifically for the redirect being blocked
+ if (data == "denied redirect while sending violation report")
+ window.done(true);
+ }
+ },
+
+ // must eventually call this to remove the listener,
+ // or mochitests might get borked.
+ remove() {
+ SpecialPowers.removeObserver(this, "csp-on-violate-policy");
+ SpecialPowers.removeObserver(this, "specialpowers-http-notify-request");
+ }
+}
+
+window.examiner = new examiner();
+
+// result == true if we saw the redirect blocked notify, false if we saw the post
+// to the redirect target go out
+window.done = function(result) {
+ ok(result, "a 307 redirect when posting violation report should be blocked");
+
+ // clean up observers and finish the test
+ window.examiner.remove();
+ SimpleTest.finish();
+}
+
+SimpleTest.waitForExplicitFinish();
+
+// save this for last so that our listeners are registered.
+// ... this loads the testbed of good and bad requests.
+document.getElementById('content_iframe').src = 'file_redirect_content.sjs?307';
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_CSP.html b/dom/security/test/csp/test_CSP.html
new file mode 100644
index 0000000000..babb9db9bc
--- /dev/null
+++ b/dom/security/test/csp/test_CSP.html
@@ -0,0 +1,130 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for Content Security Policy Connections</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+<iframe style="width:200px;height:200px;" id='cspframe'></iframe>
+<script class="testbody" type="text/javascript">
+
+// These are test results: -1 means it hasn't run,
+// true/false is the pass/fail result.
+window.tests = {
+ img_good: -1,
+ img_bad: -1,
+ style_good: -1,
+ style_bad: -1,
+ frame_good: -1,
+ frame_bad: -1,
+ script_good: -1,
+ script_bad: -1,
+ xhr_good: -1,
+ xhr_bad: -1,
+ fetch_good: -1,
+ fetch_bad: -1,
+ beacon_good: -1,
+ beacon_bad: -1,
+ media_good: -1,
+ media_bad: -1,
+ font_good: -1,
+ font_bad: -1,
+ object_good: -1,
+ object_bad: -1,
+};
+
+SpecialPowers.registerObservers("csp-on-violate-policy");
+
+// This is used to watch the blocked data bounce off CSP and allowed data
+// get sent out to the wire.
+function examiner() {
+ SpecialPowers.addObserver(this, "csp-on-violate-policy");
+ SpecialPowers.addObserver(this, "specialpowers-csp-on-violate-policy");
+ SpecialPowers.addObserver(this, "specialpowers-http-notify-request");
+}
+examiner.prototype = {
+ observe(subject, topic, data) {
+ var testpat = new RegExp("testid=([a-z0-9_]+)");
+
+ //_good things better be allowed!
+ //_bad things better be stopped!
+
+ // This is a special observer topic that is proxied from
+ // http-on-modify-request in the parent process to inform us when a URI is
+ // loaded
+ if (topic === "specialpowers-http-notify-request") {
+ var uri = data;
+ if (!testpat.test(uri)) return;
+ var testid = testpat.exec(uri)[1];
+
+ window.testResult(testid,
+ /_good/.test(testid),
+ uri + " allowed by csp");
+ }
+
+ if (topic === "csp-on-violate-policy" ||
+ topic === "specialpowers-csp-on-violate-policy") {
+ // these were blocked... record that they were blocked
+ var asciiSpec = SpecialPowers.getPrivilegedProps(SpecialPowers.do_QueryInterface(subject, "nsIURI"), "asciiSpec");
+ if (!testpat.test(asciiSpec)) return;
+ var testid = testpat.exec(asciiSpec)[1];
+ window.testResult(testid,
+ /_bad/.test(testid),
+ asciiSpec + " blocked by \"" + data + "\"");
+ }
+ },
+
+ // must eventually call this to remove the listener,
+ // or mochitests might get borked.
+ remove() {
+ SpecialPowers.removeObserver(this, "csp-on-violate-policy");
+ SpecialPowers.removeObserver(this, "specialpowers-csp-on-violate-policy");
+ SpecialPowers.removeObserver(this, "specialpowers-http-notify-request");
+ }
+}
+
+window.examiner = new examiner();
+
+window.testResult = function(testname, result, msg) {
+ // test already complete.... forget it... remember the first result.
+ if (window.tests[testname] != -1)
+ return;
+
+ ok(testname in window.tests, "It's a real test");
+ window.tests[testname] = result;
+ is(result, true, testname + ' test: ' + msg);
+
+ // if any test is incomplete, keep waiting
+ for (var v in window.tests)
+ if(tests[v] == -1)
+ return;
+
+ // ... otherwise, finish
+ window.examiner.remove();
+ SimpleTest.finish();
+}
+
+SimpleTest.waitForExplicitFinish();
+
+SpecialPowers.pushPrefEnv(
+ {'set':[// On a cellular connection the default preload value is 0 ("preload
+ // none"). Our Android emulators emulate a cellular connection, and
+ // so by default preload no media data. This causes the media_* tests
+ // to timeout. We set the default used by cellular connections to the
+ // same as used by non-cellular connections in order to get
+ // consistent behavior across platforms/devices.
+ ["media.preload.default", 2],
+ ["media.preload.default.cellular", 2]]},
+ function() {
+ // save this for last so that our listeners are registered.
+ // ... this loads the testbed of good and bad requests.
+ document.getElementById('cspframe').src = 'file_main.html';
+ });
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_allow_https_schemes.html b/dom/security/test/csp/test_allow_https_schemes.html
new file mode 100644
index 0000000000..be1f030fb9
--- /dev/null
+++ b/dom/security/test/csp/test_allow_https_schemes.html
@@ -0,0 +1,76 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 826805 - Allow http and https for scheme-less sources</title>
+ <!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+ <p id="display"></p>
+ <div id="content" style="visibility: hidden">
+ <iframe style="width:100%;" id="testframe"></iframe>
+ </div>
+
+<script class="testbody" type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+
+/* Description of the test:
+ * We are loading the following url (including a fragment portion):
+ * https://example.com/tests/dom/security/test/csp/file_path_matching.js#foo
+ * using different policies that lack specification of a scheme.
+ *
+ * Since the file is served over http:, the upgrade to https should be
+ * permitted by CSP in case no port is specified.
+ */
+
+var policies = [
+ ["allowed", "example.com"],
+ ["allowed", "example.com:443"],
+ ["allowed", "example.com:80"],
+ ["allowed", "http://*:80"],
+ ["allowed", "https://*:443"],
+ // our testing framework only supports :80 and :443, but
+ // using :8000 in a policy does the trick for the test.
+ ["blocked", "example.com:8000"],
+]
+
+var counter = 0;
+var policy;
+
+function loadNextTest() {
+ if (counter == policies.length) {
+ SimpleTest.finish();
+ }
+ else {
+ policy = policies[counter++];
+ var src = "file_testserver.sjs";
+ // append the file that should be served
+ src += "?file=" + escape("tests/dom/security/test/csp/file_allow_https_schemes.html");
+ // append the CSP that should be used to serve the file
+ src += "&csp=" + escape("default-src 'none'; script-src " + policy[1]);
+
+ document.getElementById("testframe").addEventListener("load", test);
+ document.getElementById("testframe").src = src;
+ }
+}
+
+function test() {
+ try {
+ document.getElementById("testframe").removeEventListener('load', test);
+ var testframe = document.getElementById("testframe");
+ var divcontent = testframe.contentWindow.document.getElementById('testdiv').innerHTML;
+ is(divcontent, policy[0], "should be " + policy[0] + " in test " + (counter - 1) + "!");
+ }
+ catch (e) {
+ ok(false, "ERROR: could not access content in test " + (counter - 1) + "!");
+ }
+ loadNextTest();
+}
+
+loadNextTest();
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_base-uri.html b/dom/security/test/csp/test_base-uri.html
new file mode 100644
index 0000000000..4d5c5504af
--- /dev/null
+++ b/dom/security/test/csp/test_base-uri.html
@@ -0,0 +1,124 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 1045897 - Test CSP base-uri directive</title>
+ <!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+ <p id="display"></p>
+ <div id="content" style="visibility: hidden">
+ <iframe style="width:100%;" id="testframe"></iframe>
+ </div>
+
+<script class="testbody" type="text/javascript">
+
+/*
+ * Description of the test:
+ * We load a page in an iframe (served over http://example.com) that tries to
+ * modify the 'base' either through setting or also removing the base-uri. We
+ * load that page using different policies and verify that setting the base-uri
+ * is correctly blocked by CSP.
+ */
+
+SimpleTest.waitForExplicitFinish();
+
+var tests = [
+ { csp: "base-uri http://mochi.test;",
+ base1: "http://mochi.test",
+ base2: "",
+ action: "enforce-csp",
+ result: "http://mochi.test",
+ desc: "CSP allows base uri"
+ },
+ { csp: "base-uri http://example.com;",
+ base1: "http://mochi.test",
+ base2: "",
+ action: "enforce-csp",
+ result: "http://example.com",
+ desc: "CSP blocks base uri"
+ },
+ { csp: "base-uri https:",
+ base1: "http://mochi.test",
+ base2: "",
+ action: "enforce-csp",
+ result: "http://example.com",
+ desc: "CSP blocks http base"
+ },
+ { csp: "base-uri 'none'",
+ base1: "http://mochi.test",
+ base2: "",
+ action: "enforce-csp",
+ result: "http://example.com",
+ desc: "CSP allows no base modification"
+ },
+ { csp: "",
+ base1: "http://foo:foo/",
+ base2: "",
+ action: "enforce-csp",
+ result: "http://example.com",
+ desc: "Invalid base should be ignored"
+ },
+ { csp: "base-uri http://mochi.test",
+ base1: "http://mochi.test",
+ base2: "http://test1.example.com",
+ action: "remove-base1",
+ result: "http://example.com",
+ desc: "Removing first base should result in fallback base"
+ },
+ { csp: "",
+ base1: "http://mochi.test",
+ base2: "http://test1.example.com",
+ action: "remove-base1",
+ result: "http://test1.example.com",
+ desc: "Removing first base should result in the second base"
+ },
+];
+
+// initializing to -1 so we start at index 0 when we start the test
+var counter = -1;
+
+function finishTest() {
+ window.removeEventListener("message", receiveMessage);
+ SimpleTest.finish();
+}
+
+// a postMessage handler that is used by sandboxed iframes without
+// 'allow-same-origin' to bubble up results back to this main page.
+window.addEventListener("message", receiveMessage);
+function receiveMessage(event) {
+ var result = event.data.result;
+ // we only care about the base uri, so instead of comparing the complete uri
+ // we just make sure that the base is correct which is sufficient here.
+ ok(result.startsWith(tests[counter].result),
+ `${tests[counter].desc}: Expected a base URI that starts
+ with ${tests[counter].result} but got ${result}`);
+ loadNextTest();
+}
+
+function loadNextTest() {
+ counter++;
+ if (counter == tests.length) {
+ finishTest();
+ return;
+ }
+ var src = "http://example.com/tests/dom/security/test/csp/file_base_uri_server.sjs";
+ // append the CSP that should be used to serve the file
+ // please note that we have to include 'unsafe-inline' to permit sending the postMessage
+ src += "?csp=" + escape("script-src 'unsafe-inline'; " + tests[counter].csp);
+ // append potential base tags
+ src += "&base1=" + escape(tests[counter].base1);
+ src += "&base2=" + escape(tests[counter].base2);
+ // append potential action
+ src += "&action=" + escape(tests[counter].action);
+
+ document.getElementById("testframe").src = src;
+}
+
+// start running the tests
+loadNextTest();
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_blob_data_schemes.html b/dom/security/test/csp/test_blob_data_schemes.html
new file mode 100644
index 0000000000..37a22db050
--- /dev/null
+++ b/dom/security/test/csp/test_blob_data_schemes.html
@@ -0,0 +1,89 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 1086999 - Wildcard should not match blob:, data:</title>
+ <!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+ <iframe style="width:100%;" id="testframe"></iframe>
+
+<script class="testbody" type="text/javascript">
+
+/* Description of the test:
+ * We load an image using a data: and a blob: scheme and make
+ * sure a CSP containing a single ASTERISK (*) does not allowlist
+ * those loads. The single ASTERISK character should not match a
+ * URI's scheme of a type designating globally unique identifier
+ * (such as blob:, data:, or filesystem:)
+ */
+
+var tests = [
+ {
+ policy : "default-src 'unsafe-inline' blob: data:",
+ expected : "allowed",
+ },
+ {
+ policy : "default-src 'unsafe-inline' *",
+ expected : "blocked"
+ }
+];
+
+var testIndex = 0;
+var messageCounter = 0;
+var curTest;
+
+// onError handler is over-reporting, hence we make sure that
+// we get an error for both testcases: data and blob before we
+// move on to the next test.
+var dataRan = false;
+var blobRan = false;
+
+// a postMessage handler to communicate the results back to the parent.
+window.addEventListener("message", receiveMessage);
+
+function receiveMessage(event)
+{
+ is(event.data.result, curTest.expected, event.data.scheme + " should be " + curTest.expected);
+
+ if (event.data.scheme === "data") {
+ dataRan = true;
+ }
+ if (event.data.scheme === "blob") {
+ blobRan = true;
+ }
+ if (dataRan && blobRan) {
+ loadNextTest();
+ }
+}
+
+function loadNextTest() {
+ if (testIndex === tests.length) {
+ window.removeEventListener("message", receiveMessage);
+ SimpleTest.finish();
+ return;
+ }
+
+ dataRan = false;
+ blobRan = false;
+
+ curTest = tests[testIndex++];
+ // reset the messageCounter to make sure we receive all the postMessages from the iframe
+ messageCounter = 0;
+
+ var src = "file_testserver.sjs";
+ // append the file that should be served
+ src += "?file=" + escape("tests/dom/security/test/csp/file_blob_data_schemes.html");
+ // append the CSP that should be used to serve the file
+ src += "&csp=" + escape(curTest.policy);
+
+ document.getElementById("testframe").src = src;
+}
+
+SimpleTest.waitForExplicitFinish();
+loadNextTest();
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_blob_uri_blocks_modals.html b/dom/security/test/csp/test_blob_uri_blocks_modals.html
new file mode 100644
index 0000000000..3f8de94ed2
--- /dev/null
+++ b/dom/security/test/csp/test_blob_uri_blocks_modals.html
@@ -0,0 +1,79 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Bug 1432170 - Block alert box and new window open as per the sandbox
+ allow-scripts CSP</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js">
+ </script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<iframe style="width:100%;" id="testframe"></iframe>
+<script>
+
+/* Description of the test:
+ * We apply the sanbox allow-scripts CSP to the blob iframe and check
+ * if the alert box and new window open is blocked correctly by the CSP.
+ */
+var testsToRun = {
+ block_window_open_test: false,
+ block_alert_test: false,
+ block_top_nav_alert_test: false,
+};
+
+SimpleTest.waitForExplicitFinish();
+SimpleTest.requestFlakyTimeout("have to test that alert dialogue is blocked");
+
+window.addEventListener("message", receiveMessage);
+function receiveMessage(event) {
+ switch (event.data.test) {
+ case "block_window_open_test":
+ testsToRun.block_window_open_test = true;
+ break;
+ case "block_alert_test":
+ is(event.data.msg, "alert blocked by CSP", "alert blocked by CSP");
+ testsToRun.block_alert_test = true;
+ break;
+ case "block_top_nav_alert_test":
+ testsToRun.block_top_nav_alert_test = true;
+ break;
+ }
+}
+
+var w;
+// Set "privacy.partition.bloburl_per_agent_cluster" to false until Bug 1667348 is fixed.
+SpecialPowers.pushPrefEnv({
+ set: [["privacy.partition.bloburl_per_agent_cluster", false]]}, () => {
+ // start the test
+ document.getElementById("testframe").src = "file_blob_uri_blocks_modals.html";
+ w = window.open("file_blob_top_nav_block_modals.html");
+});
+
+// If alert window is not blocked by CSP then event message is not recieved and
+// test fails after setTimeout interval of 1 second.
+setTimeout(function () {
+ is(testsToRun.block_top_nav_alert_test, true,
+ "blob top nav alert should be blocked by CSP");
+ testsToRun.block_top_nav_alert_test = true;
+ is(testsToRun.block_alert_test, true,
+ "alert should be blocked by CSP");
+ testsToRun.block_alert_test = true;
+ checkTestsCompleted();
+ },1000);
+
+function checkTestsCompleted() {
+ for (var prop in testsToRun) {
+ // some test hasn't run yet so we're not done
+ if (!testsToRun[prop]) {
+ return;
+ }
+ }
+ window.removeEventListener("message", receiveMessage);
+ w.close();
+ SimpleTest.finish();
+}
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_block_all_mixed_content.html b/dom/security/test/csp/test_block_all_mixed_content.html
new file mode 100644
index 0000000000..d60f904b6c
--- /dev/null
+++ b/dom/security/test/csp/test_block_all_mixed_content.html
@@ -0,0 +1,99 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Bug 1122236 - CSP: Implement block-all-mixed-content</title>
+ <!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<iframe style="width:100%;" id="testframe"></iframe>
+
+<script class="testbody" type="text/javascript">
+
+/* Description of the tests:
+ * Test 1:
+ * We load mixed display content in a frame using the CSP
+ * directive 'block-all-mixed-content' and observe that the image is blocked.
+ *
+ * Test 2:
+ * We load mixed display content in a frame using a CSP that allows the load
+ * and observe that the image is loaded.
+ *
+ * Test 3:
+ * We load mixed display content in a frame not using a CSP at all
+ * and observe that the image is loaded.
+ *
+ * Test 4:
+ * We load mixed display content in a frame using the CSP
+ * directive 'block-all-mixed-content' and observe that the image is blocked.
+ * Please note that Test 3 loads the image we are about to load in Test 4 into
+ * the img cache. Let's make sure the cached (mixed display content) image is
+ * not allowed to be loaded.
+ */
+
+const BASE_URI = "https://example.com/tests/dom/security/test/csp/";
+
+const tests = [
+ { // Test 1
+ query: "csp-block",
+ expected: "img-blocked",
+ description: "(csp-block) block-all-mixed content should block mixed display content"
+ },
+ { // Test 2
+ query: "csp-allow",
+ expected: "img-loaded",
+ description: "(csp-allow) mixed display content should be loaded"
+ },
+ { // Test 3
+ query: "no-csp",
+ expected: "img-loaded",
+ description: "(no-csp) mixed display content should be loaded"
+ },
+ { // Test 4
+ query: "csp-block",
+ expected: "img-blocked",
+ description: "(csp-block) block-all-mixed content should block insecure cache loads"
+ },
+ { // Test 5
+ query: "cspro-block",
+ expected: "img-loaded",
+ description: "(cspro-block) block-all-mixed in report only mode should not block"
+ },
+];
+
+var curTest;
+var counter = -1;
+
+function checkResults(result) {
+ is(result, curTest.expected, curTest.description);
+ loadNextTest();
+}
+
+window.addEventListener("message", receiveMessage);
+function receiveMessage(event) {
+ checkResults(event.data.result);
+}
+
+function loadNextTest() {
+ counter++;
+ if (counter == tests.length) {
+ window.removeEventListener("message", receiveMessage);
+ SimpleTest.finish();
+ return;
+ }
+ curTest = tests[counter];
+ testframe.src = BASE_URI + "file_block_all_mcb.sjs?" + curTest.query;
+}
+
+SimpleTest.waitForExplicitFinish();
+
+SpecialPowers.pushPrefEnv(
+ { 'set': [["security.mixed_content.block_display_content", false]] },
+ function() { loadNextTest(); }
+);
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_block_all_mixed_content_frame_navigation.html b/dom/security/test/csp/test_block_all_mixed_content_frame_navigation.html
new file mode 100644
index 0000000000..b32c1fccd5
--- /dev/null
+++ b/dom/security/test/csp/test_block_all_mixed_content_frame_navigation.html
@@ -0,0 +1,46 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Bug 1122236 - CSP: Implement block-all-mixed-content</title>
+ <!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<iframe style="width:100%;" id="testframe"></iframe>
+
+<script class="testbody" type="text/javascript">
+
+/* Description of the test:
+ *
+ * http://a.com embeds https://b.com.
+ * https://b.com has a CSP using 'block-all-mixed-content'.
+ * | site | http://a.com
+ * | embeds | https://b.com (uses block-all-mixed-content)
+ *
+ * The user navigates the embedded frame from
+ * https://b.com -> http://c.com.
+ * The test makes sure that such a navigation is not blocked
+ * by block-all-mixed-content.
+ */
+
+function checkResults(result) {
+ is(result, "frame-navigated", "frame should be allowed to be navigated");
+ window.removeEventListener("message", receiveMessage);
+ SimpleTest.finish();
+}
+
+window.addEventListener("message", receiveMessage);
+function receiveMessage(event) {
+ checkResults(event.data.result);
+}
+
+SimpleTest.waitForExplicitFinish();
+// http://a.com loads https://b.com
+document.getElementById("testframe").src =
+ "https://example.com/tests/dom/security/test/csp/file_block_all_mixed_content_frame_navigation1.html";
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_blocked_uri_in_reports.html b/dom/security/test/csp/test_blocked_uri_in_reports.html
new file mode 100644
index 0000000000..f40d98efc5
--- /dev/null
+++ b/dom/security/test/csp/test_blocked_uri_in_reports.html
@@ -0,0 +1,80 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 1069762 - Check blocked-uri in csp-reports after redirect</title>
+ <!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+
+<iframe style="width:200px;height:200px;" id='cspframe'></iframe>
+<script class="testbody" type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+
+/* Description of the test:
+ * We try to load a script from:
+ * http://example.com/tests/dom/security/test/csp/file_path_matching_redirect_server.sjs
+ * which gets redirected to:
+ * http://test1.example.com/tests/dom/security//test/csp/file_path_matching.js
+ *
+ * The blocked-uri in the csp-report should be the original URI:
+ * http://example.com/tests/dom/security/test/csp/file_path_matching_redirect_server.sjs
+ * instead of the redirected URI:
+ * http://test1.example.com/tests/com/security/test/csp/file_path_matching.js
+ *
+ * see also: http://www.w3.org/TR/CSP/#violation-reports
+ *
+ * Note, that we reuse the test-setup from
+ * test_path_matching_redirect.html
+ */
+
+const reportURI = "http://mochi.test:8888/foo.sjs";
+const policy = "script-src http://example.com; report-uri " + reportURI;
+const testfile = "tests/dom/security/test/csp/file_path_matching_redirect.html";
+
+var chromeScriptUrl = SimpleTest.getTestFileURL("file_report_chromescript.js");
+var script = SpecialPowers.loadChromeScript(chromeScriptUrl);
+
+script.addMessageListener('opening-request-completed', function ml(msg) {
+ if (msg.error) {
+ ok(false, "Could not query report (exception: " + msg.error + ")");
+ } else {
+ try {
+ var reportObj = JSON.parse(msg.report);
+ } catch (e) {
+ ok(false, "Could not parse JSON (exception: " + e + ")");
+ }
+ try {
+ var cspReport = reportObj["csp-report"];
+ // blocked-uri should only be the asciiHost instead of:
+ // http://test1.example.com/tests/dom/security/test/csp/file_path_matching.js
+ is(cspReport["blocked-uri"], "http://example.com/tests/dom/security/test/csp/file_path_matching_redirect_server.sjs", "Incorrect blocked-uri");
+ } catch (e) {
+ ok(false, "Could not query report (exception: " + e + ")");
+ }
+ }
+
+ script.removeMessageListener('opening-request-completed', ml);
+ script.sendAsyncMessage("finish");
+ SimpleTest.finish();
+});
+
+SimpleTest.waitForExplicitFinish();
+
+function runTest() {
+ var src = "file_testserver.sjs";
+ // append the file that should be served
+ src += "?file=" + escape(testfile);
+ // append the CSP that should be used to serve the file
+ src += "&csp=" + escape(policy);
+
+ document.getElementById("cspframe").src = src;
+}
+
+runTest();
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_blocked_uri_in_violation_event_after_redirects.html b/dom/security/test/csp/test_blocked_uri_in_violation_event_after_redirects.html
new file mode 100644
index 0000000000..6965cbeb92
--- /dev/null
+++ b/dom/security/test/csp/test_blocked_uri_in_violation_event_after_redirects.html
@@ -0,0 +1,56 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 1542194 - Check blockedURI in violation reports after redirects</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+
+<iframe id='testframe'></iframe>
+
+<script class="testbody" type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+
+let seenViolations = 0;
+let expectedViolations = 3;
+
+window.addEventListener("message", receiveMessage);
+function receiveMessage(event) {
+
+ seenViolations++;
+
+ let blockedURI = event.data.blockedURI;
+
+ if (blockedURI.includes("test1")) {
+ is(blockedURI,
+ "http://example.com/tests/dom/security/test/csp/file_blocked_uri_in_violation_event_after_redirects.sjs?test1a",
+ "Test 1 should be the URI before redirect");
+ } else if (blockedURI.includes("test2")) {
+ is(blockedURI,
+ "http://test2.example.com",
+ "Test 2 should be the redirected pre-path URI");
+ } else if (blockedURI.includes("test3")) {
+ is(blockedURI,
+ "http://test3.example.com",
+ "Test 3 should be the redirected pre-path URI");
+ } else {
+ ok(false, "sanity: how can we end up here?");
+ }
+
+ if (seenViolations < expectedViolations) {
+ return;
+ }
+
+ window.removeEventListener("message", receiveMessage);
+ SimpleTest.finish();
+}
+
+let testframe = document.getElementById("testframe");
+// This has to be same-origin with the test1 URL.
+testframe.src = "http://example.com/tests/dom/security/test/csp/file_blocked_uri_in_violation_event_after_redirects.html";
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_blocked_uri_redirect_frame_src.html b/dom/security/test/csp/test_blocked_uri_redirect_frame_src.html
new file mode 100644
index 0000000000..a946718bc2
--- /dev/null
+++ b/dom/security/test/csp/test_blocked_uri_redirect_frame_src.html
@@ -0,0 +1,60 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 1687342 - Check blocked-uri in csp-reports after frame redirect</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+
+<iframe id='testframe'></iframe>
+
+<script class="testbody" type="text/javascript">
+
+ /* Description of the test:
+ * We load a document from http://mochi.test with a CSP of `frame-src example.com`.
+ * We then load an iframe from example.com which redirects to test1.example.com and
+ * ensure that the report-uri is the origin of the frame before the blocked redirect.
+ */
+
+SimpleTest.waitForExplicitFinish();
+
+const BLOCKED_URI = "http://example.com";
+
+var chromeScriptUrl = SimpleTest.getTestFileURL("file_report_chromescript.js");
+var script = SpecialPowers.loadChromeScript(chromeScriptUrl);
+
+script.addMessageListener('opening-request-completed', function ml(msg) {
+ if (msg.error) {
+ ok(false, "Could not query report (exception: " + msg.error + ")");
+ return;
+ }
+ try {
+ var reportObj = JSON.parse(msg.report);
+ } catch (e) {
+ ok(false, "Could not parse JSON (exception: " + e + ")");
+ }
+ try {
+ var cspReport = reportObj["csp-report"];
+ is(cspReport["blocked-uri"], BLOCKED_URI, "Incorrect blocked-uri");
+ } catch (e) {
+ ok(false, "Could not query report (exception: " + e + ")");
+ }
+
+ script.removeMessageListener('opening-request-completed', ml);
+ script.sendAsyncMessage("finish");
+ SimpleTest.finish();
+});
+
+SimpleTest.waitForExplicitFinish();
+
+function runTest() {
+ let testframe = document.getElementById("testframe");
+ testframe.src = "file_blocked_uri_redirect_frame_src.html";
+}
+
+runTest();
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_bug1229639.html b/dom/security/test/csp/test_bug1229639.html
new file mode 100644
index 0000000000..e224fe1ffb
--- /dev/null
+++ b/dom/security/test/csp/test_bug1229639.html
@@ -0,0 +1,51 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Bug 1229639 - Percent encoded CSP path matching.</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none"></div>
+
+<iframe style="width:200px;height:200px;" id='cspframe'></iframe>
+<script class="testbody" type="text/javascript">
+
+// This is used to watch the blocked data bounce off CSP and allowed data
+// get sent out to the wire.
+function examiner() {
+ SpecialPowers.addObserver(this, "csp-on-violate-policy");
+ SpecialPowers.addObserver(this, "specialpowers-http-notify-request");
+}
+
+examiner.prototype = {
+ observe(subject, topic, data) {
+ if (data === 'http://mochi.test:8888/tests/dom/security/test/csp/%24.js') {
+ is(topic, "specialpowers-http-notify-request");
+ this.remove();
+ SimpleTest.finish();
+ }
+ },
+
+ // must eventually call this to remove the listener,
+ // or mochitests might get borked.
+ remove() {
+ SpecialPowers.removeObserver(this, "csp-on-violate-policy");
+ SpecialPowers.removeObserver(this, "specialpowers-http-notify-request");
+ }
+}
+
+window.examiner = new examiner();
+
+SimpleTest.waitForExplicitFinish();
+
+// save this for last so that our listeners are registered.
+// ... this loads the testbed of good and bad requests.
+document.getElementById('cspframe').src = 'file_bug1229639.html';
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_bug1242019.html b/dom/security/test/csp/test_bug1242019.html
new file mode 100644
index 0000000000..14e8f74baa
--- /dev/null
+++ b/dom/security/test/csp/test_bug1242019.html
@@ -0,0 +1,51 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1242019
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1242019</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1242019">Mozilla Bug 1242019</a>
+<p id="display"></p>
+
+<iframe id="cspframe"></iframe>
+
+<pre id="test">
+
+<script class="testbody" type="text/javascript">
+function cleanup() {
+ SpecialPowers.postConsoleSentinel();
+ SimpleTest.finish();
+};
+
+var expectedURI = "data:image/png;base64,iVBORw0KGgoAAAANSU"
+
+SpecialPowers.registerConsoleListener(function ConsoleMsgListener(aMsg) {
+ // look for the message with data uri and see the data uri is truncated to 40 chars
+ data_start = aMsg.message.indexOf(expectedURI)
+ if (data_start > -1) {
+ data_uri = "";
+ data_uri = aMsg.message.substr(data_start);
+ // this will either match the elipsis after the URI or the . at the end of the message
+ data_uri = data_uri.substr(0, data_uri.indexOf("…"));
+ if (data_uri == "") {
+ return;
+ }
+
+ ok(data_uri.length == 40, "Data URI only shows 40 characters in the console");
+ SimpleTest.executeSoon(cleanup);
+ }
+});
+
+// set up and start testing
+SimpleTest.waitForExplicitFinish();
+document.getElementById('cspframe').src = 'file_data-uri_blocked.html';
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_bug1312272.html b/dom/security/test/csp/test_bug1312272.html
new file mode 100644
index 0000000000..b06b08d092
--- /dev/null
+++ b/dom/security/test/csp/test_bug1312272.html
@@ -0,0 +1,32 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+
+ <title>Test for bug 1312272</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<iframe id="cspframe" style="width:100%"></iframe>
+
+<script type="text/javascript">
+SimpleTest.waitForExplicitFinish();
+function handler(evt) {
+ console.log(evt);
+ if (evt.data === "finish") {
+ ok(true, 'Other events continue to work fine.')
+ SimpleTest.finish();
+ //removeEventListener('message', handler);
+ } else {
+ ok(false, "Should not get any other message")
+ }
+}
+var cspframe = document.getElementById("cspframe");
+cspframe.src = "file_bug1312272.html";
+addEventListener("message", handler);
+console.log("assignign frame");
+</script>
+
+</body>
+</html>
diff --git a/dom/security/test/csp/test_bug1388015.html b/dom/security/test/csp/test_bug1388015.html
new file mode 100644
index 0000000000..5ca0605688
--- /dev/null
+++ b/dom/security/test/csp/test_bug1388015.html
@@ -0,0 +1,46 @@
+<!DOCTYPE HTML>
+<html>
+
+<head>
+ <title>Bug 1388015 - Test if Firefox respect Port in Wildcard Host </title>
+ <meta http-equiv="Content-Security-Policy" content="img-src https://*:443">
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+
+<body>
+
+ <img alt="Should be Blocked">
+ <script class="testbody" type="text/javascript">
+ SimpleTest.waitForExplicitFinish();
+
+ let image = document.querySelector("img");
+
+ Promise.race([
+ new Promise((res) => {
+ window.addEventListener("securitypolicyviolation", () => res(true), {once:true});
+ }),
+ new Promise((res) => {
+ image.addEventListener("load", () => res(false),{once:true});
+ })])
+ .then((result) => {
+ ok(result, " CSP did block Image with wildcard and mismatched Port");
+ })
+ .then(()=> Promise.race([
+ new Promise((res) => {
+ window.addEventListener("securitypolicyviolation", () => res(false), {once:true});
+ }),
+ new Promise((res) => {
+ image.addEventListener("load", () => res(true),{once:true});
+ requestIdleCallback(()=>{
+ image.src = "https://example.com:443/tests/dom/security/test/csp/file_dummy_pixel.png"
+ })
+ })]))
+ .then((result) => {
+ ok(result, " CSP did load the Image with wildcard and matching Port");
+ SimpleTest.finish();
+ })
+ image.src = "file_dummy_pixel.png" // mochi.test:8888
+ </script>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_bug1452037.html b/dom/security/test/csp/test_bug1452037.html
new file mode 100644
index 0000000000..fa46e91291
--- /dev/null
+++ b/dom/security/test/csp/test_bug1452037.html
@@ -0,0 +1,41 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test if "script-src: sha-... " Allowlists "javascript:" URIs</title>
+ <!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+ <iframe></iframe>
+
+<script class="testbody">
+ SimpleTest.requestCompleteLog();
+ SimpleTest.waitForExplicitFinish();
+
+ let frame = document.querySelector("iframe");
+
+ window.addEventListener("message", (msg) => {
+ ok(false, "The CSP did not block javascript:uri");
+ SimpleTest.finish();
+ });
+
+ document.addEventListener("securitypolicyviolation", () => {
+ ok(true, "The CSP did block javascript:uri");
+ SimpleTest.finish();
+ });
+
+ frame.addEventListener("load", () => {
+ let link = frame.contentWindow.document.querySelector("a");
+ frame.contentWindow.document.addEventListener("securitypolicyviolation", () => {
+ ok(true, "The CSP did block javascript:uri");
+ SimpleTest.finish();
+ })
+ link.click();
+ });
+ frame.src = "file_bug1452037.html";
+
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_bug1505412.html b/dom/security/test/csp/test_bug1505412.html
new file mode 100644
index 0000000000..717af2054b
--- /dev/null
+++ b/dom/security/test/csp/test_bug1505412.html
@@ -0,0 +1,50 @@
+<!DOCTYPE HTML>
+<html>
+
+<head>
+ <title> Bug 1505412 CSP-RO reports violations in inline-scripts with nonce</title>
+ <script src="/tests/SimpleTest/SimpleTest.js" nonce="foobar"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+
+
+<body>
+ <p id="display"></p>
+ <div id="content" style="display: none">
+ </div>
+
+ <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1505412">Test for 1505412 </a>
+ <script class="testbody" type="text/javascript" nonce="foobar">
+ /* Description of the test:
+ 1: We setup a Proxy that will cause the Test to Fail
+ if Firefox sends a CSP-Report to /report
+ 2: We Load an iframe with has a Script pointing to
+ file_bug1505412.sjs
+ 3: The Preloader will fetch the file and Gets redirected
+ 4: If correct, the File should be loaded and no CSP-Report
+ should be send.
+ */
+
+
+
+ SimpleTest.waitForExplicitFinish();
+ SimpleTest.requestCompleteLog();
+ SimpleTest.requestLongerTimeout(2); // Or might fail for Linux-Debug in some cases.
+ var script;
+
+ window.addEventListener("load",()=>{
+ let t = document.querySelector("#target");
+ t.src = "file_bug1505412_frame.html";
+ t.addEventListener("load",async () => {
+ let reportCount = await fetch("file_bug1505412_reporter.sjs?state").then(r => r.text());
+ info(reportCount);
+ ok(reportCount == 0 , "Script Loaded without CSP beeing triggered");
+ await fetch("file_bug1505412_reporter.sjs?flush");
+ SimpleTest.finish();
+ });
+ })
+
+ </script>
+ <iframe id="target" frameborder="0"></iframe>
+</body>
+
+</html> \ No newline at end of file
diff --git a/dom/security/test/csp/test_bug1579094.html b/dom/security/test/csp/test_bug1579094.html
new file mode 100644
index 0000000000..b3568586d4
--- /dev/null
+++ b/dom/security/test/csp/test_bug1579094.html
@@ -0,0 +1,31 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test if Wildcard CSP supports ExternalProtocol</title>
+ <!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <meta meta http-equiv="Content-security-policy" content="frame-src SomeExternalProto://*">
+</head>
+<body>
+ <p id="display"></p>
+ <div id="content" style="display: none"></div>
+<script class="testbody" type="text/javascript">
+ SimpleTest.waitForExplicitFinish();
+
+ document.addEventListener("securitypolicyviolation",()=>{
+ ok(false, "Error: ExternalProtocol Was blocked");
+ SimpleTest.finish();
+ });
+
+ window.addEventListener("load", ()=>{
+ ok(true, "Error: ExternalProtocol was passed");
+ SimpleTest.finish();
+ });
+</script>
+
+<iframe src="SomeExternalProto:foo@bar.com">
+
+
+</body>
+</html>
diff --git a/dom/security/test/csp/test_bug1738418.html b/dom/security/test/csp/test_bug1738418.html
new file mode 100644
index 0000000000..9fdc723b80
--- /dev/null
+++ b/dom/security/test/csp/test_bug1738418.html
@@ -0,0 +1,28 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 1738418: CSP sandbox for embed/object frames</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<iframe id="testframe"></iframe>
+<script class="testbody" type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+
+var elements = new Set(["iframe", "embed", "object"]);
+
+window.addEventListener("message", event => {
+ is(event.data.domain, "", `document in <${event.data.element}> should have sandboxed origin`);
+ elements.delete(event.data.element);
+ if (elements.size == 0) {
+ SimpleTest.finish();
+ }
+});
+
+document.getElementById("testframe").src = "file_bug1738418_parent.html";
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_bug1764343.html b/dom/security/test/csp/test_bug1764343.html
new file mode 100644
index 0000000000..1af9a710fe
--- /dev/null
+++ b/dom/security/test/csp/test_bug1764343.html
@@ -0,0 +1,116 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Bug 1764343 - CSP inheritance for same-origin iframes</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+
+ <meta http-equiv="Content-Security-Policy" content="style-src 'unsafe-inline'; script-src 'nonce-parent' 'nonce-a' 'nonce-b' 'nonce-c'; img-src 'self' data:">
+</head>
+<body>
+ <iframe id="sameOriginMetaFrame"></iframe>
+ <iframe id="aboutBlankMetaFrame"></iframe>
+<script nonce='parent'>
+SimpleTest.waitForExplicitFinish();
+
+const NEW_HTML =`
+ <head>
+ <meta http-equiv="Content-Security-Policy" content="script-src 'nonce-a' 'nonce-c' 'nonce-d';">
+ </head>
+ <body>
+ <style>
+ body { background-color: rgb(255, 0, 0); }
+ </style>
+ <script nonce="a">
+ document.a = true;
+ <\/script>
+ <script nonce="b">
+ document.b = true;
+ <\/script>
+ <script nonce="c">
+ document.c = true;
+ <\/script>
+ <script nonce="d">
+ document.d = true;
+ <\/script>
+ <img id="testInlineImage"></img>
+ </body>
+ `;
+
+// test file's CSP meta tags shouldn't overwrite same-origin iframe's CSP meta tags
+async function testBlocked() {
+ info("testBlocked");
+
+ let sameOriginMetaFrame = document.getElementById("sameOriginMetaFrame");
+ let onFrameLoad = new Promise(resolve => {
+ sameOriginMetaFrame.addEventListener('load', resolve, {once: true});
+ });
+ sameOriginMetaFrame.src = 'file_bug1764343.html';
+ await onFrameLoad;
+
+ let doc = sameOriginMetaFrame.contentDocument;
+ doc.open();
+ doc.write(NEW_HTML);
+
+ let bgcolor = window.getComputedStyle(doc.body).getPropertyValue("background-color");
+ is(bgcolor, "rgba(0, 0, 0, 0)", "inital background value in FF should be 'transparent'");
+
+ let img = doc.getElementById("testInlineImage");
+ let onImgError = new Promise(resolve => {
+ img.addEventListener('error', resolve, {once: true});
+ });
+ img.src = "//mochi.test:8888/tests/image/test/mochitest/blue.png";
+ await onImgError;
+ is(img.complete, false, "image should not be loaded");
+
+ // Make sure that CSP policy can further restrict (no 'nonce-b'), but not weak (adding 'nonce-c' or 'nonce-d')
+ is(doc.a, true, "doc.a should be true (script 'nonce-a' allowed)");
+ is(doc.b, undefined, "doc.b should be undefined (script 'nonce-b' blocked)");
+ is(doc.c, undefined, "doc.c should be undefined (script 'nonce-c' blocked)");
+ is(doc.d, undefined, "doc.d should be undefined (script 'nonce-d' blocked)");
+}
+
+ // test file's CSP meta tags should apply to about blank iframe's CSP meta tags
+async function testNotBlocked() {
+ info("testNotBlocked");
+
+ let aboutBlankMetaFrame = document.getElementById("aboutBlankMetaFrame");
+ let onFrameLoad = new Promise(resolve => {
+ aboutBlankMetaFrame.addEventListener('load', resolve, {once: true});
+ });
+ aboutBlankMetaFrame.src = 'about:blank';
+ await onFrameLoad;
+
+ let doc = aboutBlankMetaFrame.contentDocument;
+ doc.open();
+ doc.write(NEW_HTML);
+
+ let bgcolor = window.getComputedStyle(doc.body).getPropertyValue("background-color");
+ is(bgcolor, "rgb(255, 0, 0)", "background value should be updated to red");
+
+ let img = doc.getElementById("testInlineImage");
+ let onImgLoad = new Promise(resolve => {
+ img.addEventListener('load', resolve, {once: true});
+ });
+ img.src = "//mochi.test:8888/tests/image/test/mochitest/blue.png";
+ await onImgLoad;
+ is(img.complete, true, "image should be loaded");
+
+ // New HTML contains 'nonce-a/c/d' and no CSP in about:blank.
+ // (Can not weaken parent with 'nonce-d')
+ is(doc.a, true, "doc.a should be true (script 'nonce-a' allowed)");
+ is(doc.b, undefined, "doc.b should be undefined (script 'nonce-b' blocked)");
+ is(doc.c, true, "doc.c should be true (script 'nonce-c' allowed)");
+ is(doc.d, undefined, "doc.d should be true (script 'nonce-d' blocked)");
+}
+
+(async function () {
+ await testBlocked();
+ await testNotBlocked();
+ SimpleTest.finish();
+})();
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_bug1777572.html b/dom/security/test/csp/test_bug1777572.html
new file mode 100644
index 0000000000..f735f4fb6a
--- /dev/null
+++ b/dom/security/test/csp/test_bug1777572.html
@@ -0,0 +1,40 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>bug 1777572</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
+ <script>
+ SimpleTest.waitForExplicitFinish();
+
+ async function testCSPInheritance(closeOpenerWindow) {
+ let url = "file_bug1777572.html";
+ if (closeOpenerWindow) {
+ url += "?close";
+ }
+ let win = window.open(url);
+ return new Promise((resolve) => {
+ window.addEventListener("message", (event) => {
+ ok(event.data.includes("img-src"), "Got expected data " + event.data);
+ resolve();
+ }, { once: true});
+ });
+ }
+
+ async function run() {
+ // Test that CSP inheritance to the initial about:blank works the same way
+ // whether or not the opener is already closed when window.open is called.
+ await testCSPInheritance(false);
+ await testCSPInheritance(true);
+ SimpleTest.finish();
+ }
+
+ </script>
+</head>
+<body onload="run()">
+<p id="display"></p>
+<div id="content" style="display: none"></div>
+<pre id="test"></pre>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_bug663567.html b/dom/security/test/csp/test_bug663567.html
new file mode 100644
index 0000000000..137d459654
--- /dev/null
+++ b/dom/security/test/csp/test_bug663567.html
@@ -0,0 +1,76 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test if XSLT stylesheet is subject to document's CSP</title>
+ <!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+ <p id="display"></p>
+ <div id="content" style="display: none"></div>
+ <iframe style="width:100%;" id='xsltframe'></iframe>
+ <iframe style="width:100%;" id='xsltframe2'></iframe>
+
+<script class="testbody" type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+
+// define the expected output of this test
+var header = "this xml file should be formatted using an xsl file(lower iframe should contain xml dump)!";
+
+var finishedTests = 0;
+var numberOfTests = 2;
+
+var checkExplicitFinish = function() {
+ finishedTests++;
+ if (finishedTests == numberOfTests) {
+ SimpleTest.finish();
+ }
+}
+
+function checkAllowed () {
+ /* The policy for this test is:
+ * Content-Security-Policy: default-src 'self'
+ *
+ * we load the xsl file using:
+ * <?xml-stylesheet type="text/xsl" href="file_bug663467.xsl"?>
+ */
+ try {
+ var cspframe = document.getElementById('xsltframe');
+ var xsltAllowedHeader = cspframe.contentWindow.document.getElementById('xsltheader').innerHTML;
+ is(xsltAllowedHeader, header, "XSLT loaded from 'self' should be allowed!");
+ }
+ catch (e) {
+ ok(false, "Error: could not access content in xsltframe!")
+ }
+ checkExplicitFinish();
+}
+
+function checkBlocked () {
+ /* The policy for this test is:
+ * Content-Security-Policy: default-src *.example.com
+ *
+ * we load the xsl file using:
+ * <?xml-stylesheet type="text/xsl" href="file_bug663467.xsl"?>
+ */
+ try {
+ var cspframe = document.getElementById('xsltframe2');
+ var xsltBlockedHeader = cspframe.contentWindow.document.getElementById('xsltheader');
+ is(xsltBlockedHeader, null, "XSLT loaded from different host should be blocked!");
+ }
+ catch (e) {
+ ok(false, "Error: could not access content in xsltframe2!")
+ }
+ checkExplicitFinish();
+}
+
+document.getElementById('xsltframe').addEventListener('load', checkAllowed);
+document.getElementById('xsltframe').src = 'file_bug663567_allows.xml';
+
+document.getElementById('xsltframe2').addEventListener('load', checkBlocked);
+document.getElementById('xsltframe2').src = 'file_bug663567_blocks.xml';
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_bug802872.html b/dom/security/test/csp/test_bug802872.html
new file mode 100644
index 0000000000..956159ddcc
--- /dev/null
+++ b/dom/security/test/csp/test_bug802872.html
@@ -0,0 +1,53 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 802872</title>
+ <!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+ <p id="display"></p>
+ <div id="content" style="display: none"></div>
+ <iframe style="width:100%;" id='eventframe'></iframe>
+
+<script class="testbody" type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+
+var finishedTests = 0;
+var numberOfTests = 2;
+
+var checkExplicitFinish = function () {
+ finishedTests++;
+ if (finishedTests == numberOfTests) {
+ SimpleTest.finish();
+ }
+}
+
+// add event listeners for CSP-permitted EventSrc callbacks
+addEventListener('allowedEventSrcCallbackOK', function (e) {
+ ok(true, "OK: CSP allows EventSource for allowlisted domain!");
+ checkExplicitFinish();
+}, false);
+addEventListener('allowedEventSrcCallbackFailed', function (e) {
+ ok(false, "Error: CSP blocks EventSource for allowlisted domain!");
+ checkExplicitFinish();
+}, false);
+
+// add event listeners for CSP-blocked EventSrc callbacks
+addEventListener('blockedEventSrcCallbackOK', function (e) {
+ ok(false, "Error: CSP allows EventSource to not allowlisted domain!");
+ checkExplicitFinish();
+}, false);
+addEventListener('blockedEventSrcCallbackFailed', function (e) {
+ ok(true, "OK: CSP blocks EventSource for not allowlisted domain!");
+ checkExplicitFinish();
+}, false);
+
+// load it
+document.getElementById('eventframe').src = 'file_bug802872.html';
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_bug836922_npolicies.html b/dom/security/test/csp/test_bug836922_npolicies.html
new file mode 100644
index 0000000000..e418969e3d
--- /dev/null
+++ b/dom/security/test/csp/test_bug836922_npolicies.html
@@ -0,0 +1,235 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for Content Security Policy multiple policy support (regular and Report-Only mode)</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+
+<iframe style="width:200px;height:200px;" id='cspframe'></iframe>
+<script class="testbody" type="text/javascript">
+
+var path = "/tests/dom/security/test/csp/";
+
+// These are test results: verified indicates whether or not the test has run.
+// true/false is the pass/fail result.
+window.loads = {
+ css_self: {expected: true, verified: false},
+ img_self: {expected: false, verified: false},
+ script_self: {expected: true, verified: false},
+};
+
+window.violation_reports = {
+ css_self:
+ {expected: 0, expected_ro: 0}, /* totally fine */
+ img_self:
+ {expected: 1, expected_ro: 0}, /* violates enforced CSP */
+ script_self:
+ {expected: 0, expected_ro: 1}, /* violates report-only */
+};
+
+// This is used to watch the blocked data bounce off CSP and allowed data
+// get sent out to the wire. This also watches for violation reports to go out.
+function examiner() {
+ SpecialPowers.addObserver(this, "csp-on-violate-policy");
+ SpecialPowers.addObserver(this, "specialpowers-http-notify-request");
+}
+examiner.prototype = {
+ observe(subject, topic, data) {
+ var testpat = new RegExp("testid=([a-z0-9_]+)");
+
+ if (topic === "specialpowers-http-notify-request") {
+ var uri = data;
+ if (!testpat.test(uri)) return;
+ var testid = testpat.exec(uri)[1];
+
+ // violation reports don't come through here, but the requested resources do
+ // if the test has already finished, move on. Some things throw multiple
+ // requests (preloads and such)
+ try {
+ if (window.loads[testid].verified) return;
+ } catch(e) { return; }
+
+ // these are requests that were allowed by CSP
+ var testid = testpat.exec(uri)[1];
+ window.testResult(testid, 'allowed', uri + " allowed by csp");
+ }
+
+ if(topic === "csp-on-violate-policy") {
+ // if the violated policy was report-only, the resource will still be
+ // loaded even if this topic is notified.
+ var asciiSpec = SpecialPowers.getPrivilegedProps(
+ SpecialPowers.do_QueryInterface(subject, "nsIURI"),
+ "asciiSpec");
+ if (!testpat.test(asciiSpec)) return;
+ var testid = testpat.exec(asciiSpec)[1];
+
+ // if the test has already finished, move on.
+ try {
+ if (window.loads[testid].verified) return;
+ } catch(e) { return; }
+
+ // record the ones that were supposed to be blocked, but don't use this
+ // as an indicator for tests that are not blocked but do generate reports.
+ // We skip recording the result if the load is expected since a
+ // report-only policy will generate a request *and* a violation note.
+ if (!window.loads[testid].expected) {
+ window.testResult(testid,
+ 'blocked',
+ asciiSpec + " blocked by \"" + data + "\"");
+ }
+ }
+
+ // if any test is unverified, keep waiting
+ for (var v in window.loads) {
+ if(!window.loads[v].verified) {
+ return;
+ }
+ }
+
+ window.bug836922examiner.remove();
+ window.resultPoller.pollForFinish();
+ },
+
+ // must eventually call this to remove the listener,
+ // or mochitests might get borked.
+ remove() {
+ SpecialPowers.removeObserver(this, "csp-on-violate-policy");
+ SpecialPowers.removeObserver(this, "specialpowers-http-notify-request");
+ }
+}
+window.bug836922examiner = new examiner();
+
+
+// Poll for results and see if enough reports came in. Keep trying
+// for a few seconds before failing with lack of reports.
+// Have to do this because there's a race between the async reporting
+// and this test finishing, and we don't want to win the race.
+window.resultPoller = {
+
+ POLL_ATTEMPTS_LEFT: 14,
+
+ pollForFinish() {
+ var vr = resultPoller.tallyReceivedReports();
+ if (resultPoller.verifyReports(vr, resultPoller.POLL_ATTEMPTS_LEFT < 1)) {
+ // report success condition.
+ resultPoller.resetReportServer();
+ SimpleTest.finish();
+ } else {
+ resultPoller.POLL_ATTEMPTS_LEFT--;
+ // try again unless we reached the threshold.
+ setTimeout(resultPoller.pollForFinish, 100);
+ }
+ },
+
+ resetReportServer() {
+ var xhr = new XMLHttpRequest();
+ var xhr_ro = new XMLHttpRequest();
+ xhr.open("GET", "file_bug836922_npolicies_violation.sjs?reset", false);
+ xhr_ro.open("GET", "file_bug836922_npolicies_ro_violation.sjs?reset", false);
+ xhr.send(null);
+ xhr_ro.send(null);
+ },
+
+ tallyReceivedReports() {
+ var xhr = new XMLHttpRequest();
+ var xhr_ro = new XMLHttpRequest();
+ xhr.open("GET", "file_bug836922_npolicies_violation.sjs?results", false);
+ xhr_ro.open("GET", "file_bug836922_npolicies_ro_violation.sjs?results", false);
+ xhr.send(null);
+ xhr_ro.send(null);
+
+ var received = JSON.parse(xhr.responseText);
+ var received_ro = JSON.parse(xhr_ro.responseText);
+
+ var results = {enforced: {}, reportonly: {}};
+ for (var r in window.violation_reports) {
+ results.enforced[r] = 0;
+ results.reportonly[r] = 0;
+ }
+
+ for (var r in received) {
+ results.enforced[r] += received[r];
+ }
+ for (var r in received_ro) {
+ results.reportonly[r] += received_ro[r];
+ }
+
+ return results;
+ },
+
+ verifyReports(receivedCounts, lastAttempt) {
+ for (var r in window.violation_reports) {
+ var exp = window.violation_reports[r].expected;
+ var exp_ro = window.violation_reports[r].expected_ro;
+ var rec = receivedCounts.enforced[r];
+ var rec_ro = receivedCounts.reportonly[r];
+
+ // if this test breaks, these are helpful dumps:
+ //dump(">>> Verifying " + r + "\n");
+ //dump(" > Expected: " + exp + " / " + exp_ro + " (ro)\n");
+ //dump(" > Received: " + rec + " / " + rec_ro + " (ro) \n");
+
+ // in all cases, we're looking for *at least* the expected number of
+ // reports of each type (there could be more in some edge cases).
+ // If there are not enough, we keep waiting and poll the server again
+ // later. If there are enough, we can successfully finish.
+
+ if (exp == 0)
+ is(rec, 0,
+ "Expected zero enforced-policy violation " +
+ "reports for " + r + ", got " + rec);
+ else if (lastAttempt)
+ ok(rec >= exp,
+ "Received (" + rec + "/" + exp + ") " +
+ "enforced-policy reports for " + r);
+ else if (rec < exp)
+ return false; // continue waiting for more
+
+ if(exp_ro == 0)
+ is(rec_ro, 0,
+ "Expected zero report-only-policy violation " +
+ "reports for " + r + ", got " + rec_ro);
+ else if (lastAttempt)
+ ok(rec_ro >= exp_ro,
+ "Received (" + rec_ro + "/" + exp_ro + ") " +
+ "report-only-policy reports for " + r);
+ else if (rec_ro < exp_ro)
+ return false; // continue waiting for more
+ }
+
+ // if we complete the loop, we've found all of the violation
+ // reports we expect.
+ if (lastAttempt) return true;
+
+ // Repeat successful tests once more to record successes via ok()
+ return resultPoller.verifyReports(receivedCounts, true);
+ }
+};
+
+window.testResult = function(testname, result, msg) {
+ // otherwise, make sure the allowed ones are expected and blocked ones are not.
+ if (window.loads[testname].expected) {
+ is(result, 'allowed', ">> " + msg);
+ } else {
+ is(result, 'blocked', ">> " + msg);
+ }
+ window.loads[testname].verified = true;
+}
+
+
+SimpleTest.waitForExplicitFinish();
+SimpleTest.requestFlakyTimeout("untriaged");
+
+// save this for last so that our listeners are registered.
+// ... this loads the testbed of good and bad requests.
+document.getElementById('cspframe').src = 'http://mochi.test:8888' + path + 'file_bug836922_npolicies.html';
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_bug885433.html b/dom/security/test/csp/test_bug885433.html
new file mode 100644
index 0000000000..c7c17d25b6
--- /dev/null
+++ b/dom/security/test/csp/test_bug885433.html
@@ -0,0 +1,61 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for Content Security Policy inline stylesheets stuff</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+
+<iframe style="width:100%;" id='cspframe'></iframe>
+<iframe style="width:100%;" id='cspframe2'></iframe>
+<script class="testbody" type="text/javascript">
+
+//////////////////////////////////////////////////////////////////////
+// set up and go
+SimpleTest.waitForExplicitFinish();
+
+// utilities for check functions
+// black means the style wasn't applied, applied styles are green
+var green = 'rgb(0, 128, 0)';
+var black = 'rgb(0, 0, 0)';
+
+// We test both script and style execution by observing changes in computed styles
+function checkAllowed () {
+ var cspframe = document.getElementById('cspframe');
+ var color;
+
+ color = window.getComputedStyle(cspframe.contentDocument.getElementById('unsafe-inline-script-allowed')).color;
+ ok(color === green, "Inline script should be allowed");
+ color = window.getComputedStyle(cspframe.contentDocument.getElementById('unsafe-eval-script-allowed')).color;
+ ok(color === green, "Eval should be allowed");
+ color = window.getComputedStyle(cspframe.contentDocument.getElementById('unsafe-inline-style-allowed')).color;
+ ok(color === green, "Inline style should be allowed");
+
+ document.getElementById('cspframe2').src = 'file_bug885433_blocks.html';
+ document.getElementById('cspframe2').addEventListener('load', checkBlocked);
+}
+
+function checkBlocked () {
+ var cspframe = document.getElementById('cspframe2');
+ var color;
+
+ color = window.getComputedStyle(cspframe.contentDocument.getElementById('unsafe-inline-script-blocked')).color;
+ ok(color === black, "Inline script should be blocked");
+ color = window.getComputedStyle(cspframe.contentDocument.getElementById('unsafe-eval-script-blocked')).color;
+ ok(color === black, "Eval should be blocked");
+ color = window.getComputedStyle(cspframe.contentDocument.getElementById('unsafe-inline-style-blocked')).color;
+ ok(color === black, "Inline style should be blocked");
+
+ SimpleTest.finish();
+}
+
+document.getElementById('cspframe').src = 'file_bug885433_allows.html';
+document.getElementById('cspframe').addEventListener('load', checkAllowed);
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_bug886164.html b/dom/security/test/csp/test_bug886164.html
new file mode 100644
index 0000000000..5347d42ed8
--- /dev/null
+++ b/dom/security/test/csp/test_bug886164.html
@@ -0,0 +1,172 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Bug 886164 - Enforce CSP in sandboxed iframe</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+<iframe style="width:200px;height:200px;" id='cspframe' sandbox="allow-same-origin"></iframe>
+<iframe style="width:200px;height:200px;" id='cspframe2' sandbox></iframe>
+<iframe style="width:200px;height:200px;" id='cspframe3' sandbox="allow-same-origin"></iframe>
+<iframe style="width:200px;height:200px;" id='cspframe4' sandbox></iframe>
+<iframe style="width:200px;height:200px;" id='cspframe5' sandbox="allow-scripts"></iframe>
+<iframe style="width:200px;height:200px;" id='cspframe6' sandbox="allow-same-origin allow-scripts"></iframe>
+<script class="testbody" type="text/javascript">
+
+
+var path = "/tests/dom/security/test/csp/";
+
+// These are test results: -1 means it hasn't run,
+// true/false is the pass/fail result.
+window.tests = {
+ // sandbox allow-same-origin; 'self'
+ img_good: -1, // same origin
+ img_bad: -1, //example.com
+
+ // sandbox; 'self'
+ img2_bad: -1, //example.com
+ img2a_good: -1, // same origin & is image
+
+ // sandbox allow-same-origin; 'none'
+ img3_bad: -1,
+ img3a_bad: -1,
+
+ // sandbox; 'none'
+ img4_bad: -1,
+ img4a_bad: -1,
+
+ // sandbox allow-scripts; 'none' 'unsafe-inline'
+ img5_bad: -1,
+ img5a_bad: -1,
+ script5_bad: -1,
+ script5a_bad: -1,
+
+ // sandbox allow-same-origin allow-scripts; 'self' 'unsafe-inline'
+ img6_bad: -1,
+ script6_bad: -1,
+};
+
+// a postMessage handler that is used by sandboxed iframes without
+// 'allow-same-origin' to communicate pass/fail back to this main page.
+// it expects to be called with an object like {ok: true/false, desc:
+// <description of the test> which it then forwards to ok()
+window.addEventListener("message", receiveMessage);
+
+function receiveMessage(event)
+{
+ ok_wrapper(event.data.ok, event.data.desc);
+}
+
+var cspTestsDone = false;
+var iframeSandboxTestsDone = false;
+
+// iframe related
+var completedTests = 0;
+var passedTests = 0;
+
+function ok_wrapper(result, desc) {
+ ok(result, desc);
+
+ completedTests++;
+
+ if (result) {
+ passedTests++;
+ }
+
+ if (completedTests === 5) {
+ iframeSandboxTestsDone = true;
+ if (cspTestsDone) {
+ SimpleTest.finish();
+ }
+ }
+}
+
+
+//csp related
+
+// This is used to watch the blocked data bounce off CSP and allowed data
+// get sent out to the wire.
+function examiner() {
+ SpecialPowers.addObserver(this, "csp-on-violate-policy");
+ SpecialPowers.addObserver(this, "specialpowers-http-notify-request");
+}
+examiner.prototype = {
+ observe(subject, topic, data) {
+ var testpat = new RegExp("testid=([a-z0-9_]+)");
+
+ //_good things better be allowed!
+ //_bad things better be stopped!
+
+ if (topic === "specialpowers-http-notify-request") {
+ //these things were allowed by CSP
+ var uri = data;
+ if (!testpat.test(uri)) return;
+ var testid = testpat.exec(uri)[1];
+
+ window.testResult(testid,
+ /_good/.test(testid),
+ uri + " allowed by csp");
+ }
+
+ if(topic === "csp-on-violate-policy") {
+ //these were blocked... record that they were blocked
+ var asciiSpec = SpecialPowers.getPrivilegedProps(SpecialPowers.do_QueryInterface(subject, "nsIURI"), "asciiSpec");
+ if (!testpat.test(asciiSpec)) return;
+ var testid = testpat.exec(asciiSpec)[1];
+ window.testResult(testid,
+ /_bad/.test(testid),
+ asciiSpec + " blocked by \"" + data + "\"");
+ }
+ },
+
+ // must eventually call this to remove the listener,
+ // or mochitests might get borked.
+ remove() {
+ SpecialPowers.removeObserver(this, "csp-on-violate-policy");
+ SpecialPowers.removeObserver(this, "specialpowers-http-notify-request");
+ }
+}
+
+window.examiner = new examiner();
+
+window.testResult = function(testname, result, msg) {
+ //test already complete.... forget it... remember the first result.
+ if (window.tests[testname] != -1)
+ return;
+
+ window.tests[testname] = result;
+ ok(result, testname + ' test: ' + msg);
+
+ // if any test is incomplete, keep waiting
+ for (var v in window.tests)
+ if(tests[v] == -1)
+ return;
+
+ // ... otherwise, finish
+ window.examiner.remove();
+ cspTestsDone = true;
+ if (iframeSandboxTestsDone) {
+ SimpleTest.finish();
+ }
+}
+
+SimpleTest.waitForExplicitFinish();
+
+// save this for last so that our listeners are registered.
+// ... this loads the testbed of good and bad requests.
+document.getElementById('cspframe').src = 'file_bug886164.html';
+document.getElementById('cspframe2').src = 'file_bug886164_2.html';
+document.getElementById('cspframe3').src = 'file_bug886164_3.html';
+document.getElementById('cspframe4').src = 'file_bug886164_4.html';
+document.getElementById('cspframe5').src = 'file_bug886164_5.html';
+document.getElementById('cspframe6').src = 'file_bug886164_6.html';
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_bug888172.html b/dom/security/test/csp/test_bug888172.html
new file mode 100644
index 0000000000..a78258e21f
--- /dev/null
+++ b/dom/security/test/csp/test_bug888172.html
@@ -0,0 +1,73 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 888172 - CSP 1.0 does not process 'unsafe-inline' or 'unsafe-eval' for default-src</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+
+<iframe style="width:100%;" id='testframe1'></iframe>
+<iframe style="width:100%;" id='testframe2'></iframe>
+<iframe style="width:100%;" id='testframe3'></iframe>
+<script class="testbody" type="text/javascript">
+
+//////////////////////////////////////////////////////////////////////
+// set up and go
+SimpleTest.waitForExplicitFinish();
+
+// utilities for check functions
+// black means the style wasn't applied, applied styles are green
+var green = 'rgb(0, 128, 0)';
+var black = 'rgb(0, 0, 0)';
+
+function getElementColorById(doc, id) {
+ return window.getComputedStyle(doc.contentDocument.getElementById(id)).color;
+}
+
+// We test both script and style execution by observing changes in computed styles
+function checkDefaultSrcOnly() {
+ var testframe = document.getElementById('testframe1');
+
+ ok(getElementColorById(testframe, 'unsafe-inline-script') === green, "Inline script should be allowed");
+ ok(getElementColorById(testframe, 'unsafe-eval-script') === green, "Eval should be allowed");
+ ok(getElementColorById(testframe, 'unsafe-inline-style') === green, "Inline style should be allowed");
+
+ document.getElementById('testframe2').src = 'file_bug888172.sjs?csp=' +
+ escape("default-src 'self' 'unsafe-inline' 'unsafe-eval'; script-src 'self'");
+ document.getElementById('testframe2').addEventListener('load', checkDefaultSrcWithScriptSrc);
+}
+
+function checkDefaultSrcWithScriptSrc() {
+ var testframe = document.getElementById('testframe2');
+
+ ok(getElementColorById(testframe, 'unsafe-inline-script') === black, "Inline script should be blocked");
+ ok(getElementColorById(testframe, 'unsafe-eval-script') === black, "Eval should be blocked");
+ ok(getElementColorById(testframe, 'unsafe-inline-style') === green, "Inline style should be allowed");
+
+ document.getElementById('testframe3').src = 'file_bug888172.sjs?csp=' +
+ escape("default-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self'");
+ document.getElementById('testframe3').addEventListener('load', checkDefaultSrcWithStyleSrc);
+}
+
+function checkDefaultSrcWithStyleSrc() {
+ var testframe = document.getElementById('testframe3');
+
+ ok(getElementColorById(testframe, 'unsafe-inline-script') === green, "Inline script should be allowed");
+ ok(getElementColorById(testframe, 'unsafe-eval-script') === green, "Eval should be allowed");
+ ok(getElementColorById(testframe, 'unsafe-inline-style') === black, "Inline style should be blocked");
+
+ // last test calls finish
+ SimpleTest.finish();
+}
+
+document.getElementById('testframe1').src = 'file_bug888172.sjs?csp=' +
+ escape("default-src 'self' 'unsafe-inline' 'unsafe-eval'");
+document.getElementById('testframe1').addEventListener('load', checkDefaultSrcOnly);
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_bug909029.html b/dom/security/test/csp/test_bug909029.html
new file mode 100644
index 0000000000..7a3ac81a1b
--- /dev/null
+++ b/dom/security/test/csp/test_bug909029.html
@@ -0,0 +1,129 @@
+<!doctype html>
+<html>
+ <head>
+ <title>Bug 909029 - CSP source-lists ignore some source expressions like 'unsafe-inline' when * or 'none' are used (e.g., style-src, script-src)</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ </head>
+ <body>
+ <div id=content style="visibility:hidden">
+ <iframe id=testframe1></iframe>
+ <iframe id=testframe2></iframe>
+ </div>
+ <script class="testbody" type="text/javascript">
+SimpleTest.waitForExplicitFinish();
+
+window.tests = {
+ starExternalStylesLoaded: -1,
+ starExternalImgLoaded: -1,
+ noneExternalStylesBlocked: -1,
+ noneExternalImgLoaded: -1,
+ starInlineStyleAllowed: -1,
+ starInlineScriptBlocked: -1,
+ noneInlineStyleAllowed: -1,
+ noneInlineScriptBlocked: -1
+}
+
+function examiner() {
+ SpecialPowers.addObserver(this, "csp-on-violate-policy");
+ SpecialPowers.addObserver(this, "specialpowers-http-notify-request");
+}
+examiner.prototype = {
+ observe(subject, topic, data) {
+ var testpat = new RegExp("testid=([a-zA-Z]+)");
+
+ if (topic === "specialpowers-http-notify-request") {
+ var uri = data;
+ if (!testpat.test(uri)) return;
+ var testid = testpat.exec(uri)[1];
+ window.testResult(testid,
+ /Loaded/.test(testid),
+ "resource loaded");
+ }
+
+ if(topic === "csp-on-violate-policy") {
+ // these were blocked... record that they were blocked
+ // try because the subject could be an nsIURI or an nsISupportsCString
+ try {
+ var asciiSpec = SpecialPowers.getPrivilegedProps(SpecialPowers.do_QueryInterface(subject, "nsIURI"), "asciiSpec");
+ if (!testpat.test(asciiSpec)) return;
+ var testid = testpat.exec(asciiSpec)[1];
+ window.testResult(testid,
+ /Blocked/.test(testid),
+ "resource blocked by CSP");
+ } catch(e) {
+ // if that fails, the subject is probably a string. Strings are only
+ // reported for inline and eval violations. Since we are testing those
+ // via the observed effects of script on CSSOM, we can simply ignore
+ // these subjects.
+ }
+ }
+ },
+
+ // must eventually call this to remove the listener,
+ // or mochitests might get borked.
+ remove() {
+ SpecialPowers.removeObserver(this, "csp-on-violate-policy");
+ SpecialPowers.removeObserver(this, "specialpowers-http-notify-request");
+ }
+}
+
+window.examiner = new examiner();
+
+window.testResult = function(testname, result, msg) {
+ //dump("in testResult: testname = " + testname + "\n");
+
+ //test already complete.... forget it... remember the first result.
+ if (window.tests[testname] != -1)
+ return;
+
+ window.tests[testname] = result;
+ is(result, true, testname + ' test: ' + msg);
+
+ // if any test is incomplete, keep waiting
+ for (var v in window.tests)
+ if(tests[v] == -1)
+ return;
+
+ // ... otherwise, finish
+ window.examiner.remove();
+ SimpleTest.finish();
+}
+
+// Helpers for inline script/style checks
+var black = 'rgb(0, 0, 0)';
+var green = 'rgb(0, 128, 0)';
+function getElementColorById(doc, id) {
+ return window.getComputedStyle(doc.contentDocument.getElementById(id)).color;
+}
+
+function checkInlineWithStar() {
+ var testframe = document.getElementById('testframe1');
+ window.testResult("starInlineStyleAllowed",
+ getElementColorById(testframe, 'inline-style') === green,
+ "Inline styles should be allowed (style-src 'unsafe-inline' with star)");
+ window.testResult("starInlineScriptBlocked",
+ getElementColorById(testframe, 'inline-script') === black,
+ "Inline scripts should be blocked (style-src 'unsafe-inline' with star)");
+}
+
+function checkInlineWithNone() {
+ // If a directive has 'none' in addition to other sources, 'none' is ignored
+ // and the other sources are used. 'none' is only a valid source if it is
+ // used by itself.
+ var testframe = document.getElementById('testframe2');
+ window.testResult("noneInlineStyleAllowed",
+ getElementColorById(testframe, 'inline-style') === green,
+ "Inline styles should be allowed (style-src 'unsafe-inline' with none)");
+ window.testResult("noneInlineScriptBlocked",
+ getElementColorById(testframe, 'inline-script') === black,
+ "Inline scripts should be blocked (style-src 'unsafe-inline' with none)");
+}
+
+document.getElementById('testframe1').src = 'file_bug909029_star.html';
+document.getElementById('testframe1').addEventListener('load', checkInlineWithStar);
+document.getElementById('testframe2').src = 'file_bug909029_none.html';
+document.getElementById('testframe2').addEventListener('load', checkInlineWithNone);
+ </script>
+ </body>
+</html>
diff --git a/dom/security/test/csp/test_bug910139.html b/dom/security/test/csp/test_bug910139.html
new file mode 100644
index 0000000000..bbebedf877
--- /dev/null
+++ b/dom/security/test/csp/test_bug910139.html
@@ -0,0 +1,66 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>CSP should block XSLT as script, not as style</title>
+ <!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+ <p id="display"></p>
+ <div id="content" style="display: none"></div>
+ <iframe style="width:100%;" id='xsltframe'></iframe>
+ <iframe style="width:100%;" id='xsltframe2'></iframe>
+
+<script class="testbody" type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+
+// define the expected output of this test
+var header = "this xml file should be formatted using an xsl file(lower iframe should contain xml dump)!";
+
+function checkAllowed () {
+ /* The policy for this test is:
+ * Content-Security-Policy: default-src 'self'; script-src 'self'
+ *
+ * we load the xsl file using:
+ * <?xml-stylesheet type="text/xsl" href="file_bug910139.xsl"?>
+ */
+ try {
+ var cspframe = document.getElementById('xsltframe');
+ var xsltAllowedHeader = cspframe.contentWindow.document.getElementById('xsltheader').innerHTML;
+ is(xsltAllowedHeader, header, "XSLT loaded from 'self' should be allowed!");
+ }
+ catch (e) {
+ ok(false, "Error: could not access content in xsltframe!")
+ }
+
+ // continue with the next test
+ document.getElementById('xsltframe2').addEventListener('load', checkBlocked);
+ document.getElementById('xsltframe2').src = 'file_bug910139.sjs';
+}
+
+function checkBlocked () {
+ /* The policy for this test is:
+ * Content-Security-Policy: default-src 'self'; script-src *.example.com
+ *
+ * we load the xsl file using:
+ * <?xml-stylesheet type="text/xsl" href="file_bug910139.xsl"?>
+ */
+ try {
+ var cspframe = document.getElementById('xsltframe2');
+ var xsltBlockedHeader = cspframe.contentWindow.document.getElementById('xsltheader');
+ is(xsltBlockedHeader, null, "XSLT loaded from different host should be blocked!");
+ }
+ catch (e) {
+ ok(false, "Error: could not access content in xsltframe2!")
+ }
+ SimpleTest.finish();
+}
+
+document.getElementById('xsltframe').addEventListener('load', checkAllowed);
+document.getElementById('xsltframe').src = 'file_bug910139.sjs';
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_bug941404.html b/dom/security/test/csp/test_bug941404.html
new file mode 100644
index 0000000000..7c35c38aa1
--- /dev/null
+++ b/dom/security/test/csp/test_bug941404.html
@@ -0,0 +1,107 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Bug 941404 - Data documents should not set CSP</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+
+</div>
+
+<iframe style="width:200px;height:200px;" id='cspframe'></iframe>
+<script class="testbody" type="text/javascript">
+
+
+var path = "/tests/dom/security/test/csp/";
+
+// These are test results: -1 means it hasn't run,
+// true/false is the pass/fail result.
+window.tests = {
+ img_good: -1,
+ img2_good: -1,
+};
+
+
+//csp related
+
+// This is used to watch the blocked data bounce off CSP and allowed data
+// get sent out to the wire.
+function examiner() {
+ SpecialPowers.addObserver(this, "csp-on-violate-policy");
+ SpecialPowers.addObserver(this, "specialpowers-http-notify-request");
+}
+
+examiner.prototype = {
+ observe(subject, topic, data) {
+ var testpat = new RegExp("testid=([a-z0-9_]+)");
+
+ //_good things better be allowed!
+ //_bad things better be stopped!
+
+ if (topic === "specialpowers-http-notify-request") {
+ //these things were allowed by CSP
+ var uri = data;
+ if (!testpat.test(uri)) return;
+ var testid = testpat.exec(uri)[1];
+
+ window.testResult(testid,
+ /_good/.test(testid),
+ uri + " allowed by csp");
+ }
+
+ if(topic === "csp-on-violate-policy") {
+ //these were blocked... record that they were blocked
+ var asciiSpec = SpecialPowers.getPrivilegedProps(SpecialPowers.do_QueryInterface(subject, "nsIURI"), "asciiSpec");
+ if (!testpat.test(asciiSpec)) return;
+ var testid = testpat.exec(asciiSpec)[1];
+ window.testResult(testid,
+ /_bad/.test(testid),
+ asciiSpec + " blocked by \"" + data + "\"");
+ }
+ },
+
+ // must eventually call this to remove the listener,
+ // or mochitests might get borked.
+ remove() {
+ SpecialPowers.removeObserver(this, "csp-on-violate-policy");
+ SpecialPowers.removeObserver(this, "specialpowers-http-notify-request");
+ }
+}
+
+window.examiner = new examiner();
+
+window.testResult = function(testname, result, msg) {
+ //test already complete.... forget it... remember the first result.
+ if (window.tests[testname] != -1)
+ return;
+
+ window.tests[testname] = result;
+ is(result, true, testname + ' test: ' + msg);
+
+ // if any test is incomplete, keep waiting
+ for (var v in window.tests)
+ if(tests[v] == -1) {
+ console.log(v + " is not complete");
+ return;
+ }
+
+ // ... otherwise, finish
+ window.examiner.remove();
+ SimpleTest.finish();
+}
+
+SimpleTest.waitForExplicitFinish();
+
+// save this for last so that our listeners are registered.
+// ... this loads the testbed of good and bad requests.
+document.getElementById('cspframe').src = 'file_bug941404.html';
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_child-src_iframe.html b/dom/security/test/csp/test_child-src_iframe.html
new file mode 100644
index 0000000000..2b85e280bd
--- /dev/null
+++ b/dom/security/test/csp/test_child-src_iframe.html
@@ -0,0 +1,113 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 1045891</title>
+ <!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+ <p id="display"></p>
+ <div id="content" style="visibility: hidden">
+ </div>
+
+<script class="testbody" type="text/javascript">
+
+/*
+ * Description of the test:
+ * We load a page with a given CSP and verify that child frames and workers are correctly
+ * evaluated through the "child-src" directive.
+ */
+
+SimpleTest.waitForExplicitFinish();
+
+var IFRAME_SRC="file_child-src_iframe.html"
+
+var tests = {
+ 'same-src': {
+ id: "same-src",
+ file: IFRAME_SRC,
+ result : "allowed",
+ policy : "default-src 'none'; script-src 'unsafe-inline'; child-src http://mochi.test:8888"
+ },
+ 'star-src': {
+ id: "star-src",
+ file: IFRAME_SRC,
+ result : "allowed",
+ policy : "default-src 'none'; script-src 'unsafe-inline'; child-src *"
+ },
+ 'other-src': {
+ id: "other-src",
+ file: IFRAME_SRC,
+ result : "blocked",
+ policy : "default-src http://mochi.test:8888; script-src 'unsafe-inline'; child-src http://www.example.com"
+ },
+ 'same-src-by-frame-src': {
+ id: "same-src-by-frame-src",
+ file: IFRAME_SRC,
+ result : "allowed",
+ policy : "default-src 'none'; script-src 'unsafe-inline'; child-src 'none'; frame-src http://mochi.test:8888"
+ },
+ 'star-src-by-frame-src': {
+ id: "star-src-by-frame-src",
+ file: IFRAME_SRC,
+ result : "allowed",
+ policy : "default-src 'none'; script-src 'unsafe-inline'; child-src 'none'; frame-src *"
+ },
+ 'other-src-by-frame-src': {
+ id: "other-src-by-frame-src",
+ file: IFRAME_SRC,
+ result : "blocked",
+ policy : "default-src 'none'; script-src 'unsafe-inline'; child-src http://mochi.test:8888; frame-src http://www.example.com"
+ },
+ 'none-src-by-frame-src': {
+ id: "none-src-by-frame-src",
+ file: IFRAME_SRC,
+ result : "blocked",
+ policy : "default-src 'none'; script-src 'unsafe-inline'; child-src http://mochi.test:8888; frame-src 'none'"
+ }
+};
+
+finished = {};
+
+function checkFinished() {
+ if (Object.keys(finished).length == Object.keys(tests).length) {
+ window.removeEventListener('message', recvMessage);
+ SimpleTest.finish();
+ }
+}
+
+function recvMessage(ev) {
+ is(ev.data.message, tests[ev.data.id].result, "CSP child-src test " + ev.data.id);
+ finished[ev.data.id] = ev.data.message;
+
+ checkFinished();
+}
+
+window.addEventListener('message', recvMessage);
+
+function loadNextTest() {
+ for (item in tests) {
+ test = tests[item];
+ var src = "file_testserver.sjs";
+ // append the file that should be served
+ src += "?file=" + escape("tests/dom/security/test/csp/" + test.file);
+ // append the CSP that should be used to serve the file
+ src += "&csp=" + escape(test.policy);
+ // add our identifier
+ src += "#" + escape(test.id);
+
+ content = document.getElementById('content');
+ testframe = document.createElement("iframe");
+ testframe.setAttribute('id', test.id);
+ content.appendChild(testframe);
+ testframe.src = src;
+ }
+}
+
+// start running the tests
+loadNextTest();
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_child-src_worker-redirect.html b/dom/security/test/csp/test_child-src_worker-redirect.html
new file mode 100644
index 0000000000..a1b1c9c2b4
--- /dev/null
+++ b/dom/security/test/csp/test_child-src_worker-redirect.html
@@ -0,0 +1,125 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title>Bug 1045891</title>
+ <!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ </head>
+ <body>
+ <p id="display"></p>
+ <div id="content" style="visibility: hidden">
+ </div>
+
+ <script class="testbody" type="text/javascript">
+ /*
+ * Description of the test:
+ * We load a page with a given CSP and verify that child frames and workers are correctly
+ * evaluated through the "child-src" directive.
+ */
+
+ SimpleTest.waitForExplicitFinish();
+
+ var WORKER_REDIRECT_TEST_FILE = "file_child-src_worker-redirect.html";
+ var SHARED_WORKER_REDIRECT_TEST_FILE = "file_child-src_shared_worker-redirect.html";
+
+ var tests = {
+ 'same-src-worker_redir-same': {
+ id: "same-src-worker_redir-same",
+ file: WORKER_REDIRECT_TEST_FILE,
+ result : "allowed",
+ redir: "same",
+ policy : "default-src 'none'; script-src 'self' 'unsafe-inline'; child-src http://mochi.test:8888"
+ },
+ 'same-src-worker_redir-other': {
+ id: "same-src-worker_redir-other",
+ file: WORKER_REDIRECT_TEST_FILE,
+ result : "blocked",
+ redir: "other",
+ policy : "default-src 'none'; script-src 'self' 'unsafe-inline'; child-src http://mochi.test:8888"
+ },
+ 'star-src-worker_redir-same': {
+ id: "star-src-worker_redir-same",
+ file: WORKER_REDIRECT_TEST_FILE,
+ redir: "same",
+ result : "allowed",
+ policy : "default-src 'none'; script-src 'self' 'unsafe-inline'; child-src *"
+ },
+ 'other-src-worker_redir-same': {
+ id: "other-src-worker_redir-same",
+ file: WORKER_REDIRECT_TEST_FILE,
+ redir: "same",
+ result : "blocked",
+ policy : "default-src 'none'; script-src 'self' 'unsafe-inline'; child-src https://www.example.org"
+ },
+ /* shared workers */
+ 'same-src-shared_worker_redir-same': {
+ id: "same-src-shared_worker_redir-same",
+ file: SHARED_WORKER_REDIRECT_TEST_FILE,
+ result : "allowed",
+ redir: "same",
+ policy : "default-src 'none'; script-src 'self' 'unsafe-inline'; child-src http://mochi.test:8888"
+ },
+ 'same-src-shared_worker_redir-other': {
+ id: "same-src-shared_worker_redir-other",
+ file: SHARED_WORKER_REDIRECT_TEST_FILE,
+ result : "blocked",
+ redir: "other",
+ policy : "default-src 'none'; script-src 'self' 'unsafe-inline'; child-src http://mochi.test:8888"
+ },
+ 'star-src-shared_worker_redir-same': {
+ id: "star-src-shared_worker_redir-same",
+ file: SHARED_WORKER_REDIRECT_TEST_FILE,
+ redir: "same",
+ result : "allowed",
+ policy : "default-src 'none'; script-src 'self' 'unsafe-inline'; child-src *"
+ },
+ 'other-src-shared_worker_redir-same': {
+ id: "other-src-shared_worker_redir-same",
+ file: SHARED_WORKER_REDIRECT_TEST_FILE,
+ redir: "same",
+ result : "blocked",
+ policy : "default-src 'none'; script-src 'self' 'unsafe-inline'; child-src https://www.example.org"
+ },
+ };
+
+ finished = {};
+
+ function recvMessage(ev) {
+ is(ev.data.message, tests[ev.data.id].result, "CSP child-src worker test " + ev.data.id);
+ finished[ev.data.id] = ev.data.message;
+
+ if (Object.keys(finished).length == Object.keys(tests).length) {
+ window.removeEventListener('message', recvMessage);
+ SimpleTest.finish();
+ }
+ }
+
+ window.addEventListener('message', recvMessage);
+
+ function loadNextTest() {
+ for (item in tests) {
+ test = tests[item];
+ var src = "file_testserver.sjs";
+ // append the file that should be served
+ src += "?file=" + escape("tests/dom/security/test/csp/" + test.file);
+ // append the CSP that should be used to serve the file
+ src += "&csp=" + escape(test.policy);
+ // add whether redirect is to same or different
+ src += "&redir=" + escape(test.policy);
+ // add our identifier
+ src += "#" + escape(test.id);
+
+ content = document.getElementById('content');
+ testframe = document.createElement("iframe");
+ testframe.setAttribute('id', test.id);
+ content.appendChild(testframe);
+ testframe.src = src;
+ }
+ }
+
+ // start running the tests
+ loadNextTest();
+ </script>
+ </body>
+</html>
diff --git a/dom/security/test/csp/test_child-src_worker.html b/dom/security/test/csp/test_child-src_worker.html
new file mode 100644
index 0000000000..154e533551
--- /dev/null
+++ b/dom/security/test/csp/test_child-src_worker.html
@@ -0,0 +1,148 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title>Bug 1045891</title>
+ <!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ </head>
+ <body>
+ <p id="display"></p>
+ <div id="content" style="visibility: hidden">
+ </div>
+
+ <script class="testbody" type="text/javascript">
+ /*
+ * Description of the test:
+ * We load a page with a given CSP and verify that child frames and workers are correctly
+ * evaluated through the "child-src" directive.
+ */
+
+ SimpleTest.waitForExplicitFinish();
+
+ var WORKER_TEST_FILE = "file_child-src_worker.html";
+ var SERVICE_WORKER_TEST_FILE = "file_child-src_service_worker.html";
+ var SHARED_WORKER_TEST_FILE = "file_child-src_shared_worker.html";
+
+ var tests = {
+ 'same-src-worker': {
+ id: "same-src-worker",
+ file: WORKER_TEST_FILE,
+ result : "allowed",
+ policy : "default-src 'none'; script-src 'unsafe-inline'; child-src http://mochi.test:8888"
+ },
+ 'same-src-service_worker': {
+ id: "same-src-service_worker",
+ file: SERVICE_WORKER_TEST_FILE,
+ result : "allowed",
+ policy : "default-src 'none'; script-src 'unsafe-inline'; child-src http://mochi.test:8888"
+ },
+ 'same-src-shared_worker': {
+ id: "same-src-shared_worker",
+ file: SHARED_WORKER_TEST_FILE,
+ result : "allowed",
+ policy : "default-src 'none'; script-src 'unsafe-inline'; child-src http://mochi.test:8888"
+ },
+ 'star-src-worker': {
+ id: "star-src-worker",
+ file: WORKER_TEST_FILE,
+ result : "allowed",
+ policy : "default-src 'none'; script-src 'unsafe-inline'; child-src *"
+ },
+ 'star-src-service_worker': {
+ id: "star-src-service_worker",
+ file: SERVICE_WORKER_TEST_FILE,
+ result : "allowed",
+ policy : "default-src 'none'; script-src 'unsafe-inline'; child-src *"
+ },
+ 'star-src-shared_worker': {
+ id: "star-src-shared_worker",
+ file: SHARED_WORKER_TEST_FILE,
+ result : "allowed",
+ policy : "default-src 'none'; script-src 'unsafe-inline'; child-src *"
+ },
+ 'other-src-worker': {
+ id: "other-src-worker",
+ file: WORKER_TEST_FILE,
+ result : "blocked",
+ policy : "default-src 'none'; script-src 'unsafe-inline'; child-src https://www.example.org"
+ },
+ 'other-src-service_worker': {
+ id: "other-src-service_worker",
+ file: SERVICE_WORKER_TEST_FILE,
+ result : "blocked",
+ policy : "default-src 'none'; script-src 'unsafe-inline'; child-src https://www.example.org"
+ },
+ 'other-src-shared_worker': {
+ id: "other-src-shared_worker",
+ file: SHARED_WORKER_TEST_FILE,
+ result : "blocked",
+ policy : "default-src 'none'; script-src 'unsafe-inline'; child-src https://www.example.org"
+ },
+ 'script-src-worker': {
+ id: "script-src-worker",
+ file: WORKER_TEST_FILE,
+ result : "blocked",
+ policy : "default-src 'none'; script-src https://www.example.org 'unsafe-inline'"
+ },
+ 'script-src-service_worker': {
+ id: "script-src-service_worker",
+ file: SERVICE_WORKER_TEST_FILE,
+ result : "blocked",
+ policy : "default-src 'none'; script-src https://www.example.org 'unsafe-inline'"
+ },
+ 'script-src-self-shared_worker': {
+ id: "script-src-self-shared_worker",
+ file: SHARED_WORKER_TEST_FILE,
+ result : "blocked",
+ policy : "default-src 'none'; script-src https://www.example.org 'unsafe-inline'"
+ },
+ };
+
+ finished = {};
+
+ function recvMessage(ev) {
+ is(ev.data.message, tests[ev.data.id].result, "CSP child-src worker test " + ev.data.id);
+ finished[ev.data.id] = ev.data.message;
+
+ if (Object.keys(finished).length == Object.keys(tests).length) {
+ window.removeEventListener('message', recvMessage);
+ SimpleTest.finish();
+ }
+ }
+
+ window.addEventListener('message', recvMessage);
+
+ function loadNextTest() {
+ for (item in tests) {
+ test = tests[item];
+ var src = "file_testserver.sjs";
+ // append the file that should be served
+ src += "?file=" + escape("tests/dom/security/test/csp/" + test.file);
+ // append the CSP that should be used to serve the file
+ src += "&csp=" + escape(test.policy);
+ // add our identifier
+ src += "#" + escape(test.id);
+
+ content = document.getElementById('content');
+ testframe = document.createElement("iframe");
+ testframe.setAttribute('id', test.id);
+ content.appendChild(testframe);
+ testframe.src = src;
+ }
+ }
+
+ onload = function() {
+ SpecialPowers.pushPrefEnv({"set": [
+ ["dom.serviceWorkers.exemptFromPerDomainMax", true],
+ ["dom.serviceWorkers.enabled", true],
+ ["dom.serviceWorkers.testing.enabled", true],
+ ["dom.caches.enabled", true]
+ ]}, loadNextTest);
+ };
+
+ // start running the tests
+ //loadNextTest();
+ </script>
+ </body>
+</html>
diff --git a/dom/security/test/csp/test_child-src_worker_data.html b/dom/security/test/csp/test_child-src_worker_data.html
new file mode 100644
index 0000000000..9d36e73e0c
--- /dev/null
+++ b/dom/security/test/csp/test_child-src_worker_data.html
@@ -0,0 +1,126 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title>Bug 1045891</title>
+ <!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ </head>
+ <body>
+ <p id="display"></p>
+ <div id="content" style="visibility: hidden">
+ </div>
+
+ <script class="testbody" type="text/javascript">
+ /*
+ * Description of the test:
+ * We load a page with a given CSP and verify that child frames and workers are correctly
+ * evaluated through the "child-src" directive.
+ */
+
+ SimpleTest.waitForExplicitFinish();
+
+ var WORKER_TEST_FILE = "file_child-src_worker_data.html";
+ var SHARED_WORKER_TEST_FILE = "file_child-src_shared_worker_data.html";
+
+ var tests = {
+ 'same-src-worker-no-data': {
+ id: "same-src-worker-no-data",
+ file: WORKER_TEST_FILE,
+ result : "blocked",
+ policy : "default-src 'none'; script-src 'unsafe-inline'; child-src 'self'"
+ },
+ 'same-src-worker': {
+ id: "same-src-worker",
+ file: WORKER_TEST_FILE,
+ result : "allowed",
+ policy : "default-src 'none'; script-src 'unsafe-inline'; child-src 'self' data:"
+ },
+ 'same-src-shared_worker-no-data': {
+ id: "same-src-shared_worker-no-data",
+ file: SHARED_WORKER_TEST_FILE,
+ result : "blocked",
+ policy : "default-src 'none'; script-src 'unsafe-inline'; child-src 'self'"
+ },
+ 'same-src-shared_worker': {
+ id: "same-src-shared_worker",
+ file: SHARED_WORKER_TEST_FILE,
+ result : "allowed",
+ policy : "default-src 'none'; script-src 'unsafe-inline'; child-src 'self' data:"
+ },
+ 'star-src-worker': {
+ id: "star-src-worker",
+ file: WORKER_TEST_FILE,
+ result : "allowed",
+ policy : "default-src 'none'; script-src 'unsafe-inline'; child-src * data:"
+ },
+ 'star-src-worker-no-data': {
+ id: "star-src-worker-no-data",
+ file: WORKER_TEST_FILE,
+ result : "blocked",
+ policy : "default-src 'none'; script-src 'unsafe-inline'; child-src *"
+ },
+ 'star-src-shared_worker-no-data': {
+ id: "star-src-shared_worker-no-data",
+ file: SHARED_WORKER_TEST_FILE,
+ result : "blocked",
+ policy : "default-src 'none'; script-src 'unsafe-inline'; child-src *"
+ },
+ 'star-src-shared_worker': {
+ id: "star-src-shared_worker",
+ file: SHARED_WORKER_TEST_FILE,
+ result : "allowed",
+ policy : "default-src 'none'; script-src 'unsafe-inline'; child-src * data:"
+ },
+ 'other-src-worker-no-data': {
+ id: "other-src-worker-no-data",
+ file: WORKER_TEST_FILE,
+ result : "blocked",
+ policy : "default-src 'none'; script-src 'unsafe-inline'; child-src https://www.example.org"
+ },
+ 'other-src-shared_worker-no-data': {
+ id: "other-src-shared_worker-no-data",
+ file: SHARED_WORKER_TEST_FILE,
+ result : "blocked",
+ policy : "default-src 'none'; script-src 'unsafe-inline'; child-src https://www.example.org"
+ },
+ };
+
+ finished = {};
+
+ function recvMessage(ev) {
+ is(ev.data.message, tests[ev.data.id].result, "CSP child-src worker test " + ev.data.id);
+ finished[ev.data.id] = ev.data.message;
+
+ if (Object.keys(finished).length == Object.keys(tests).length) {
+ window.removeEventListener('message', recvMessage);
+ SimpleTest.finish();
+ }
+ }
+
+ window.addEventListener('message', recvMessage);
+
+ function loadNextTest() {
+ for (item in tests) {
+ test = tests[item];
+ var src = "file_testserver.sjs";
+ // append the file that should be served
+ src += "?file=" + escape("tests/dom/security/test/csp/" + test.file);
+ // append the CSP that should be used to serve the file
+ src += "&csp=" + escape(test.policy);
+ // add our identifier
+ src += "#" + escape(test.id);
+
+ content = document.getElementById('content');
+ testframe = document.createElement("iframe");
+ testframe.setAttribute('id', test.id);
+ content.appendChild(testframe);
+ testframe.src = src;
+ }
+ }
+
+ // start running the tests
+ loadNextTest();
+ </script>
+ </body>
+</html>
diff --git a/dom/security/test/csp/test_connect-src.html b/dom/security/test/csp/test_connect-src.html
new file mode 100644
index 0000000000..1ae4482dd8
--- /dev/null
+++ b/dom/security/test/csp/test_connect-src.html
@@ -0,0 +1,129 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 1031530 and Bug 1139667 - Test mapping of XMLHttpRequest and fetch() to connect-src</title>
+ <!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+ <p id="display"></p>
+ <div id="content" style="visibility: hidden">
+ <iframe style="width:100%;" id="testframe"></iframe>
+ </div>
+
+<script class="testbody" type="text/javascript">
+
+/*
+ * Description of the test:
+ * We load a page with a given CSP and verify that XMLHttpRequests and fetches are correctly
+ * evaluated through the "connect-src" directive. All XMLHttpRequests are served
+ * using http://mochi.test:8888, which allows the requests to succeed for the first
+ * two policies and to fail for the last policy. Please note that we have to add
+ * 'unsafe-inline' so we can run the JS test code in file_connect-src.html.
+ */
+
+SimpleTest.waitForExplicitFinish();
+
+var tests = [
+ {
+ file: "file_connect-src.html",
+ result : "allowed",
+ policy : "default-src 'none' script-src 'unsafe-inline'; connect-src http://mochi.test:8888"
+ },
+ {
+ file: "file_connect-src.html",
+ result : "allowed",
+ policy : "default-src 'none'; script-src 'unsafe-inline'; connect-src *"
+ },
+ {
+ file: "file_connect-src.html",
+ result : "blocked",
+ policy : "default-src 'none'; script-src 'unsafe-inline'; connect-src http://www.example.com"
+ },
+ {
+ file: "file_connect-src-fetch.html",
+ result : "allowed",
+ policy : "default-src 'none' script-src 'unsafe-inline'; connect-src http://mochi.test:8888"
+ },
+ {
+ file: "file_connect-src-fetch.html",
+ result : "allowed",
+ policy : "default-src 'none'; script-src 'unsafe-inline'; connect-src *"
+ },
+ {
+ file: "file_connect-src-fetch.html",
+ result : "blocked",
+ policy : "default-src 'none'; script-src 'unsafe-inline'; connect-src http://www.example.com"
+ }
+];
+
+// initializing to -1 so we start at index 0 when we start the test
+var counter = -1;
+
+function checkResult(aResult) {
+ is(aResult, tests[counter].result, "should be " + tests[counter].result + " in test " + counter + "!");
+ loadNextTest();
+}
+
+// We use the examiner to identify requests that hit the wire and requests
+// that are blocked by CSP and bubble up the result to the including iframe
+// document (parent).
+function examiner() {
+ SpecialPowers.addObserver(this, "csp-on-violate-policy");
+ SpecialPowers.addObserver(this, "specialpowers-http-notify-request");
+}
+examiner.prototype = {
+ observe(subject, topic, data) {
+ if (topic === "specialpowers-http-notify-request") {
+ // making sure we do not bubble a result for something other
+ // then the request in question.
+ if (!data.includes("file_testserver.sjs?foo")) {
+ return;
+ }
+ checkResult("allowed");
+ }
+
+ if (topic === "csp-on-violate-policy") {
+ // making sure we do not bubble a result for something other
+ // then the request in question.
+ var asciiSpec = SpecialPowers.getPrivilegedProps(
+ SpecialPowers.do_QueryInterface(subject, "nsIURI"),
+ "asciiSpec");
+
+ if (!asciiSpec.includes("file_testserver.sjs?foo")) {
+ return;
+ }
+ checkResult("blocked");
+ }
+ },
+ remove() {
+ SpecialPowers.removeObserver(this, "csp-on-violate-policy");
+ SpecialPowers.removeObserver(this, "specialpowers-http-notify-request");
+ }
+}
+window.ConnectSrcExaminer = new examiner();
+
+function loadNextTest() {
+ counter++;
+ if (counter == tests.length) {
+ window.ConnectSrcExaminer.remove();
+ SimpleTest.finish();
+ return;
+ }
+
+ var src = "file_testserver.sjs";
+ // append the file that should be served
+ src += "?file=" + escape("tests/dom/security/test/csp/" + tests[counter].file);
+ // append the CSP that should be used to serve the file
+ src += "&csp=" + escape(tests[counter].policy);
+
+ document.getElementById("testframe").src = src;
+}
+
+// start running the tests
+loadNextTest();
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_csp_frame_ancestors_about_blank.html b/dom/security/test/csp/test_csp_frame_ancestors_about_blank.html
new file mode 100644
index 0000000000..8f57d9e133
--- /dev/null
+++ b/dom/security/test/csp/test_csp_frame_ancestors_about_blank.html
@@ -0,0 +1,59 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Bug 1668071 - CSP frame-ancestors in about:blank</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+
+<script class="testbody" type="text/javascript">
+
+/* Description of the test:
+ * We dynamically load an about:blank iframe which then loads a testframe
+ * including a CSP frame-ancestors directive which matches the including
+ * security context. We make sure that we not incorrectly block on
+ * about:blank which should inherit the security context.
+ */
+
+SimpleTest.waitForExplicitFinish();
+
+let aboutBlankFrame = document.createElement("iframe");
+document.body.appendChild(aboutBlankFrame);
+
+aboutBlankFrame.onload = function() {
+ ok(true, "aboutBlankFrame onload should fire");
+ let aboutBlankDoc = aboutBlankFrame.contentDocument;
+ is(aboutBlankDoc.documentURI, "about:blank",
+ "sanity: aboutBlankFrame URI should be about:blank");
+
+ let testframe = aboutBlankDoc.createElement("iframe");
+ aboutBlankDoc.body.appendChild(testframe);
+ testframe.onload = function() {
+ ok(true, "testframe onload should fire");
+ let testDoc = SpecialPowers.wrap(testframe.contentDocument);
+ ok(testDoc.documentURI.endsWith("file_csp_frame_ancestors_about_blank.html"),
+ "sanity: document in testframe should be the testfile");
+
+ let cspJSON = testDoc.cspJSON;
+ ok(cspJSON.includes("frame-ancestors"), "found frame-ancestors directive");
+ ok(cspJSON.includes("http://mochi.test:8888"), "found frame-ancestors value");
+
+ SimpleTest.finish();
+ }
+
+ testframe.onerror = function() {
+ ok(false, "testframe onerror should not fire");
+ }
+ testframe.src = "file_csp_frame_ancestors_about_blank.html";
+}
+
+aboutBlankFrame.onerror = function() {
+ ok(false, "aboutBlankFrame onerror should not be called");
+}
+aboutBlankFrame.src = "about:blank";
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_csp_style_src_empty_hash.html b/dom/security/test/csp/test_csp_style_src_empty_hash.html
new file mode 100644
index 0000000000..b500c196e6
--- /dev/null
+++ b/dom/security/test/csp/test_csp_style_src_empty_hash.html
@@ -0,0 +1,32 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 1609122 - Empty Style Element with valid style-src hash </title>
+ <!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+
+ <meta http-equiv="Content-Security-Policy" content="style-src 'sha256-47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=';">
+</head>
+<body>
+<iframe style="width:100%;" id="testframe"></iframe>
+
+<script class="testbody" type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+
+/* Description of the test:
+ * We try to load a stylesheet that is empty with a matching hash
+ * sha256-47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=' should match ""
+ * thus allow the style to be accessed
+ */
+
+
+var s = document.head.appendChild(document.createElement("style"));
+s.disabled = true;
+
+is(s.disabled, true, "Empty Stylesheet with matching Hash was not blocked");
+SimpleTest.finish();
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_csp_worker_inheritance.html b/dom/security/test/csp/test_csp_worker_inheritance.html
new file mode 100644
index 0000000000..ebf6bea8a6
--- /dev/null
+++ b/dom/security/test/csp/test_csp_worker_inheritance.html
@@ -0,0 +1,20 @@
+/**
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+<html>
+ <head>
+ <title>Test for Bug 1475849</title>
+ </head>
+ <body>
+ <p id="display"></p>
+ <div id="content" style="display: none">
+ </div>
+ <iframe style="width:200px;height:200px;" id='cspframe'></iframe>
+ <script class="testbody" type="text/javascript">
+ document.getElementById('cspframe').src = 'main_csp_worker.html';
+ </script>
+
+ </body>
+</html>
diff --git a/dom/security/test/csp/test_data_csp_inheritance.html b/dom/security/test/csp/test_data_csp_inheritance.html
new file mode 100644
index 0000000000..dd7f3174a2
--- /dev/null
+++ b/dom/security/test/csp/test_data_csp_inheritance.html
@@ -0,0 +1,36 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 1381761 - Treating 'data:' documents as unique, opaque origins should still inherit the CSP</title>
+ <!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<iframe style="width:100%;" id="testframe"></iframe>
+
+<script class="testbody" type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+
+/* Description of the test:
+ * We load an iframe using a meta CSP which includes another iframe
+ * using a data: URI. We make sure the CSP gets inherited into
+ * the data: URI iframe.
+ */
+
+window.addEventListener("message", receiveMessage);
+function receiveMessage(event) {
+ window.removeEventListener("message", receiveMessage);
+ // toplevel CSP should apply to data: URI iframe hence resulting
+ // in 1 applied policy.
+ is(event.data.result, 1,
+ "data: URI iframe inherits CSP from including context");
+ SimpleTest.finish();
+}
+
+document.getElementById("testframe").src = "file_data_csp_inheritance.html";
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_data_csp_merge.html b/dom/security/test/csp/test_data_csp_merge.html
new file mode 100644
index 0000000000..87219c406d
--- /dev/null
+++ b/dom/security/test/csp/test_data_csp_merge.html
@@ -0,0 +1,36 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 1386183 - Meta CSP on data: URI iframe should be merged with toplevel CSP</title>
+ <!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<iframe style="width:100%;" id="testframe"></iframe>
+
+<script class="testbody" type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+
+/* Description of the test:
+ * We load an iframe using a meta CSP which includes another iframe
+ * using a data: URI which also defines a meta CSP. We make sure the
+ * CSP from the including document gets merged with the data: URI
+ * CSP and applies to the data: URI iframe.
+ */
+
+window.addEventListener("message", receiveMessage);
+function receiveMessage(event) {
+ window.removeEventListener("message", receiveMessage);
+ // toplevel CSP + data: URI iframe meta CSP => 2 CSP policies
+ is(event.data.result, 2,
+ "CSP on data: URI iframe gets merged with CSP from including context");
+ SimpleTest.finish();
+}
+
+document.getElementById("testframe").src = "file_data_csp_merge.html";
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_data_doc_ignore_meta_csp.html b/dom/security/test/csp/test_data_doc_ignore_meta_csp.html
new file mode 100644
index 0000000000..6f0a3fbbf6
--- /dev/null
+++ b/dom/security/test/csp/test_data_doc_ignore_meta_csp.html
@@ -0,0 +1,39 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 1382869: data document should ignore meta csp</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<iframe style="width:100%;" id="testframe"></iframe>
+
+<script class="testbody" type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+
+/* Description of the test:
+ * We load an iframe creating a new data document which defines
+ * a meta csp. We make sure the meta CSP is ignored and does not
+ * apply to the actual iframe document.
+ */
+
+window.addEventListener("message", receiveMessage);
+function receiveMessage(event) {
+ window.removeEventListener("message", receiveMessage);
+ is(event.data.result, "dataDocCreated", "sanity: received msg from loaded frame");
+
+ var frame = document.getElementById("testframe");
+ var contentDoc = SpecialPowers.wrap(frame).contentDocument;
+ var cspOBJ = JSON.parse(contentDoc.cspJSON);
+ // make sure we got no policy attached
+ var policies = cspOBJ["csp-policies"];
+ is(policies.length, 0, "there should be no CSP attached to the iframe");
+ SimpleTest.finish();
+}
+
+document.getElementById("testframe").src = "file_data_doc_ignore_meta_csp.html";
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_docwrite_meta.html b/dom/security/test/csp/test_docwrite_meta.html
new file mode 100644
index 0000000000..776f1bb32f
--- /dev/null
+++ b/dom/security/test/csp/test_docwrite_meta.html
@@ -0,0 +1,86 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Bug 663570 - Implement Content Security Policy via meta tag</title>
+ <!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<p id="display"></p>
+<iframe style="width:100%;" id="writemetacspframe"></iframe>
+<iframe style="width:100%;" id="commentmetacspframe"></iframe>
+
+
+<script class="testbody" type="text/javascript">
+/* Description of the test:
+ * We load two frames, where the first frame does doc.write(meta csp) and
+ * the second does doc.write(comment out meta csp).
+ * We make sure to reuse/invalidate preloads depending on the policy.
+ */
+
+SimpleTest.waitForExplicitFinish();
+
+var writemetacspframe = document.getElementById("writemetacspframe");
+var commentmetacspframe = document.getElementById("commentmetacspframe");
+var seenResults = 0;
+
+function checkTestsDone() {
+ seenResults++;
+ if (seenResults < 2) {
+ return;
+ }
+ SimpleTest.finish();
+}
+
+// document.write(<meta csp ...>) should block resources from being included in the doc
+function checkResultsBlocked() {
+ writemetacspframe.removeEventListener('load', checkResultsBlocked);
+
+ // stylesheet: default background color within FF is transparent
+ var bgcolor = window.getComputedStyle(writemetacspframe.contentDocument.body)
+ .getPropertyValue("background-color");
+ is(bgcolor, "rgba(0, 0, 0, 0)", "inital background value in FF should be 'transparent'");
+
+ // image: make sure image is blocked
+ var img = writemetacspframe.contentDocument.getElementById("testimage");
+ is(img.naturalWidth, 0, "image width should be 0");
+ is(img.naturalHeight, 0, "image height should be 0");
+
+ // script: make sure defined variable in external script is undefined
+ is(writemetacspframe.contentDocument.myMetaCSPScript, undefined, "myMetaCSPScript should be 'undefined'");
+
+ checkTestsDone();
+}
+
+// document.write(<--) to comment out meta csp should allow resources to be loaded
+// after the preload failed
+function checkResultsAllowed() {
+ commentmetacspframe.removeEventListener('load', checkResultsAllowed);
+
+ // stylesheet: should be applied; bgcolor should be red
+ var bgcolor = window.getComputedStyle(commentmetacspframe.contentDocument.body).getPropertyValue("background-color");
+ is(bgcolor, "rgb(255, 0, 0)", "background should be red/rgb(255, 0, 0)");
+
+ // image: should be completed
+ var img = commentmetacspframe.contentDocument.getElementById("testimage");
+ ok(img.complete, "image should not be loaded");
+
+ // script: defined variable in external script should be accessible
+ is(commentmetacspframe.contentDocument.myMetaCSPScript, "external-JS-loaded", "myMetaCSPScript should be 'external-JS-loaded'");
+
+ checkTestsDone();
+}
+
+// doc.write(meta csp) should should allow preloads but should block actual loads
+writemetacspframe.src = 'file_docwrite_meta.html';
+writemetacspframe.addEventListener('load', checkResultsBlocked);
+
+// commenting out a meta CSP should result in loaded image, script, style
+commentmetacspframe.src = 'file_doccomment_meta.html';
+commentmetacspframe.addEventListener('load', checkResultsAllowed);
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_dual_header.html b/dom/security/test/csp/test_dual_header.html
new file mode 100644
index 0000000000..cfea86103b
--- /dev/null
+++ b/dom/security/test/csp/test_dual_header.html
@@ -0,0 +1,66 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 1036399 - Multiple CSP policies should be combined towards an intersection</title>
+ <!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+ <p id="display"></p>
+ <div id="content" style="visibility: hidden">
+ <iframe style="width:100%;" id="testframe"></iframe>
+ </div>
+
+<script class="testbody" type="text/javascript">
+
+/* Description of the test:
+ * We have two tests where each tests serves a page using two CSP policies:
+ * a) * default-src 'self'
+ * * default-src 'self' 'unsafe-inline'
+ *
+ * b) * default-src 'self' 'unsafe-inline'
+ * * default-src 'self' 'unsafe-inline'
+ *
+ * We make sure the inline script is *blocked* for test (a) but *allowed* for test (b).
+ * Multiple CSPs should be combined towards an intersection and it shouldn't be possible
+ * to open up (loosen) a CSP policy.
+ */
+
+const TESTS = [
+ { query: "tight", result: "blocked" },
+ { query: "loose", result: "allowed" }
+];
+var testCounter = -1;
+
+function ckeckResult() {
+ try {
+ document.getElementById("testframe").removeEventListener('load', ckeckResult);
+ var testframe = document.getElementById("testframe");
+ var divcontent = testframe.contentWindow.document.getElementById('testdiv').innerHTML;
+ is(divcontent, curTest.result, "should be 'blocked'!");
+ }
+ catch (e) {
+ ok(false, "error: could not access content in div container!");
+ }
+ loadNextTest();
+}
+
+function loadNextTest() {
+ testCounter++;
+ if (testCounter >= TESTS.length) {
+ SimpleTest.finish();
+ return;
+ }
+ curTest = TESTS[testCounter];
+ var src = "file_dual_header_testserver.sjs?" + curTest.query;
+ document.getElementById("testframe").addEventListener("load", ckeckResult);
+ document.getElementById("testframe").src = src;
+}
+
+SimpleTest.waitForExplicitFinish();
+loadNextTest();
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_empty_directive.html b/dom/security/test/csp/test_empty_directive.html
new file mode 100644
index 0000000000..81c5df8403
--- /dev/null
+++ b/dom/security/test/csp/test_empty_directive.html
@@ -0,0 +1,51 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1439425
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1439425</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1439425">Mozilla Bug 1439425</a>
+<p id="display"></p>
+
+<iframe id="cspframe"></iframe>
+
+<pre id="test">
+
+<script class="testbody" type="text/javascript">
+let consoleCount = 0;
+
+function cleanup() {
+ SpecialPowers.postConsoleSentinel();
+}
+
+function finish() {
+ SimpleTest.finish();
+}
+
+SpecialPowers.registerConsoleListener(function ConsoleMsgListener(aMsg) {
+ if (aMsg.message == "SENTINEL") {
+ is(consoleCount, 0);
+ SimpleTest.executeSoon(finish);
+ } else if (aMsg.message.includes("Content-Security-Policy")) {
+ ++consoleCount;
+ ok(false, "Must never see a console warning here");
+ }
+});
+
+// set up and start testing
+SimpleTest.waitForExplicitFinish();
+let frame = document.getElementById('cspframe');
+frame.onload = () => {
+ SimpleTest.executeSoon(cleanup);
+};
+frame.src = 'file_empty_directive.html';
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_evalscript.html b/dom/security/test/csp/test_evalscript.html
new file mode 100644
index 0000000000..bf1621f81e
--- /dev/null
+++ b/dom/security/test/csp/test_evalscript.html
@@ -0,0 +1,59 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for Content Security Policy "no eval" base restriction</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+<iframe style="width:100%;height:300px;" id='cspframe'></iframe>
+<iframe style="width:100%;height:300px;" id='cspframe2'></iframe>
+<script class="testbody" type="text/javascript">
+
+var evalScriptsThatRan = 0;
+var evalScriptsBlocked = 0;
+var evalScriptsTotal = 19;
+
+// called by scripts that run
+var scriptRan = function(shouldrun, testname, data) {
+ evalScriptsThatRan++;
+ ok(shouldrun, 'EVAL SCRIPT RAN: ' + testname + '(' + data + ')');
+ checkTestResults();
+}
+
+// called when a script is blocked
+var scriptBlocked = function(shouldrun, testname, data) {
+ evalScriptsBlocked++;
+ ok(!shouldrun, 'EVAL SCRIPT BLOCKED: ' + testname + '(' + data + ')');
+ checkTestResults();
+}
+
+var verifyZeroRetVal = function(val, testname) {
+ ok(val === 0, 'RETURN VALUE SHOULD BE ZERO, was ' + val + ': ' + testname);
+}
+
+// Check to see if all the tests have run
+var checkTestResults = function() {
+ // if any test is incomplete, keep waiting
+ if (evalScriptsTotal - evalScriptsBlocked - evalScriptsThatRan > 0)
+ return;
+
+ // ... otherwise, finish
+ SimpleTest.finish();
+}
+
+//////////////////////////////////////////////////////////////////////
+// set up and go
+SimpleTest.waitForExplicitFinish();
+
+// save this for last so that our listeners are registered.
+// ... this loads the testbed of good and bad requests.
+document.getElementById('cspframe').src = 'file_evalscript_main.html';
+document.getElementById('cspframe2').src = 'file_evalscript_main_allowed.html';
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_evalscript_allowed_by_strict_dynamic.html b/dom/security/test/csp/test_evalscript_allowed_by_strict_dynamic.html
new file mode 100644
index 0000000000..29c3e87287
--- /dev/null
+++ b/dom/security/test/csp/test_evalscript_allowed_by_strict_dynamic.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <meta http-equiv="Content-Security-Policy"
+ content="script-src 'nonce-foobar' 'strict-dynamic' 'unsafe-eval'">
+ <title>Bug 1439330 - CSP: eval is not blocked if 'strict-dynamic' is enabled
+ </title>
+ <script nonce="foobar" type="application/javascript" src="/tests/SimpleTest/SimpleTest.js">
+ </script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script nonce="foobar">
+
+/* Description of the test:
+ * We apply the script-src 'nonce-foobar' 'strict-dynamic' 'unsafe-eval' CSP and
+ * check if the eval function is allowed correctly by the CSP.
+ */
+
+SimpleTest.waitForExplicitFinish();
+
+// start the test
+try {
+ eval("1");
+ ok(true, "eval allowed by CSP");
+}
+catch (ex) {
+ ok(false, "eval should be allowed by CSP");
+}
+
+SimpleTest.finish();
+
+</script>
+</body>
+</html> \ No newline at end of file
diff --git a/dom/security/test/csp/test_evalscript_blocked_by_strict_dynamic.html b/dom/security/test/csp/test_evalscript_blocked_by_strict_dynamic.html
new file mode 100644
index 0000000000..179e865459
--- /dev/null
+++ b/dom/security/test/csp/test_evalscript_blocked_by_strict_dynamic.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <meta http-equiv="Content-Security-Policy"
+ content="script-src 'nonce-foobar' 'strict-dynamic'">
+ <title>Bug 1439330 - CSP: eval is not blocked if 'strict-dynamic' is enabled
+ </title>
+ <script nonce="foobar" type="application/javascript" src="/tests/SimpleTest/SimpleTest.js">
+ </script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<script nonce="foobar">
+
+/* Description of the test:
+ * We apply the script-src 'nonce-foobar' 'strict-dynamic' CSP and
+ * check if the eval function is blocked correctly by the CSP.
+ */
+
+SimpleTest.waitForExplicitFinish();
+
+// start the test
+try {
+ eval("1");
+ ok(false, "eval should be blocked by CSP");
+}
+catch (ex) {
+ ok(true, "eval blocked by CSP");
+}
+
+SimpleTest.finish();
+
+</script>
+</body>
+</html> \ No newline at end of file
diff --git a/dom/security/test/csp/test_fontloader.html b/dom/security/test/csp/test_fontloader.html
new file mode 100644
index 0000000000..2f68223af1
--- /dev/null
+++ b/dom/security/test/csp/test_fontloader.html
@@ -0,0 +1,98 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Bug 1122236 - CSP: Implement block-all-mixed-content</title>
+ <!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <!-- Including WindowSnapshot.js so we can take screenshots of containers !-->
+ <script src="/tests/SimpleTest/WindowSnapshot.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body onload="setupTests()">
+<iframe style="width:100%;" id="baselineframe"></iframe>
+<iframe style="width:100%;" id="testframe"></iframe>
+
+<script class="testbody" type="text/javascript">
+
+/* Description of the tests:
+ * We load a baselineFrame and compare the testFrame using
+ * compareSnapshots whether the font got loaded or blocked.
+ * Test 1: Use font-src 'none' so font gets blocked
+ * Test 2: Use font-src * so font gets loaded
+ * Test 3: Use no csp so font gets loaded
+ * Test 4: Use font-src 'none' so font gets blocked
+ * Makes sure the cache gets invalidated.
+ */
+
+SimpleTest.waitForExplicitFinish();
+
+const BASE_URI = "https://example.com/tests/dom/security/test/csp/";
+
+const tests = [
+ { // test 1
+ query: "csp-block",
+ expected: true, // frames should be equal since font is *not* allowed to load
+ description: "font should be blocked by csp (csp-block)"
+ },
+ { // test 2
+ query: "csp-allow",
+ expected: false, // frames should *not* be equal since font is loaded
+ description: "font should load and apply (csp-allow)"
+ },
+ { // test 3
+ query: "no-csp",
+ expected: false, // frames should *not* be equals since font is loaded
+ description: "font should load and apply (no-csp)"
+ },
+ { // test 4
+ query: "csp-block",
+ expected: true, // frames should be equal since font is *not* allowed to load
+ description: "font should be blocked by csp (csp-block) [apply csp to cache]"
+ }
+];
+
+var curTest;
+var counter = -1;
+var baselineframe = document.getElementById("baselineframe");
+var testframe = document.getElementById("testframe");
+
+async function checkResult() {
+ testframe.removeEventListener('load', checkResult);
+ try {
+ ok(compareSnapshots(await snapshotWindow(baselineframe.contentWindow),
+ await snapshotWindow(testframe.contentWindow),
+ curTest.expected)[0],
+ curTest.description);
+ } catch(err) {
+ ok(false, "error: " + err.message);
+ }
+ loadNextTest();
+}
+
+function loadNextTest() {
+ counter++;
+ if (counter == tests.length) {
+ SimpleTest.finish();
+ return;
+ }
+ curTest = tests[counter];
+ testframe.addEventListener("load", checkResult);
+ testframe.src = BASE_URI + "file_fontloader.sjs?" + curTest.query;
+}
+
+// once the baselineframe is loaded we can start running tests
+function startTests() {
+ baselineframe.removeEventListener('load', startTests);
+ loadNextTest();
+}
+
+// make sure the main page is loaded before we start the test
+function setupTests() {
+ baselineframe.addEventListener("load", startTests);
+ baselineframe.src = BASE_URI + "file_fontloader.sjs?baseline";
+}
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_form-action.html b/dom/security/test/csp/test_form-action.html
new file mode 100644
index 0000000000..7bbc52a116
--- /dev/null
+++ b/dom/security/test/csp/test_form-action.html
@@ -0,0 +1,105 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 529697 - Test mapping of form submission to form-action</title>
+ <!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+ <p id="display"></p>
+ <div id="content" style="visibility: hidden">
+ <iframe style="width:100%;" id="testframe"></iframe>
+ </div>
+
+<script class="testbody" type="text/javascript">
+
+/*
+ * Description of the test:
+ * We load a page with a given CSP and verify that form submissions are correctly
+ * evaluated through the "form-action" directive.
+ */
+
+SimpleTest.waitForExplicitFinish();
+
+var tests = [
+ {
+ page : "file_form-action.html",
+ result : "allowed",
+ policy : "form-action 'self'"
+ },
+ {
+ page : "file_form-action.html",
+ result : "blocked",
+ policy : "form-action 'none'"
+ }
+];
+
+// initializing to -1 so we start at index 0 when we start the test
+var counter = -1;
+
+function checkResult(aResult) {
+ is(aResult, tests[counter].result, "should be " + tests[counter].result + " in test " + counter + "!");
+ loadNextTest();
+}
+
+// We use the examiner to identify requests that hit the wire and requests
+// that are blocked by CSP and bubble up the result to the including iframe
+// document (parent).
+function examiner() {
+ SpecialPowers.addObserver(this, "csp-on-violate-policy");
+ SpecialPowers.addObserver(this, "specialpowers-http-notify-request");
+}
+examiner.prototype = {
+ observe(subject, topic, data) {
+ if (topic === "specialpowers-http-notify-request") {
+ // making sure we do not bubble a result for something other
+ // then the request in question.
+ if (!data.includes("submit-form")) {
+ return;
+ }
+ checkResult("allowed");
+ }
+
+ if (topic === "csp-on-violate-policy") {
+ // making sure we do not bubble a result for something other
+ // then the request in question.
+ var asciiSpec = SpecialPowers.getPrivilegedProps(
+ SpecialPowers.do_QueryInterface(subject, "nsIURI"),
+ "asciiSpec");
+ if (!asciiSpec.includes("submit-form")) {
+ return;
+ }
+ checkResult("blocked");
+ }
+ },
+ remove() {
+ SpecialPowers.removeObserver(this, "csp-on-violate-policy");
+ SpecialPowers.removeObserver(this, "specialpowers-http-notify-request");
+ }
+}
+window.FormActionExaminer = new examiner();
+
+function loadNextTest() {
+ counter++;
+ if (counter == tests.length) {
+ window.FormActionExaminer.remove();
+ SimpleTest.finish();
+ return;
+ }
+
+ var src = "file_testserver.sjs";
+ // append the file that should be served
+ src += "?file=" + escape("tests/dom/security/test/csp/" + tests[counter].page);
+ // append the CSP that should be used to serve the file
+ src += "&csp=" + escape(tests[counter].policy);
+
+ document.getElementById("testframe").src = src;
+}
+
+// start running the tests
+loadNextTest();
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_form_action_blocks_url.html b/dom/security/test/csp/test_form_action_blocks_url.html
new file mode 100644
index 0000000000..f835504ff4
--- /dev/null
+++ b/dom/security/test/csp/test_form_action_blocks_url.html
@@ -0,0 +1,76 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>Bug 1251043 - Test form-action blocks URL</title>
+ <!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+ <iframe id="testframe"></iframe>
+
+<script class="testbody" type="text/javascript">
+/*
+ * Description of the test:
+ * 1) Let's load a form into an iframe which uses a CSP of: form-action 'none';
+ * 2) Let's hit the submit button and make sure the form is not submitted.
+ *
+ * Since a blocked form submission does not fire any event handler, we have to
+ * use timeout triggered function that verifies that the form didn't get submitted.
+ */
+
+SimpleTest.requestFlakyTimeout(
+ "Form submission blocked by CSP does not fire any events " +
+ "hence we have to check back after 300ms to make sure the form " +
+ "is not submitted");
+SimpleTest.waitForExplicitFinish();
+
+const FORM_SUBMITTED = "form submission succeeded";
+var timeOutId;
+var testframe = document.getElementById("testframe");
+
+// In case the form gets submitted, the test would receive an 'load'
+// event and would trigger the test to fail early.
+function logFormSubmittedError() {
+ clearTimeout(timeOutId);
+ testframe.removeEventListener('load', logFormSubmittedError);
+ ok(false, "form submission should be blocked");
+ SimpleTest.finish();
+}
+
+// After 300ms we verify the form did not get submitted.
+function verifyFormNotSubmitted() {
+ clearTimeout(timeOutId);
+ var frameContent = testframe.contentWindow.document.body.innerHTML;
+ isnot(frameContent.indexOf("CONTROL-TEXT"), -1,
+ "form should not be submitted and still contain the control text");
+ SimpleTest.finish();
+}
+
+function submitForm() {
+ // Part 1: The form has loaded in the testframe
+ // unregister the current event handler
+ testframe.removeEventListener('load', submitForm);
+
+ // Part 2: Register a new load event handler. In case the
+ // form gets submitted, this load event fires and we can
+ // fail the test right away.
+ testframe.addEventListener("load", logFormSubmittedError);
+
+ // Part 3: Since blocking the form does not throw any kind of error;
+ // Firefox just logs the CSP error to the console we have to register
+ // this timeOut function which then verifies that the form didn't
+ // get submitted.
+ timeOutId = setTimeout(verifyFormNotSubmitted, 300);
+
+ // Part 4: We are ready, let's hit the submit button of the form.
+ var submitButton = testframe.contentWindow.document.getElementById('submitButton');
+ submitButton.click();
+}
+
+testframe.addEventListener("load", submitForm);
+testframe.src = "file_form_action_server.sjs?loadframe";
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_frame_ancestors_ro.html b/dom/security/test/csp/test_frame_ancestors_ro.html
new file mode 100644
index 0000000000..1cfe6be1cd
--- /dev/null
+++ b/dom/security/test/csp/test_frame_ancestors_ro.html
@@ -0,0 +1,69 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for frame-ancestors support in Content-Security-Policy-Report-Only</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<iframe style="width: 100%" id="cspframe"></iframe>
+<script type="text/javascript">
+const docUri = "http://mochi.test:8888/tests/dom/security/test/csp/file_frame_ancestors_ro.html";
+const frame = document.getElementById("cspframe");
+
+let testResults = {
+ reportFired: false,
+ frameLoaded: false
+};
+
+function checkResults(reportObj) {
+ let cspReport = reportObj["csp-report"];
+ is(cspReport["document-uri"], docUri, "Incorrect document-uri");
+
+ // we can not test for the whole referrer since it includes platform specific information
+ is(cspReport.referrer, document.location.toString(), "Incorrect referrer");
+ is(cspReport["blocked-uri"], document.location.toString(), "Incorrect blocked-uri");
+ is(cspReport["violated-directive"], "frame-ancestors", "Incorrect violated-directive");
+ is(cspReport["original-policy"], "frame-ancestors 'none'; report-uri http://mochi.test:8888/foo.sjs", "Incorrect original-policy");
+ testResults.reportFired = true;
+}
+
+let chromeScriptUrl = SimpleTest.getTestFileURL("file_report_chromescript.js");
+let script = SpecialPowers.loadChromeScript(chromeScriptUrl);
+
+script.addMessageListener('opening-request-completed', function ml(msg) {
+ if (msg.error) {
+ ok(false, "Could not query report (exception: " + msg.error + ")");
+ } else {
+ try {
+ let reportObj = JSON.parse(msg.report);
+ // test for the proper values in the report object
+ checkResults(reportObj);
+ } catch (e) {
+ ok(false, "Error verifying report object (exception: " + e + ")");
+ }
+ }
+
+ script.removeMessageListener('opening-request-completed', ml);
+ script.sendAsyncMessage("finish");
+ checkTestResults();
+});
+
+frame.addEventListener( 'load', () => {
+ // Make sure the frame is still loaded
+ testResults.frameLoaded = true;
+ checkTestResults()
+} );
+
+function checkTestResults() {
+ if( testResults.reportFired && testResults.frameLoaded ) {
+ SimpleTest.finish();
+ }
+}
+
+SimpleTest.waitForExplicitFinish();
+frame.src = docUri;
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_frame_src.html b/dom/security/test/csp/test_frame_src.html
new file mode 100644
index 0000000000..f87549b72b
--- /dev/null
+++ b/dom/security/test/csp/test_frame_src.html
@@ -0,0 +1,84 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Bug 1302667 - Test frame-src</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<iframe style="width:100%;" id="testframe"></iframe>
+
+<script class="testbody" type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+
+/* Description of the test:
+ * We load a page inlcuding a frame a CSP of:
+ * >> frame-src https://example.com; child-src 'none'
+ * and make sure that frame-src governs frames correctly. In addition,
+ * we make sure that child-src is discarded in case frame-src is specified.
+ */
+
+const ORIGIN_1 = "https://example.com/tests/dom/security/test/csp/";
+const ORIGIN_2 = "https://test1.example.com/tests/dom/security/test/csp/";
+
+let TESTS = [
+ // frame-src tests
+ ORIGIN_1 + "file_frame_src_frame_governs.html",
+ ORIGIN_2 + "file_frame_src_frame_governs.html",
+ // child-src tests
+ ORIGIN_1 + "file_frame_src_child_governs.html",
+ ORIGIN_2 + "file_frame_src_child_governs.html",
+];
+
+let testIndex = 0;
+
+function checkFinish() {
+ if (testIndex >= TESTS.length) {
+ window.removeEventListener("message", receiveMessage);
+ SimpleTest.finish();
+ return;
+ }
+ runNextTest();
+}
+
+window.addEventListener("message", receiveMessage);
+function receiveMessage(event) {
+ let href = event.data.href;
+ let result = event.data.result;
+
+ if (href.startsWith("https://example.com")) {
+ if (result == "frame-allowed") {
+ ok(true, "allowing frame from https://example.com (" + result + ")");
+ }
+ else {
+ ok(false, "blocking frame from https://example.com (" + result + ")");
+ }
+ }
+ else if (href.startsWith("https://test1.example.com")) {
+ if (result == "frame-blocked") {
+ ok(true, "blocking frame from https://test1.example.com (" + result + ")");
+ }
+ else {
+ ok(false, "allowing frame from https://test1.example.com (" + result + ")");
+ }
+ }
+ else {
+ // sanity check, we should never enter that branch, bust just in case...
+ ok(false, "unexpected result: " + result);
+ }
+ checkFinish();
+}
+
+function runNextTest() {
+ document.getElementById("testframe").src = TESTS[testIndex];
+ testIndex++;
+}
+
+// fire up the tests
+runNextTest();
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_frameancestors.html b/dom/security/test/csp/test_frameancestors.html
new file mode 100644
index 0000000000..8b44ba72fb
--- /dev/null
+++ b/dom/security/test/csp/test_frameancestors.html
@@ -0,0 +1,160 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for Content Security Policy Frame Ancestors directive</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+<iframe style="width:100%;height:300px;" id='cspframe'></iframe>
+<script class="testbody" type="text/javascript">
+
+// These are test results: -1 means it hasn't run,
+// true/false is the pass/fail result.
+var framesThatShouldLoad = {
+ aa_allow: -1, /* innermost frame allows a *
+ //aa_block: -1, /* innermost frame denies a */
+ ab_allow: -1, /* innermost frame allows a */
+ //ab_block: -1, /* innermost frame denies a */
+ aba_allow: -1, /* innermost frame allows b,a */
+ //aba_block: -1, /* innermost frame denies b */
+ //aba2_block: -1, /* innermost frame denies a */
+ abb_allow: -1, /* innermost frame allows b,a */
+ //abb_block: -1, /* innermost frame denies b */
+ //abb2_block: -1, /* innermost frame denies a */
+};
+
+// we normally expect _6_ violations (6 test cases that cause blocks), but many
+// of the cases cause violations due to the // origin of the test harness (same
+// as 'a'). When the violation is cross-origin, the URI passed to the observers
+// is null (see bug 846978). This means we can't tell if it's part of the test
+// case or if it is the test harness frame (also origin 'a').
+// As a result, we'll get an extra violation for the following cases:
+// ab_block "frame-ancestors 'none'" (outer frame and test harness)
+// aba2_block "frame-ancestors b" (outer frame and test harness)
+// abb2_block "frame-ancestors b" (outer frame and test harness)
+//
+// and while we can detect the test harness check for this one case since
+// the violations are not cross-origin and we get the URI:
+// aba2_block "frame-ancestors b" (outer frame and test harness)
+//
+// we can't for these other ones:
+// ab_block "frame-ancestors 'none'" (outer frame and test harness)
+// abb2_block "frame-ancestors b" (outer frame and test harness)
+//
+// so that results in 2 extra violation notifications due to the test harness.
+// expected = 6, total = 8
+//
+// Number of tests that pass for this file should be 12 (8 violations 4 loads)
+var expectedViolationsLeft = 8;
+
+// CSP frame-ancestor checks happen in the parent, hence we have to
+// proxy the csp violation notifications.
+SpecialPowers.registerObservers("csp-on-violate-policy");
+
+// This is used to watch the blocked data bounce off CSP and allowed data
+// get sent out to the wire.
+function examiner() {
+ SpecialPowers.addObserver(this, "specialpowers-csp-on-violate-policy");
+}
+examiner.prototype = {
+ observe(subject, topic, data) {
+ // subject should be an nsURI... though could be null since CSP
+ // prohibits cross-origin URI reporting during frame ancestors checks.
+ if (subject && !SpecialPowers.can_QI(subject))
+ return;
+
+ var asciiSpec = subject;
+
+ try {
+ asciiSpec = SpecialPowers.getPrivilegedProps(
+ SpecialPowers.do_QueryInterface(subject, "nsIURI"),
+ "asciiSpec");
+
+ // skip checks on the test harness -- can't do this skipping for
+ // cross-origin blocking since the observer doesn't get the URI. This
+ // can cause this test to over-succeed (but only in specific cases).
+ if (asciiSpec.includes("test_frameancestors.html")) {
+ return;
+ }
+ } catch (ex) {
+ // was not an nsIURI, so it was probably a cross-origin report.
+ }
+
+ if (topic === "specialpowers-csp-on-violate-policy") {
+ //these were blocked... record that they were blocked
+ window.frameBlocked(asciiSpec, data);
+ }
+ },
+
+ // must eventually call this to remove the listener,
+ // or mochitests might get borked.
+ remove() {
+ SpecialPowers.removeObserver(this, "specialpowers-csp-on-violate-policy");
+ }
+}
+
+// called when a frame is loaded
+// -- if it's not enumerated above, it should not load!
+var frameLoaded = function(testname, uri) {
+ //test already complete.... forget it... remember the first result.
+ if (window.framesThatShouldLoad[testname] != -1)
+ return;
+
+ if (typeof window.framesThatShouldLoad[testname] === 'undefined') {
+ // uh-oh, we're not expecting this frame to load!
+ ok(false, testname + ' framed site should not have loaded: ' + uri);
+ } else {
+ framesThatShouldLoad[testname] = true;
+ ok(true, testname + ' framed site when allowed by csp (' + uri + ')');
+ }
+ checkTestResults();
+}
+
+// called when a frame is blocked
+// -- we can't determine *which* frame was blocked, but at least we can count them
+var frameBlocked = function(uri, policy) {
+ ok(true, 'a CSP policy blocked frame from being loaded: ' + policy);
+ expectedViolationsLeft--;
+ checkTestResults();
+}
+
+
+// Check to see if all the tests have run
+var checkTestResults = function() {
+ // if any test is incomplete, keep waiting
+ for (var v in framesThatShouldLoad)
+ if(window.framesThatShouldLoad[v] == -1)
+ return;
+
+ if (window.expectedViolationsLeft > 0)
+ return;
+
+ // ... otherwise, finish
+ window.examiner.remove();
+ SimpleTest.finish();
+}
+
+window.addEventListener("message", receiveMessage);
+
+function receiveMessage(event) {
+ if (event.data.call && event.data.call == 'frameLoaded')
+ frameLoaded(event.data.testname, event.data.uri);
+}
+
+//////////////////////////////////////////////////////////////////////
+// set up and go
+window.examiner = new examiner();
+SimpleTest.waitForExplicitFinish();
+
+// save this for last so that our listeners are registered.
+// ... this loads the testbed of good and bad requests.
+document.getElementById('cspframe').src = 'file_frameancestors_main.html';
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_frameancestors_userpass.html b/dom/security/test/csp/test_frameancestors_userpass.html
new file mode 100644
index 0000000000..332318fe17
--- /dev/null
+++ b/dom/security/test/csp/test_frameancestors_userpass.html
@@ -0,0 +1,148 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for Userpass in Frame Ancestors directive</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+<iframe style="width:100%;height:300px;" id='cspframe'></iframe>
+<script class="testbody" type="text/javascript">
+
+// These are test results: -1 means it hasn't run,
+// true/false is the pass/fail result.
+var framesThatShouldLoad = {
+ frame_a: -1, /* frame a allowed */
+ frame_b: -1, /* frame b allowed */
+};
+
+// Number of tests that pass for this file should be 1
+var expectedViolationsLeft = 1;
+
+// CSP frame-ancestor checks happen in the parent, hence we have to
+// proxy the csp violation notifications.
+SpecialPowers.registerObservers("csp-on-violate-policy");
+
+// This is used to watch the blocked data bounce off CSP and allowed data
+// get sent out to the wire.
+function examiner() {
+ SpecialPowers.addObserver(this, "specialpowers-csp-on-violate-policy");
+}
+examiner.prototype = {
+ observe(subject, topic, data) {
+ // subject should be an nsURI... though could be null since CSP
+ // prohibits cross-origin URI reporting during frame ancestors checks.
+ if (subject && !SpecialPowers.can_QI(subject))
+ return;
+
+ var asciiSpec = subject;
+
+ try {
+ asciiSpec = SpecialPowers.getPrivilegedProps(
+ SpecialPowers.do_QueryInterface(subject, "nsIURI"),
+ "asciiSpec");
+
+ // skip checks on the test harness -- can't do this skipping for
+ // cross-origin blocking since the observer doesn't get the URI. This
+ // can cause this test to over-succeed (but only in specific cases).
+ if (asciiSpec.includes("test_frameancestors_userpass.html")) {
+ return;
+ }
+ } catch (ex) {
+ // was not an nsIURI, so it was probably a cross-origin report.
+ }
+
+ if (topic === "specialpowers-csp-on-violate-policy") {
+ //these were blocked... record that they were blocked
+ window.frameBlocked(asciiSpec, data);
+ }
+ },
+
+ // must eventually call this to remove the listener,
+ // or mochitests might get borked.
+ remove() {
+ SpecialPowers.removeObserver(this, "specialpowers-csp-on-violate-policy");
+ }
+}
+
+// called when a frame is loaded
+// -- if it's not enumerated above, it should not load!
+var frameLoaded = function(testname, uri) {
+ //test already complete.... forget it... remember the first result.
+ if (window.framesThatShouldLoad[testname] != -1)
+ return;
+
+ if (typeof window.framesThatShouldLoad[testname] === 'undefined') {
+ // uh-oh, we're not expecting this frame to load!
+ ok(false, testname + ' framed site should not have loaded: ' + uri);
+ } else {
+ //Check if @ symbol is there in URI.
+ if (uri.includes('@')) {
+ ok(false, ' URI contains userpass. Fetched URI is ' + uri);
+ } else {
+ framesThatShouldLoad[testname] = true;
+ ok(true, ' URI doesn\'t contain userpass. Fetched URI is ' + uri);
+ }
+ }
+ checkTestResults();
+}
+
+// called when a frame is blocked
+// -- we can't determine *which* frame was blocked, but at least we can count them
+var frameBlocked = function(uri, policy) {
+
+ //Check if @ symbol is there in URI or in csp policy.
+ // Bug 1557712: Intermittent failure -> not sure why the 'uri' might ever
+ // be non existing at this point, however if there is no uri, there can
+ // also be no userpass!
+ if (policy.includes('@') ||
+ (typeof uri === 'string' && uri.includes('@'))) {
+ ok(false, ' a CSP policy blocked frame from being loaded. But contains' +
+ ' userpass. Policy is: ' + policy + ';URI is: ' + uri );
+ } else {
+ ok(true, ' a CSP policy blocked frame from being loaded. Doesn\'t contain'+
+ ' userpass. Policy is: ' + policy + ';URI is: ' + uri );
+ }
+ expectedViolationsLeft--;
+ checkTestResults();
+}
+
+
+// Check to see if all the tests have run
+var checkTestResults = function() {
+ // if any test is incomplete, keep waiting
+ for (var v in framesThatShouldLoad)
+ if(window.framesThatShouldLoad[v] == -1)
+ return;
+
+ if (window.expectedViolationsLeft > 0)
+ return;
+
+ // ... otherwise, finish
+ window.examiner.remove();
+ SimpleTest.finish();
+}
+
+window.addEventListener("message", receiveMessage);
+
+function receiveMessage(event) {
+ if (event.data.call && event.data.call == 'frameLoaded')
+ frameLoaded(event.data.testname, event.data.uri);
+}
+
+//////////////////////////////////////////////////////////////////////
+// set up and go
+window.examiner = new examiner();
+SimpleTest.waitForExplicitFinish();
+
+// save this for last so that our listeners are registered.
+// ... this loads the testbed of good and bad requests.
+document.getElementById('cspframe').src = 'file_frameancestors_userpass.html';
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_hash_source.html b/dom/security/test/csp/test_hash_source.html
new file mode 100644
index 0000000000..2334ae0101
--- /dev/null
+++ b/dom/security/test/csp/test_hash_source.html
@@ -0,0 +1,135 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test CSP 1.1 hash-source for inline scripts and styles</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="visibility:hidden">
+ <iframe style="width:100%;" id='cspframe'></iframe>
+</div>
+<script class="testbody" type="text/javascript">
+
+function cleanup() {
+ // finish the tests
+ SimpleTest.finish();
+}
+
+function checkInline () {
+ var cspframe = document.getElementById('cspframe').contentDocument;
+
+ var inlineScriptTests = {
+ 'inline-script-valid-hash': {
+ shouldBe: 'allowed',
+ message: 'Inline script with valid hash should be allowed'
+ },
+ 'inline-script-invalid-hash': {
+ shouldBe: 'blocked',
+ message: 'Inline script with invalid hash should be blocked'
+ },
+ 'inline-script-invalid-hash-valid-nonce': {
+ shouldBe: 'allowed',
+ message: 'Inline script with invalid hash and valid nonce should be allowed'
+ },
+ 'inline-script-valid-hash-invalid-nonce': {
+ shouldBe: 'allowed',
+ message: 'Inline script with valid hash and invalid nonce should be allowed'
+ },
+ 'inline-script-invalid-hash-invalid-nonce': {
+ shouldBe: 'blocked',
+ message: 'Inline script with invalid hash and invalid nonce should be blocked'
+ },
+ 'inline-script-valid-sha512-hash': {
+ shouldBe: 'allowed',
+ message: 'Inline script with a valid sha512 hash should be allowed'
+ },
+ 'inline-script-valid-sha384-hash': {
+ shouldBe: 'allowed',
+ message: 'Inline script with a valid sha384 hash should be allowed'
+ },
+ 'inline-script-valid-sha1-hash': {
+ shouldBe: 'blocked',
+ message: 'Inline script with a valid sha1 hash should be blocked, because sha1 is not a valid hash function'
+ },
+ 'inline-script-valid-md5-hash': {
+ shouldBe: 'blocked',
+ message: 'Inline script with a valid md5 hash should be blocked, because md5 is not a valid hash function'
+ }
+ }
+
+ for (testId in inlineScriptTests) {
+ var test = inlineScriptTests[testId];
+ is(cspframe.getElementById(testId).innerHTML, test.shouldBe, test.message);
+ }
+
+ // Inline style tries to change an element's color to green. If blocked, the
+ // element's color will be the default black.
+ var green = "rgb(0, 128, 0)";
+ var black = "rgb(0, 0, 0)";
+
+ var getElementColorById = function (id) {
+ return window.getComputedStyle(cspframe.getElementById(id)).color;
+ };
+
+ var inlineStyleTests = {
+ 'inline-style-valid-hash': {
+ shouldBe: green,
+ message: 'Inline style with valid hash should be allowed'
+ },
+ 'inline-style-invalid-hash': {
+ shouldBe: black,
+ message: 'Inline style with invalid hash should be blocked'
+ },
+ 'inline-style-invalid-hash-valid-nonce': {
+ shouldBe: green,
+ message: 'Inline style with invalid hash and valid nonce should be allowed'
+ },
+ 'inline-style-valid-hash-invalid-nonce': {
+ shouldBe: green,
+ message: 'Inline style with valid hash and invalid nonce should be allowed'
+ },
+ 'inline-style-invalid-hash-invalid-nonce' : {
+ shouldBe: black,
+ message: 'Inline style with invalid hash and invalid nonce should be blocked'
+ },
+ 'inline-style-valid-sha512-hash': {
+ shouldBe: green,
+ message: 'Inline style with a valid sha512 hash should be allowed'
+ },
+ 'inline-style-valid-sha384-hash': {
+ shouldBe: green,
+ message: 'Inline style with a valid sha384 hash should be allowed'
+ },
+ 'inline-style-valid-sha1-hash': {
+ shouldBe: black,
+ message: 'Inline style with a valid sha1 hash should be blocked, because sha1 is not a valid hash function'
+ },
+ 'inline-style-valid-md5-hash': {
+ shouldBe: black,
+ message: 'Inline style with a valid md5 hash should be blocked, because md5 is not a valid hash function'
+ }
+ }
+
+ for (testId in inlineStyleTests) {
+ var test = inlineStyleTests[testId];
+ is(getElementColorById(testId), test.shouldBe, test.message);
+ }
+
+ cleanup();
+}
+
+//////////////////////////////////////////////////////////////////////
+// set up and go
+SimpleTest.waitForExplicitFinish();
+
+// save this for last so that our listeners are registered.
+// ... this loads the testbed of good and bad requests.
+document.getElementById('cspframe').src = 'file_hash_source.html';
+document.getElementById('cspframe').addEventListener('load', checkInline);
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_iframe_sandbox.html b/dom/security/test/csp/test_iframe_sandbox.html
new file mode 100644
index 0000000000..cd7417bc8b
--- /dev/null
+++ b/dom/security/test/csp/test_iframe_sandbox.html
@@ -0,0 +1,240 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=671389
+Bug 671389 - Implement CSP sandbox directive
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Tests for Bug 671389</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<script type="application/javascript">
+
+ SimpleTest.waitForExplicitFinish();
+
+ // Check if two sandbox flags are the same, ignoring case-sensitivity.
+ // getSandboxFlags returns a list of sandbox flags (if any) or
+ // null if the flag is not set.
+ // This function checks if two flags are the same, i.e., they're
+ // either not set or have the same flags.
+ function eqFlags(a, b) {
+ if (a === null && b === null) { return true; }
+ if (a === null || b === null) { return false; }
+ if (a.length !== b.length) { return false; }
+ var a_sorted = a.map(function(e) { return e.toLowerCase(); }).sort();
+ var b_sorted = b.map(function(e) { return e.toLowerCase(); }).sort();
+ for (var i in a_sorted) {
+ if (a_sorted[i] !== b_sorted[i]) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ // Get the sandbox flags of document doc.
+ // If the flag is not set sandboxFlagsAsString returns null,
+ // this function also returns null.
+ // If the flag is set it may have some flags; in this case
+ // this function returns the (potentially empty) list of flags.
+ function getSandboxFlags(doc) {
+ var flags = doc.sandboxFlagsAsString;
+ if (flags === null) { return null; }
+ return flags? flags.split(" "):[];
+ }
+
+ // Constructor for a CSP sandbox flags test. The constructor
+ // expectes a description 'desc' and set of options 'opts':
+ // - sandboxAttribute: [null] or string corresponding to the iframe sandbox attributes
+ // - csp: [null] or string corresponding to the CSP sandbox flags
+ // - cspReportOnly: [null] or string corresponding to the CSP report-only sandbox flags
+ // - file: [null] or string corresponding to file the server should serve
+ // Above, we use [brackets] to denote default values.
+ function CSPFlagsTest(desc, opts) {
+ function ifundef(x, v) {
+ return (x !== undefined) ? x : v;
+ }
+
+ function intersect(as, bs) { // Intersect two csp attributes:
+ as = as === null ? null
+ : as.split(' ').filter(function(x) { return !!x; });
+ bs = bs === null ? null
+ : bs.split(' ').filter(function(x) { return !!x; });
+
+ if (as === null) { return bs; }
+ if (bs === null) { return as; }
+
+ var cs = [];
+ as.forEach(function(a) {
+ if (a && bs.includes(a))
+ cs.push(a);
+ });
+ return cs;
+ }
+
+ this.desc = desc || "Untitled test";
+ this.attr = ifundef(opts.sandboxAttribute, null);
+ this.csp = ifundef(opts.csp, null);
+ this.cspRO = ifundef(opts.cspReportOnly, null);
+ this.file = ifundef(opts.file, null);
+ this.expected = intersect(this.attr, this.csp);
+ }
+
+ // Return function that checks that the actual flags are the same as the
+ // expected flags
+ CSPFlagsTest.prototype.checkFlags = function(iframe) {
+ var this_ = this;
+ return function() {
+ try {
+ var actual = getSandboxFlags(SpecialPowers.wrap(iframe).contentDocument);
+ ok(eqFlags(actual, this_.expected),
+ this_.desc + ' - expected: "' + this_.expected + '", got: "' + actual + '"');
+ } catch (e) {
+ ok(false,
+ this_.desc + ' - expected: "' + this_.expected + '", failed with: "' + e + '"');
+ }
+ runNextTest();
+ };
+ };
+
+ // Set the iframe src and sandbox attribute
+ CSPFlagsTest.prototype.runTest = function () {
+ var iframe = document.createElement('iframe');
+ document.getElementById("content").appendChild(iframe);
+ iframe.onload = this.checkFlags(iframe);
+
+ // set sandbox attribute
+ if (this.attr === null) {
+ iframe.removeAttribute('sandbox');
+ } else {
+ iframe.sandbox = this.attr;
+ }
+
+ // set query string
+ var src = 'http://mochi.test:8888/tests/dom/security/test/csp/file_testserver.sjs';
+
+ var delim = '?';
+
+ if (this.csp !== null) {
+ src += delim + 'csp=' + escape('sandbox ' + this.csp);
+ delim = '&';
+ }
+
+ if (this.cspRO !== null) {
+ src += delim + 'cspRO=' + escape('sandbox ' + this.cspRO);
+ delim = '&';
+ }
+
+ if (this.file !== null) {
+ src += delim + 'file=' + escape(this.file);
+ delim = '&';
+ }
+
+ iframe.src = src;
+ iframe.width = iframe.height = 10;
+
+ }
+
+ testCases = [
+ {
+ desc: "Test 1: Header should not override attribute",
+ sandboxAttribute: "",
+ csp: "allow-forms aLLOw-POinter-lock alLOW-popups aLLOW-SAME-ORIGin ALLOW-SCRIPTS allow-top-navigation"
+ },
+ {
+ desc: "Test 2: Attribute should not override header",
+ sandboxAttribute: "sandbox allow-forms allow-pointer-lock allow-popups allow-same-origin allow-scripts allow-top-navigation",
+ csp: ""
+ },
+ {
+ desc: "Test 3: Header and attribute intersect",
+ sandboxAttribute: "allow-same-origin allow-scripts",
+ csp: "allow-forms allow-same-origin allow-scripts"
+ },
+ {
+ desc: "Test 4: CSP sandbox sets the right flags (pt 1)",
+ csp: "alLOW-FORms ALLOW-pointer-lock allow-popups allow-same-origin allow-scripts ALLOW-TOP-NAVIGation"
+ },
+ {
+ desc: "Test 5: CSP sandbox sets the right flags (pt 2)",
+ csp: "allow-same-origin allow-TOP-navigation"
+ },
+ {
+ desc: "Test 6: CSP sandbox sets the right flags (pt 3)",
+ csp: "allow-FORMS ALLOW-scripts"
+ },
+ {
+ desc: "Test 7: CSP sandbox sets the right flags (pt 4)",
+ csp: ""
+ },
+ {
+ desc: "Test 8: CSP sandbox sets the right flags (pt 5)",
+ csp: null
+ },
+ {
+ desc: "Test 9: Read-only header should not override attribute",
+ sandboxAttribute: "",
+ cspReportOnly: "allow-forms ALLOW-pointer-lock allow-POPUPS allow-same-origin ALLOW-scripts allow-top-NAVIGATION"
+ },
+ {
+ desc: "Test 10: Read-only header should not override CSP header",
+ csp: "allow-forms allow-scripts",
+ cspReportOnly: "allow-forms aLlOw-PoInTeR-lOcK aLLow-pOPupS aLLoW-SaME-oRIgIN alLow-scripts allow-tOp-navigation"
+ },
+ {
+ desc: "Test 11: Read-only header should not override attribute or CSP header",
+ sandboxAttribute: "allow-same-origin allow-scripts",
+ csp: "allow-forms allow-same-origin allow-scripts",
+ cspReportOnly: "allow-forms allow-pointer-lock allow-popups allow-same-origin allow-scripts allow-top-navigation"
+ },
+ {
+ desc: "Test 12: CSP sandbox not affected by document.write()",
+ csp: "allow-scripts",
+ file: 'tests/dom/security/test/csp/file_iframe_sandbox_document_write.html'
+ },
+ ].map(function(t) { return (new CSPFlagsTest(t.desc,t)); });
+
+
+ var testCaseIndex = 0;
+
+ // Track ok messages from iframes
+ var childMessages = 0;
+ var totalChildMessages = 1;
+
+
+ // Check to see if we ran all the tests and received all messges
+ // from child iframes. If so, finish.
+ function tryFinish() {
+ if (testCaseIndex === testCases.length && childMessages === totalChildMessages){
+ SimpleTest.finish();
+ }
+ }
+
+ function runNextTest() {
+
+ tryFinish();
+
+ if (testCaseIndex < testCases.length) {
+ testCases[testCaseIndex].runTest();
+ testCaseIndex++;
+ }
+ }
+
+ function receiveMessage(event) {
+ ok(event.data.ok, event.data.desc);
+ childMessages++;
+ tryFinish();
+ }
+
+ window.addEventListener("message", receiveMessage);
+
+ addLoadEvent(runNextTest);
+</script>
+<body>
+ <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=671389">Mozilla Bug 671389</a> - Implement CSP sandbox directive
+ <p id="display"></p>
+ <div id="content">
+ </div>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_iframe_sandbox_srcdoc.html b/dom/security/test/csp/test_iframe_sandbox_srcdoc.html
new file mode 100644
index 0000000000..9c36aa5447
--- /dev/null
+++ b/dom/security/test/csp/test_iframe_sandbox_srcdoc.html
@@ -0,0 +1,62 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Bug 1073952 - CSP should restrict scripts in srcdoc iframe even if sandboxed</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<p id="display">Bug 1073952</p>
+<iframe style="width:200px;height:200px;" id='cspframe'></iframe>
+<script class="testbody" type="text/javascript">
+
+// This is used to watch the blocked data bounce off CSP and allowed data
+// get sent out to the wire.
+function examiner() {
+ SpecialPowers.addObserver(this, "csp-on-violate-policy");
+}
+
+examiner.prototype = {
+ observe(subject, topic, data) {
+
+ if(topic === "csp-on-violate-policy") {
+ var violationString = SpecialPowers.getPrivilegedProps(SpecialPowers.
+ do_QueryInterface(subject, "nsISupportsCString"), "data");
+ // the violation subject for inline script violations is unfortunately vague,
+ // all we can do is match the string.
+ if (!violationString.includes("Inline Script")) {
+ return
+ }
+ ok(true, "CSP inherited into sandboxed srcdoc iframe, script blocked.");
+ window.testFinished();
+ }
+ },
+
+ // must eventually call this to remove the listener,
+ // or mochitests might get borked.
+ remove() {
+ SpecialPowers.removeObserver(this, "csp-on-violate-policy");
+ }
+}
+
+window.examiner = new examiner();
+
+function testFinished() {
+ window.examiner.remove();
+ SimpleTest.finish();
+}
+
+addEventListener("message", function(e) {
+ ok(false, "We should not execute JS in srcdoc iframe.");
+ window.testFinished();
+})
+SimpleTest.waitForExplicitFinish();
+
+// save this for last so that our listeners are registered.
+// ... this loads the testbed of good and bad requests.
+document.getElementById('cspframe').src = 'file_iframe_sandbox_srcdoc.html';
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_iframe_sandbox_top_1.html b/dom/security/test/csp/test_iframe_sandbox_top_1.html
new file mode 100644
index 0000000000..c1ade7ac6c
--- /dev/null
+++ b/dom/security/test/csp/test_iframe_sandbox_top_1.html
@@ -0,0 +1,80 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=671389
+Bug 671389 - Implement CSP sandbox directive
+
+Tests CSP sandbox attribute on top-level page.
+
+Minimal flags: allow-same-origin allow-scripts:
+Since we need to load the SimpleTest files, we have to set the
+allow-same-origin flag. Additionally, we set the allow-scripts flag
+since we need JS to check the flags.
+
+Though not necessary, for this test we also set the allow-forms flag.
+We may later wish to extend the testing suite with sandbox_csp_top_*
+tests that set different permutations of the flags.
+
+CSP header: Content-Security-Policy: sandbox allow-forms allow-scripts allow-same-origin
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Tests for Bug 671389</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<script type="application/javascript">
+
+SimpleTest.waitForExplicitFinish();
+
+// Check if two sandbox flags are the same.
+// getSandboxFlags returns a list of sandbox flags (if any) or
+// null if the flag is not set.
+// This function checks if two flags are the same, i.e., they're
+// either not set or have the same flags.
+function eqFlags(a, b) {
+ if (a === null && b === null) { return true; }
+ if (a === null || b === null) { return false; }
+ if (a.length !== b.length) { return false; }
+ var a_sorted = a.sort();
+ var b_sorted = b.sort();
+ for (var i in a_sorted) {
+ if (a_sorted[i] !== b_sorted[i]) {
+ return false;
+ }
+ }
+ return true;
+}
+
+// Get the sandbox flags of document doc.
+// If the flag is not set sandboxFlagsAsString returns null,
+// this function also returns null.
+// If the flag is set it may have some flags; in this case
+// this function returns the (potentially empty) list of flags.
+function getSandboxFlags(doc) {
+ var flags = doc.sandboxFlagsAsString;
+ if (flags === null) { return null; }
+ return flags? flags.split(" "):[];
+}
+
+function checkFlags(expected) {
+ try {
+ var flags = getSandboxFlags(SpecialPowers.wrap(document));
+ ok(eqFlags(flags, expected), name + ' expected: "' + expected + '", got: "' + flags + '"');
+ } catch (e) {
+ ok(false, name + ' expected "' + expected + ', but failed with ' + e);
+ }
+ SimpleTest.finish();
+}
+
+</script>
+
+<body onLoad='checkFlags(["allow-forms", "allow-scripts", "allow-same-origin"]);'>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=671389">Mozilla Bug 671389</a> - Implement CSP sandbox directive
+<p id="display"></p>
+<div id="content">
+ I am a top-level page sandboxed with "allow-scripts allow-forms
+ allow-same-origin".
+</div>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_iframe_sandbox_top_1.html^headers^ b/dom/security/test/csp/test_iframe_sandbox_top_1.html^headers^
new file mode 100644
index 0000000000..d9cd0606e7
--- /dev/null
+++ b/dom/security/test/csp/test_iframe_sandbox_top_1.html^headers^
@@ -0,0 +1 @@
+Content-Security-Policy: sAnDbOx aLLow-FOrms aLlOw-ScRiPtS ALLOW-same-origin
diff --git a/dom/security/test/csp/test_iframe_srcdoc.html b/dom/security/test/csp/test_iframe_srcdoc.html
new file mode 100644
index 0000000000..04694aa5e0
--- /dev/null
+++ b/dom/security/test/csp/test_iframe_srcdoc.html
@@ -0,0 +1,140 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 1073952 - Test CSP enforcement within iframe srcdoc</title>
+ <!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<iframe style="width:100%;" id="testframe"></iframe>
+
+<script class="testbody" type="text/javascript">
+
+/*
+ * Description of the test:
+ * (1) We serve a site which makes use of script-allowed sandboxed iframe srcdoc
+ * and make sure that CSP applies to the nested browsing context
+ * within the iframe.
+ * [PAGE WITH CSP [IFRAME SANDBOX SRCDOC [SCRIPT]]]
+ *
+ * (2) We serve a site which nests script within an script-allowed sandboxed
+ * iframe srcdoc within another script-allowed sandboxed iframe srcdoc and
+ * make sure that CSP applies to the nested browsing context
+ * within the iframe*s*.
+ * [PAGE WITH CSP [IFRAME SANDBOX SRCDOC [IFRAME SANDBOX SRCDOC [SCRIPT]]]]
+ *
+ * Please note that the test relies on the "csp-on-violate-policy" observer.
+ * Whenever the script within the iframe is blocked observers are notified.
+ * In turn, this renders the 'result' within tests[] unused. In case the script
+ * would execute however, the postMessageHandler would bubble up 'allowed' and
+ * the test would fail.
+ */
+
+SimpleTest.waitForExplicitFinish();
+
+var tests = [
+ // [PAGE *WITHOUT* CSP [IFRAME SRCDOC [SCRIPT]]]
+ { csp: "",
+ result: "allowed",
+ query: "simple_iframe_srcdoc",
+ desc: "No CSP should run script within script-allowed sandboxed iframe srcdoc"
+ },
+ { csp: "script-src https://test1.com",
+ result: "blocked",
+ query: "simple_iframe_srcdoc",
+ desc: "CSP should block script within script-allowed sandboxediframe srcdoc"
+ },
+ // [PAGE *WITHOUT* CSP [IFRAME SRCDOC [IFRAME SRCDOC [SCRIPT]]]]
+ { csp: "",
+ result: "allowed",
+ query: "nested_iframe_srcdoc",
+ desc: "No CSP should run script within script-allowed sandboxed iframe srcdoc nested within another script-allowed sandboxed iframe srcdoc"
+ },
+ // [PAGE WITH CSP [IFRAME SRCDOC ]]
+ { csp: "script-src https://test2.com",
+ result: "blocked",
+ query: "nested_iframe_srcdoc",
+ desc: "CSP should block script within script-allowed sandboxed iframe srcdoc nested within another script-allowed sandboxed iframe srcdoc"
+ },
+ { csp: "",
+ result: "allowed",
+ query: "nested_iframe_srcdoc_datauri",
+ desc: "No CSP, should run script within script-allowed sandboxed iframe src with data URL nested within another script-allowed sandboxed iframe srcdoc"
+ },
+ { csp: "script-src https://test3.com",
+ result: "blocked",
+ query: "nested_iframe_srcdoc_datauri",
+ desc: "CSP should block script within script-allowed sandboxed iframe src with data URL nested within another script-allowed sandboxed iframe srcdoc"
+ },
+
+];
+
+// initializing to -1 so we start at index 0 when we start the test
+var counter = -1;
+
+function finishTest() {
+ window.removeEventListener("message", receiveMessage);
+ window.examiner.remove();
+ SimpleTest.finish();
+}
+
+window.addEventListener("message", receiveMessage);
+function receiveMessage(event) {
+ var result = event.data.result;
+ testComplete(result, tests[counter].result, tests[counter].desc);
+}
+
+function examiner() {
+ SpecialPowers.addObserver(this, "csp-on-violate-policy");
+}
+
+examiner.prototype = {
+ observe(subject, topic, data) {
+ if (topic === "csp-on-violate-policy") {
+ var violationString = SpecialPowers.getPrivilegedProps(SpecialPowers.
+ do_QueryInterface(subject, "nsISupportsCString"), "data");
+ // the violation subject for inline script violations is unfortunately vague,
+ // all we can do is match the string.
+ if (!violationString.includes("Inline Script")) {
+ return
+ }
+ testComplete("blocked", tests[counter].result, tests[counter].desc);
+ }
+ },
+ remove() {
+ SpecialPowers.removeObserver(this, "csp-on-violate-policy");
+ }
+}
+
+function testComplete(result, expected, desc) {
+ is(result, expected, desc);
+ // ignore cases when we get csp violations and postMessage from the same frame.
+ var frameURL = new URL(document.getElementById("testframe").src);
+ var params = new URLSearchParams(frameURL.search);
+ var counterInFrame = params.get("counter");
+ if (counterInFrame == counter) {
+ loadNextTest();
+ }
+}
+
+function loadNextTest() {
+ counter++;
+ if (counter == tests.length) {
+ finishTest();
+ return;
+ }
+ var src = "file_iframe_srcdoc.sjs";
+ src += "?csp=" + escape(tests[counter].csp);
+ src += "&action=" + escape(tests[counter].query);
+ src += "&counter=" + counter;
+ document.getElementById("testframe").src = src;
+}
+
+// start running the tests
+window.examiner = new examiner();
+loadNextTest();
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_ignore_unsafe_inline.html b/dom/security/test/csp/test_ignore_unsafe_inline.html
new file mode 100644
index 0000000000..09d08157da
--- /dev/null
+++ b/dom/security/test/csp/test_ignore_unsafe_inline.html
@@ -0,0 +1,122 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 1004703 - ignore 'unsafe-inline' if nonce- or hash-source specified</title>
+ <!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<iframe style="width:100%;" id="testframe"></iframe>
+
+<script class="testbody" type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+
+/* Description of the test:
+ * We load a page that contains three scripts using different policies
+ * and make sure 'unsafe-inline' is ignored within script-src if hash-source
+ * or nonce-source is specified.
+ *
+ * The expected output of each test is a sequence of chars.
+ * E.g. the default char we expect is 'a', depending on what inline scripts
+ * are allowed to run we also expect 'b', 'c', 'd'.
+ *
+ * The test also covers the handling of multiple policies where the second
+ * policy makes use of a directive that should *not* fallback to
+ * default-src, see Bug 1198422.
+ */
+
+const POLICY_PREFIX = "default-src 'none'; script-src ";
+
+var tests = [
+ {
+ policy1: POLICY_PREFIX + "'unsafe-inline'",
+ policy2: "frame-ancestors 'self'",
+ description: "'unsafe-inline' allows all scripts to execute",
+ file: "file_ignore_unsafe_inline.html",
+ result: "abcd",
+ },
+ {
+ policy1: POLICY_PREFIX + "'unsafe-inline' 'sha256-uJXAPKP5NZxnVMZMUkDofh6a9P3UMRc1CRTevVPS/rI='",
+ policy2: "base-uri http://mochi.test",
+ description: "defining a hash should only allow one script to execute",
+ file: "file_ignore_unsafe_inline.html",
+ result: "ac",
+ },
+ {
+ policy1: POLICY_PREFIX + "'unsafe-inline' 'nonce-FooNonce'",
+ policy2: "form-action 'none'",
+ description: "defining a nonce should only allow one script to execute",
+ file: "file_ignore_unsafe_inline.html",
+ result: "ad",
+ },
+ {
+ policy1: POLICY_PREFIX + "'unsafe-inline' 'sha256-uJXAPKP5NZxnVMZMUkDofh6a9P3UMRc1CRTevVPS/rI=' 'nonce-FooNonce'",
+ policy2: "upgrade-insecure-requests",
+ description: "defining hash and nonce should allow two scripts to execute",
+ file: "file_ignore_unsafe_inline.html",
+ result: "acd",
+ },
+ {
+ policy1: POLICY_PREFIX + "'unsafe-inline' 'sha256-uJXAPKP5NZxnVMZMUkDofh6a9P3UMRc1CRTevVPS/rI=' 'nonce-FooNonce' 'unsafe-inline'",
+ policy2: "referrer origin",
+ description: "defining hash, nonce and 'unsafe-inline' twice should still only allow two scripts to execute",
+ file: "file_ignore_unsafe_inline.html",
+ result: "acd",
+ },
+ {
+ policy1: "default-src 'unsafe-inline' 'sha256-uJXAPKP5NZxnVMZMUkDofh6a9P3UMRc1CRTevVPS/rI=' 'nonce-FooNonce' ",
+ policy2: "sandbox allow-scripts allow-same-origin",
+ description: "unsafe-inline should be ignored within default-src when a hash or nonce is specified",
+ file: "file_ignore_unsafe_inline.html",
+ result: "acd",
+ },
+];
+
+var counter = 0;
+var curTest;
+
+function loadNextTest() {
+ if (counter == tests.length) {
+ document.getElementById("testframe").removeEventListener("load", test);
+ SimpleTest.finish();
+ return;
+ }
+
+ curTest = tests[counter++];
+ var src = "file_ignore_unsafe_inline_multiple_policies_server.sjs?file=";
+ // append the file that should be served
+ src += escape("tests/dom/security/test/csp/" + curTest.file);
+
+ // append the first CSP that should be used to serve the file
+ src += "&csp1=" + escape(curTest.policy1);
+ // append the second CSP that should be used to serve the file
+ src += "&csp2=" + escape(curTest.policy2);
+
+ document.getElementById("testframe").addEventListener("load", test);
+ document.getElementById("testframe").src = src;
+}
+
+function test() {
+ try {
+ document.getElementById("testframe").removeEventListener('load', test);
+ var testframe = document.getElementById("testframe");
+ var divcontent = testframe.contentWindow.document.getElementById('testdiv').innerHTML;
+ // sort the characters to make sure the result is in ascending order
+ // in case handlers run out of order
+ divcontent = divcontent.split('').sort().join('');
+
+ is(divcontent, curTest.result, curTest.description);
+ }
+ catch (e) {
+ ok(false, "error: could not access content for test " + curTest.description + "!");
+ }
+ loadNextTest();
+}
+
+loadNextTest();
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_ignore_xfo.html b/dom/security/test/csp/test_ignore_xfo.html
new file mode 100644
index 0000000000..5dbfecd18d
--- /dev/null
+++ b/dom/security/test/csp/test_ignore_xfo.html
@@ -0,0 +1,120 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 1024557: Ignore x-frame-options if CSP with frame-ancestors exists</title>
+ <!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<iframe style="width:100%;" id="csp_testframe"></iframe>
+<iframe style="width:100%;" id="csp_testframe_no_xfo"></iframe>
+<iframe style="width:100%;" id="csp_ro_testframe"></iframe>
+
+<script class="testbody" type="text/javascript">
+
+/*
+ * We load two frames using:
+ * x-frame-options: deny
+ * where the first frame uses a csp and the second a csp_ro including frame-ancestors.
+ * We make sure that xfo is ignored for regular csp but not for csp_ro.
+ */
+
+SimpleTest.waitForExplicitFinish();
+
+var script = SpecialPowers.loadChromeScript(() => {
+/* eslint-env mozilla/chrome-script */
+ let ignoreCount = 0;
+ function listener(msg) {
+ if(msg.message.includes("Content-Security-Policy: Ignoring ‘x-frame-options’ because of ‘frame-ancestors’ directive.")) {
+ ignoreCount++;
+ if(ignoreCount == 2) {
+ ok(false, 'The "Content-Security-Policy: Ignoring ‘x-frame-options’ because of ‘frame-ancestors’ directive." warning should only appear once for the csp_testframe.');
+ }
+ }
+ }
+ Services.console.registerListener(listener);
+
+ addMessageListener("cleanup", () => {
+ Services.console.unregisterListener(listener);
+ });
+});
+
+SimpleTest.registerCleanupFunction(async () => {
+ await script.sendQuery("cleanup");
+});
+
+var testcounter = 0;
+function checkFinished() {
+ testcounter++;
+ if (testcounter < 4) {
+ return;
+ }
+ // remove the listener and we are done.
+ window.examiner.remove();
+ SimpleTest.finish();
+}
+
+// X-Frame-Options checks happen in the parent, hence we have to
+// proxy the xfo violation notifications.
+SpecialPowers.registerObservers("xfo-on-violate-policy");
+
+function examiner() {
+ SpecialPowers.addObserver(this, "specialpowers-xfo-on-violate-policy");
+}
+examiner.prototype = {
+ observe(subject, topic, data) {
+ var asciiSpec = SpecialPowers.getPrivilegedProps(SpecialPowers.do_QueryInterface(subject, "nsIURI"), "asciiSpec");
+
+ is(asciiSpec, "http://mochi.test:8888/tests/dom/security/test/csp/file_ro_ignore_xfo.html", "correct subject");
+ ok(topic.endsWith("xfo-on-violate-policy"), "correct topic");
+ is(data, "deny", "correct data");
+ checkFinished();
+ },
+ remove() {
+ SpecialPowers.removeObserver(this, "specialpowers-xfo-on-violate-policy");
+ }
+}
+window.examiner = new examiner();
+
+// 1) test XFO with CSP
+var csp_testframe = document.getElementById("csp_testframe");
+csp_testframe.onload = function() {
+ var msg = csp_testframe.contentDocument.getElementById("cspmessage");
+ is(msg.innerHTML, "Ignoring XFO because of CSP", "Loading frame with with XFO and CSP");
+ checkFinished();
+}
+csp_testframe.onerror = function() {
+ ok(false, "sanity: should not fire onerror for csp_testframe");
+ checkFinished();
+}
+csp_testframe.src = "file_ignore_xfo.html";
+
+// 2) test XFO with CSP_RO
+var csp_ro_testframe = document.getElementById("csp_ro_testframe");
+// If XFO denies framing then the onload event should fire.
+csp_ro_testframe.onload = function() {
+ ok(true, "sanity: should fire onload for csp_ro_testframe");
+ checkFinished();
+}
+csp_ro_testframe.onerror = function() {
+ ok(false, "sanity: should not fire onerror for csp_ro_testframe");
+ checkFinished();
+}
+csp_ro_testframe.src = "file_ro_ignore_xfo.html";
+
+var csp_testframe_no_xfo = document.getElementById("csp_testframe_no_xfo");
+csp_testframe_no_xfo.onload = function() {
+ var msg = csp_testframe_no_xfo.contentDocument.getElementById("cspmessage");
+ is(msg.innerHTML, "Do not log xfo ignore warning when no xfo is set.", "Loading frame with with no XFO and CSP");
+ checkFinished();
+}
+csp_testframe_no_xfo.onerror = function() {
+ ok(false, "sanity: should not fire onerror for csp_testframe_no_xfo");
+ checkFinished();
+}
+csp_testframe_no_xfo.src = "file_no_log_ignore_xfo.html";
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_image_document.html b/dom/security/test/csp/test_image_document.html
new file mode 100644
index 0000000000..eba83f95a7
--- /dev/null
+++ b/dom/security/test/csp/test_image_document.html
@@ -0,0 +1,35 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Bug 1627235: Test CSP for images loaded as iframe</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+
+<iframe id="testframe"></iframe>
+
+<script class="testbody" type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+
+let testframe = document.getElementById("testframe");
+
+testframe.onload = function() {
+ ok(true, "sanity: should fire onload for image document");
+
+ let contentDoc = SpecialPowers.wrap(testframe.contentDocument);
+ let cspJSON = contentDoc.cspJSON;
+ ok(cspJSON.includes("default-src"), "found default-src directive");
+ ok(cspJSON.includes("https://bug1627235.test.com"), "found default-src value");
+ SimpleTest.finish();
+}
+testframe.onerror = function() {
+ ok(false, "sanity: should not fire onerror for image document");
+}
+testframe.src = "file_image_document_pixel.png";
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_image_nonce.html b/dom/security/test/csp/test_image_nonce.html
new file mode 100644
index 0000000000..dd6bc13922
--- /dev/null
+++ b/dom/security/test/csp/test_image_nonce.html
@@ -0,0 +1,60 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Bug 1139297 - Implement CSP upgrade-insecure-requests directive</title>
+ <!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<iframe style="width:100%;" id="testframe"></iframe>
+
+<script class="testbody" type="text/javascript">
+
+/* Description of the test:
+ * We load three images: (a) with a matching nonce,
+ (b) with a non matching nonce,
+ * (c) with no nonce
+ * and make sure that all three images get blocked because
+ * "img-src nonce-bla" should not allow an image load, not
+ * even if the nonce matches*.
+ */
+
+SimpleTest.waitForExplicitFinish();
+
+var counter = 0;
+
+function finishTest() {
+ window.removeEventListener("message", receiveMessage);
+ SimpleTest.finish();
+}
+
+function checkResults(aResult) {
+ counter++;
+ if (aResult === "img-with-matching-nonce-blocked" ||
+ aResult === "img-with_non-matching-nonce-blocked" ||
+ aResult === "img-without-nonce-blocked") {
+ ok (true, "correct result for: " + aResult);
+ }
+ else {
+ ok(false, "unexpected result: " + aResult + "\n\n");
+ }
+ if (counter < 3) {
+ return;
+ }
+ finishTest();
+}
+
+// a postMessage handler that is used by sandboxed iframes without
+// 'allow-same-origin' to bubble up results back to this main page.
+window.addEventListener("message", receiveMessage);
+function receiveMessage(event) {
+ checkResults(event.data.result);
+}
+
+document.getElementById("testframe").src = "file_image_nonce.html";
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_independent_iframe_csp.html b/dom/security/test/csp/test_independent_iframe_csp.html
new file mode 100644
index 0000000000..9549263a11
--- /dev/null
+++ b/dom/security/test/csp/test_independent_iframe_csp.html
@@ -0,0 +1,79 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Bug 1419222 - iFrame CSP should not affect parent document CSP</title>
+ <!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<p id="display"></p>
+<iframe style="width:100%;" id="testframe" src="file_independent_iframe_csp.html"></iframe>
+
+<script class="testbody" type="text/javascript">
+
+ /* Description of the test:
+ This test makes sure adding a CSP directive to an iFrame does not propagate
+ the new directive to the parent document.
+
+ The test page records it's own CSP before and after adding an iFrame
+ with an additional CSP directive.
+
+ CSPs before and after adding the iFrame are compared to make sure they do
+ not differ.
+ */
+
+ SimpleTest.waitForExplicitFinish();
+
+ function finishTest() {
+ window.removeEventListener("message", compareCSPs);
+ SimpleTest.finish();
+ }
+
+ function compareCSPs(event) {
+ try {
+ var beginCspObj = event.data.result[0];
+ var iFrameCspObj = event.data.result[1];
+ var endCspObj = event.data.result[2];
+
+ // make sure the parent document had one policy from the start.
+ var beginPolicies = beginCspObj["csp-policies"];
+ is(beginPolicies.length, 1, "The parent doc should start with one policy applied.");
+
+ // make sure the parent document still has one policy after adding the iFrame.
+ var endPolicies = endCspObj["csp-policies"];
+ is(endPolicies.length, 1, "The parent doc should still have one policy applied after adding the iFrame.");
+
+ // make sure the iFrame has an additional CSP policy.
+ var iFramePolicies = iFrameCspObj["csp-policies"];
+ is(iFramePolicies.length, 2, "The iFrame should have two policies applied");
+
+ var beginDirs = [];
+ var endDirs = [];
+ for (var dir in beginPolicies[0]) {
+ beginDirs.push(dir);
+ }
+ for (var dir in endPolicies[0]) {
+ endDirs.push(dir);
+ }
+ // Check correct number of CSP diretives.
+ is(beginDirs.length, 3, "The parent's CSP policy should contain 3 directives.");
+ // Compare the parent'S CSP directives before and after adding the iFrame.
+ ok((beginDirs.length == endDirs.length && beginDirs.every((value, index) => value == endDirs[index])),
+ "Begin and end CSP directives of the parent should not differ");
+ }
+ catch (e) {
+ ok(false, "uuh, something went wrong within independent iFrame csp test");
+ }
+
+ finishTest();
+ }
+
+ // a postMessage handler to initiate the checks after the iFrame was added to
+ // the test page.
+ window.addEventListener("message", compareCSPs);
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_inlinescript.html b/dom/security/test/csp/test_inlinescript.html
new file mode 100644
index 0000000000..99b055f0c7
--- /dev/null
+++ b/dom/security/test/csp/test_inlinescript.html
@@ -0,0 +1,123 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test for Content Security Policy Frame Ancestors directive</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+<iframe style="width:100%;height:300px;" id='testframe'></iframe>
+
+<script class="testbody" type="text/javascript">
+
+var tests = [
+ {
+ /* test allowed */
+ csp: "default-src 'self'; script-src 'self' 'unsafe-inline'",
+ results: ["body-onload-fired", "text-node-fired",
+ "javascript-uri-fired", "javascript-uri-anchor-fired"],
+ desc: "allow inline scripts",
+ received: 0, // counter to make sure we received all 4 reports
+ },
+ {
+ /* test blocked */
+ csp: "default-src 'self'",
+ results: ["inline-script-blocked"],
+ desc: "block inline scripts",
+ received: 0, // counter to make sure we received all 4 reports
+ }
+];
+
+var counter = 0;
+var curTest;
+
+// This is used to watch the blocked data bounce off CSP and allowed data
+// get sent out to the wire.
+function examiner() {
+ SpecialPowers.addObserver(this, "csp-on-violate-policy");
+}
+examiner.prototype = {
+ observe(subject, topic, data) {
+ if (topic !== "csp-on-violate-policy") {
+ return;
+ }
+
+ var what = SpecialPowers.getPrivilegedProps(SpecialPowers.
+ do_QueryInterface(subject, "nsISupportsCString"), "data");
+
+ if (!what.includes("Inline Script had invalid hash") &&
+ !what.includes("Inline Scripts will not execute")) {
+ return;
+ }
+ window.checkResults("inline-script-blocked");
+ },
+ remove() {
+ SpecialPowers.removeObserver(this, "csp-on-violate-policy");
+ }
+}
+
+function finishTest() {
+ window.examiner.remove();
+ window.removeEventListener("message", receiveMessage);
+ SimpleTest.finish();
+}
+
+// Check to see if all the tests have run
+var checkResults = function(result) {
+ var index = curTest.results.indexOf(result);
+ isnot(index, -1, "should find result (" + result +") within test: " + curTest.desc);
+ if (index > -1) {
+ curTest.received += 1;
+ }
+
+ // make sure we receive all the 4 reports for the 4 inline scripts
+ if (curTest.received < 4) {
+ return;
+ }
+
+ if (counter < tests.length) {
+ loadNextTest();
+ return;
+ }
+ finishTest();
+}
+
+// a postMessage handler that is used to bubble up results from the testframe
+window.addEventListener("message", receiveMessage);
+function receiveMessage(event) {
+ checkResults(event.data);
+}
+
+function clickit() {
+ document.getElementById("testframe").removeEventListener('load', clickit);
+ var testframe = document.getElementById('testframe');
+ var a = testframe.contentDocument.getElementById('anchortoclick');
+ sendMouseEvent({type:'click'}, a, testframe.contentWindow);
+}
+
+function loadNextTest() {
+ curTest = tests[counter++];
+ var src = "file_testserver.sjs?file=";
+ // append the file that should be served
+ src += escape("tests/dom/security/test/csp/file_inlinescript.html");
+ // append the CSP that should be used to serve the file
+ src += "&csp=" + escape(curTest.csp);
+
+ document.getElementById("testframe").src = src;
+ document.getElementById("testframe").addEventListener("load", clickit);
+}
+
+// set up the test and go
+window.examiner = new examiner();
+SimpleTest.waitForExplicitFinish();
+loadNextTest();
+
+</script>
+
+</body>
+</html>
diff --git a/dom/security/test/csp/test_inlinestyle.html b/dom/security/test/csp/test_inlinestyle.html
new file mode 100644
index 0000000000..dc15dc5078
--- /dev/null
+++ b/dom/security/test/csp/test_inlinestyle.html
@@ -0,0 +1,107 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for Content Security Policy inline stylesheets stuff</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+
+<iframe style="width:100%;height:300px;" id='cspframe1'></iframe>
+<iframe style="width:100%;height:300px;" id='cspframe2'></iframe>
+<script class="testbody" type="text/javascript">
+
+//////////////////////////////////////////////////////////////////////
+// set up and go
+SimpleTest.waitForExplicitFinish();
+
+var done = 0;
+
+// When a CSP 1.0 compliant policy is specified we should block inline
+// styles applied by <style> element, style attribute, and SMIL <animate> and <set> tags
+// (when it's not explicitly allowed.)
+function checkStyles(evt) {
+ var cspframe = document.getElementById('cspframe1');
+ var color;
+
+ // black means the style wasn't applied. green colors are used for styles
+ //expected to be applied. A color is red if a style is erroneously applied
+ color = window.getComputedStyle(cspframe.contentDocument.getElementById('linkstylediv')).color;
+ ok('rgb(0, 255, 0)' === color, 'External Stylesheet (' + color + ')');
+ color = window.getComputedStyle(cspframe.contentDocument.getElementById('inlinestylediv')).color;
+ ok('rgb(0, 0, 0)' === color, 'Inline Style TAG (' + color + ')');
+ color = window.getComputedStyle(cspframe.contentDocument.getElementById('attrstylediv')).color;
+ ok('rgb(0, 0, 0)' === color, 'Style Attribute (' + color + ')');
+ color = window.getComputedStyle(cspframe.contentDocument.getElementById('csstextstylediv')).color;
+ ok('rgb(0, 255, 0)' === color, 'cssText (' + color + ')');
+ // SMIL tests
+ color = window.getComputedStyle(cspframe.contentDocument.getElementById('xmlTest',null)).fill;
+ ok('rgb(0, 0, 0)' === color, 'XML Attribute styling (SMIL) (' + color + ')');
+ color = window.getComputedStyle(cspframe.contentDocument.getElementById('cssOverrideTest',null)).fill;
+ ok('rgb(0, 0, 0)' === color, 'CSS Override styling (SMIL) (' + color + ')');
+ color = window.getComputedStyle(cspframe.contentDocument.getElementById('cssOverrideTestById',null)).fill;
+ ok('rgb(0, 0, 0)' === color, 'CSS Override styling via ID lookup (SMIL) (' + color + ')');
+ color = window.getComputedStyle(cspframe.contentDocument.getElementById('cssSetTestById',null)).fill;
+ ok('rgb(0, 0, 0)' === color, 'CSS Set Element styling via ID lookup (SMIL) (' + color + ')');
+
+ color = window.getComputedStyle(cspframe.contentDocument.getElementById('modifycsstextdiv')).color;
+ ok('rgb(0, 255, 0)' === color, 'Modify loaded style sheet via cssText (' + color + ')');
+
+ checkIfDone();
+}
+
+// When a CSP 1.0 compliant policy is specified we should allow inline
+// styles when it is explicitly allowed.
+function checkStylesAllowed(evt) {
+ var cspframe = document.getElementById('cspframe2');
+ var color;
+
+ // black means the style wasn't applied. green colors are used for styles
+ // expected to be applied. A color is red if a style is erroneously applied
+ color = window.getComputedStyle(cspframe.contentDocument.getElementById('linkstylediv')).color;
+ ok('rgb(0, 255, 0)' === color, 'External Stylesheet (' + color + ')');
+ color = window.getComputedStyle(cspframe.contentDocument.getElementById('inlinestylediv')).color;
+ ok('rgb(0, 255, 0)' === color, 'Inline Style TAG (' + color + ')');
+ color = window.getComputedStyle(cspframe.contentDocument.getElementById('attrstylediv')).color;
+ ok('rgb(0, 255, 0)' === color, 'Style Attribute (' + color + ')');
+
+ // Note that the below test will fail if "script-src: 'unsafe-inline'" breaks,
+ // since it relies on executing script to set .cssText
+ color = window.getComputedStyle(cspframe.contentDocument.getElementById('csstextstylediv')).color;
+ ok('rgb(0, 255, 0)' === color, 'style.cssText (' + color + ')');
+ // SMIL tests
+ color = window.getComputedStyle(cspframe.contentDocument.getElementById('xmlTest',null)).fill;
+ ok('rgb(0, 255, 0)' === color, 'XML Attribute styling (SMIL) (' + color + ')');
+ color = window.getComputedStyle(cspframe.contentDocument.getElementById('cssOverrideTest',null)).fill;
+ ok('rgb(0, 255, 0)' === color, 'CSS Override styling (SMIL) (' + color + ')');
+ color = window.getComputedStyle(cspframe.contentDocument.getElementById('cssOverrideTestById',null)).fill;
+ ok('rgb(0, 255, 0)' === color, 'CSS Override styling via ID lookup (SMIL) (' + color + ')');
+ color = window.getComputedStyle(cspframe.contentDocument.getElementById('cssSetTestById',null)).fill;
+ ok('rgb(0, 255, 0)' === color, 'CSS Set Element styling via ID lookup (SMIL) (' + color + ')');
+
+ color = window.getComputedStyle(cspframe.contentDocument.getElementById('modifycsstextdiv')).color;
+ ok('rgb(0, 255, 0)' === color, 'Modify loaded style sheet via cssText (' + color + ')');
+
+ checkIfDone();
+}
+
+function checkIfDone() {
+ done++;
+ if (done == 2)
+ SimpleTest.finish();
+}
+
+// save this for last so that our listeners are registered.
+// ... this loads the testbed of good and bad requests.
+document.getElementById('cspframe1').src = 'file_inlinestyle_main.html';
+document.getElementById('cspframe1').addEventListener('load', checkStyles);
+document.getElementById('cspframe2').src = 'file_inlinestyle_main_allowed.html';
+document.getElementById('cspframe2').addEventListener('load', checkStylesAllowed);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_invalid_source_expression.html b/dom/security/test/csp/test_invalid_source_expression.html
new file mode 100644
index 0000000000..c170dc2a27
--- /dev/null
+++ b/dom/security/test/csp/test_invalid_source_expression.html
@@ -0,0 +1,57 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 1086612 - CSP: Let source expression be the empty set in case no valid source can be parsed</title>
+ <!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+ <p id="display"></p>
+ <div id="content" style="visibility: hidden">
+ <iframe style="width:100%;" id="testframe"></iframe>
+ </div>
+
+<script class="testbody" type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+
+/* Description of the test:
+ * We try to parse a policy:
+ * script-src bankid:/*
+ * where the source expression (bankid:/*) is invalid. In that case the source-expression
+ * should be the empty set ('none'), see: http://www.w3.org/TR/CSP11/#source-list-parsing
+ * We confirm that the script is blocked by CSP.
+ */
+
+const policy = "script-src bankid:/*";
+
+function runTest() {
+ var src = "file_testserver.sjs";
+ // append the file that should be served
+ src += "?file=" + escape("tests/dom/security/test/csp/file_invalid_source_expression.html");
+ // append the CSP that should be used to serve the file
+ src += "&csp=" + escape(policy);
+
+ document.getElementById("testframe").addEventListener("load", test);
+ document.getElementById("testframe").src = src;
+}
+
+function test() {
+ try {
+ document.getElementById("testframe").removeEventListener('load', test);
+ var testframe = document.getElementById("testframe");
+ var divcontent = testframe.contentWindow.document.getElementById('testdiv').innerHTML;
+ is(divcontent, "blocked", "should be 'blocked'!");
+ }
+ catch (e) {
+ ok(false, "ERROR: could not access content!");
+ }
+ SimpleTest.finish();
+}
+
+runTest();
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_leading_wildcard.html b/dom/security/test/csp/test_leading_wildcard.html
new file mode 100644
index 0000000000..53994b0013
--- /dev/null
+++ b/dom/security/test/csp/test_leading_wildcard.html
@@ -0,0 +1,101 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 1032303 - CSP - Keep FULL STOP when matching *.foo.com to disallow loads from foo.com</title>
+ <!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+ <p id="display"></p>
+ <div id="content" style="visibility: hidden">
+ <iframe style="width:100%;" id="testframe"></iframe>
+ </div>
+
+<script class="testbody" type="text/javascript">
+
+/*
+ * Description of the test:
+ * We load a page with a CSP that allows scripts to be loaded from *.example.com.
+ * On that page we try to load two scripts:
+ * a) [allowed] leading_wildcard_allowed.js which is served from test1.example.com
+ * b) [blocked] leading_wildcard_blocked.js which is served from example.com
+ *
+ * We verify that only the allowed script executes by registering observers which listen
+ * to CSP violations and http-notifications. Please note that both scripts do *not* exist
+ * in the file system. The test just verifies that CSP blocks correctly.
+ */
+
+SimpleTest.waitForExplicitFinish();
+
+var policy = "default-src 'none' script-src *.example.com";
+var testsExecuted = 0;
+
+function finishTest() {
+ if (++testsExecuted < 2) {
+ return;
+ }
+ window.wildCardExaminer.remove();
+ SimpleTest.finish();
+}
+
+// We use the examiner to identify requests that hit the wire and requests
+// that are blocked by CSP.
+function examiner() {
+ SpecialPowers.addObserver(this, "csp-on-violate-policy");
+ SpecialPowers.addObserver(this, "specialpowers-http-notify-request");
+}
+examiner.prototype = {
+ observe(subject, topic, data) {
+
+ // allowed requests
+ if (topic === "specialpowers-http-notify-request") {
+ if (data.includes("leading_wildcard_allowed.js")) {
+ ok (true, "CSP should allow file_leading_wildcard_allowed.js!");
+ finishTest();
+ }
+ if (data.includes("leading_wildcard_blocked.js")) {
+ ok(false, "CSP should not allow file_leading_wildcard_blocked.js!");
+ finishTest();
+ }
+ }
+
+ // blocked requests
+ if (topic === "csp-on-violate-policy") {
+ var asciiSpec = SpecialPowers.getPrivilegedProps(
+ SpecialPowers.do_QueryInterface(subject, "nsIURI"),
+ "asciiSpec");
+
+ if (asciiSpec.includes("leading_wildcard_allowed.js")) {
+ ok (false, "CSP should not block file_leading_wildcard_allowed.js!");
+ finishTest();
+ }
+ if (asciiSpec.includes("leading_wildcard_blocked.js")) {
+ ok (true, "CSP should block file_leading_wildcard_blocked.js!");
+ finishTest();
+ }
+ }
+ },
+ remove() {
+ SpecialPowers.removeObserver(this, "csp-on-violate-policy");
+ SpecialPowers.removeObserver(this, "specialpowers-http-notify-request");
+ }
+}
+window.wildCardExaminer = new examiner();
+
+function runTest() {
+ var src = "file_testserver.sjs";
+ // append the file that should be served
+ src += "?file=" + escape("tests/dom/security/test/csp/file_leading_wildcard.html");
+ // append the CSP that should be used to serve the file
+ src += "&csp=" + escape(policy);
+
+ document.getElementById("testframe").src = src;
+}
+
+// start running the tests
+runTest();
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_link_rel_preload.html b/dom/security/test/csp/test_link_rel_preload.html
new file mode 100644
index 0000000000..18f236d56a
--- /dev/null
+++ b/dom/security/test/csp/test_link_rel_preload.html
@@ -0,0 +1,80 @@
+<!doctype html>
+<html>
+<head>
+ <title>Bug 1599791 - Test link rel=preload</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<iframe id=testframe></iframe>
+<script class="testbody" type="text/javascript">
+
+// Please note that 'fakeServer' does not exist because the test relies
+// on "csp-on-violate-policy" , and "specialpowers-http-notify-request"
+// which fire if either the request is blocked or fires. The test does
+// not rely on the result of the load.
+
+let TOTAL_TESTS = 3; // script, style, image
+let seenTests = 0;
+
+function examiner() {
+ SpecialPowers.addObserver(this, "csp-on-violate-policy");
+ SpecialPowers.addObserver(this, "specialpowers-http-notify-request");
+}
+examiner.prototype = {
+ observe(subject, topic, data) {
+ if (topic === "csp-on-violate-policy") {
+ let asciiSpec = SpecialPowers.getPrivilegedProps(
+ SpecialPowers.do_QueryInterface(subject, "nsIURI"),
+ "asciiSpec");
+ if (asciiSpec.includes("fakeServer?script") ||
+ asciiSpec.includes("fakeServer?style") ||
+ asciiSpec.includes("fakeServer?fetch") ||
+ asciiSpec.includes("fakeServer?font") ||
+ asciiSpec.includes("fakeServer?image")) {
+ let type = asciiSpec.substring(asciiSpec.indexOf("?") + 1);
+ ok (true, type + " should be blocked by CSP");
+ checkFinished();
+ }
+ }
+
+ if (topic === "specialpowers-http-notify-request") {
+ if (data.includes("fakeServer?script") ||
+ data.includes("fakeServer?style") ||
+ data.includes("fakeServer?fetch") ||
+ data.includes("fakeServer?font") ||
+ data.includes("fakeServer?image")) {
+ let type = data.substring(data.indexOf("?") + 1);
+ ok (false, type + " should not be loaded");
+ checkFinished();
+ }
+ }
+ },
+ remove() {
+ SpecialPowers.removeObserver(this, "csp-on-violate-policy");
+ SpecialPowers.removeObserver(this, "specialpowers-http-notify-request");
+ }
+}
+
+window.examiner = new examiner();
+
+function checkFinished() {
+ seenTests++;
+ if (seenTests == TOTAL_TESTS) {
+ window.examiner.remove();
+ SimpleTest.finish();
+ return;
+ }
+}
+
+SimpleTest.waitForExplicitFinish();
+
+SpecialPowers.pushPrefEnv(
+ {'set':[["network.preload", true]]},
+ function() {
+ document.getElementById("testframe").src = "file_link_rel_preload.html";
+ });
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_meta_csp_self.html b/dom/security/test/csp/test_meta_csp_self.html
new file mode 100644
index 0000000000..8d7d5812a9
--- /dev/null
+++ b/dom/security/test/csp/test_meta_csp_self.html
@@ -0,0 +1,63 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 1387871 - CSP: Test 'self' within meta csp in data: URI iframe</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<iframe style="width:100%;" id="testframe"></iframe>
+
+<script class="testbody" type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+
+/* Description of the test:
+ * We load a data: URI into an iframe which provides a meta-csp
+ * including the keyword 'self'. We make sure 'self' does not
+ * allow a data: image to load.
+ */
+
+window.addEventListener("message", receiveMessage);
+function receiveMessage(event) {
+ window.removeEventListener("message", receiveMessage);
+ is(event.data.result, "dataFrameReady", "sanity: received msg from loaded frame");
+
+ var frame = document.getElementById("testframe");
+
+ // make sure the img was blocked
+ var img = SpecialPowers.wrap(frame).contentDocument.getElementById("testimg");
+ is(img.naturalWidth, 0, "img should be blocked - width should be 0");
+ is(img.naturalHeight, 0, "img should be blocked - height should be 0");
+
+ // sanity check, make sure 'self' translates into data
+ var contentDoc = SpecialPowers.wrap(frame).contentDocument;
+ // parse the cspJSON in a csp-object
+ var cspOBJ = JSON.parse(contentDoc.cspJSON);
+ ok(cspOBJ, "sanity: was able to parse the CSP JSON");
+
+ // make sure we only got one policy
+ var policies = cspOBJ["csp-policies"];
+ is(policies.length, 1, "sanity: received one CSP policy");
+
+ var policy = policies[0];
+ var val = policy['img-src'];
+ is(val.toString(), "'self'", "'self' should translate into data");
+ SimpleTest.finish();
+}
+
+let DATA_URI = `data:text/html,
+ <html>
+ <head>
+ <meta http-equiv="Content-Security-Policy" content="img-src 'self'">
+ </head>
+ <body onload="parent.postMessage({result:'dataFrameReady'},'*');">
+ data: URI frame with meta-csp including 'self'<br/>
+ <img id="testimg" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==" />
+ </body>
+ </html>`;
+document.getElementById("testframe").src = DATA_URI;
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_meta_element.html b/dom/security/test/csp/test_meta_element.html
new file mode 100644
index 0000000000..42cddbacbf
--- /dev/null
+++ b/dom/security/test/csp/test_meta_element.html
@@ -0,0 +1,91 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Bug 663570 - Implement Content Security Policy via <meta> tag</title>
+ <!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<p id="display"></p>
+<iframe style="width:100%;" id="testframe" src="file_meta_element.html"></iframe>
+
+<script class="testbody" type="text/javascript">
+
+/* Description of the test:
+ * The test is twofold:
+ * First, by loading a page using meta csp (into an iframe) we make sure that
+ * images get correctly blocked as the csp policy includes "img-src 'none'";
+ *
+ * Second, we make sure meta csp ignores the following directives:
+ * * report-uri
+ * * frame-ancestors
+ * * sandbox
+ *
+ * Please note that the CSP sanbdox directive (bug 671389) has not landed yet.
+ * Once bug 671389 lands this test will fail and needs to be updated.
+ */
+
+SimpleTest.waitForExplicitFinish();
+const EXPECTED_DIRS = ["img-src", "script-src"];
+
+function finishTest() {
+ window.removeEventListener("message", receiveMessage);
+ SimpleTest.finish();
+}
+
+function checkResults(result) {
+ is(result, "img-blocked", "loading images should be blocked by meta csp");
+
+ try {
+ // get the csp in JSON notation from the principal
+ var frame = document.getElementById("testframe");
+ var contentDoc = SpecialPowers.wrap(frame.contentDocument);
+ var cspJSON = contentDoc.cspJSON;
+
+ ok(cspJSON, "CSP applied through meta element");
+
+ // parse the cspJSON in a csp-object
+ var cspOBJ = JSON.parse(cspJSON);
+ ok(cspOBJ, "was able to parse the JSON");
+
+ // make sure we only got one policy
+ var policies = cspOBJ["csp-policies"];
+ is(policies.length, 1, "there should be one policy applied");
+
+ // iterate the policy and make sure to only encounter
+ // expected directives.
+ var policy = policies[0];
+ for (var dir in policy) {
+ // special case handling for report-only which is not a directive
+ // but present in the JSON notation of the CSP.
+ if (dir === "report-only") {
+ continue;
+ }
+ var index = EXPECTED_DIRS.indexOf(dir);
+ isnot(index, -1, "meta csp contains directive: " + dir + "!");
+
+ // take the element out of the array so we can make sure
+ // that we have seen all the expected values in the end.
+ EXPECTED_DIRS.splice(index, 1);
+ }
+ is(EXPECTED_DIRS.length, 0, "have seen all the expected values");
+ }
+ catch (e) {
+ ok(false, "uuh, something went wrong within meta csp test");
+ }
+
+ finishTest();
+}
+
+// a postMessage handler used to bubble up the onsuccess/onerror state
+// from within the iframe.
+window.addEventListener("message", receiveMessage);
+function receiveMessage(event) {
+ checkResults(event.data.result);
+}
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_meta_header_dual.html b/dom/security/test/csp/test_meta_header_dual.html
new file mode 100644
index 0000000000..679512d068
--- /dev/null
+++ b/dom/security/test/csp/test_meta_header_dual.html
@@ -0,0 +1,135 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Bug 663570 - Implement Content Security Policy via meta tag</title>
+ <!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<p id="display"></p>
+<iframe style="width:100%;" id="testframe"></iframe>
+
+<script class="testbody" type="text/javascript">
+
+/* Description of the test:
+ * We test all sorts of CSPs on documents, including documents with no
+ * CSP, with meta CSP and with meta CSP in combination with a CSP header.
+ */
+
+const TESTS = [
+ {
+ /* load image without any CSP */
+ query: "test1",
+ result: "img-loaded",
+ policyLen: 0,
+ desc: "no CSP should allow load",
+ },
+ {
+ /* load image where meta denies load */
+ query: "test2",
+ result: "img-blocked",
+ policyLen: 1,
+ desc: "meta (img-src 'none') should block load"
+ },
+ {
+ /* load image where meta allows load */
+ query: "test3",
+ result: "img-loaded",
+ policyLen: 1,
+ desc: "meta (img-src http://mochi.test) should allow load"
+ },
+ {
+ /* load image where meta allows but header blocks */
+ query: "test4", // triggers speculative load
+ result: "img-blocked",
+ policyLen: 2,
+ desc: "meta (img-src http://mochi.test), header (img-src 'none') should block load"
+ },
+ {
+ /* load image where meta blocks but header allows */
+ query: "test5", // triggers speculative load
+ result: "img-blocked",
+ policyLen: 2,
+ desc: "meta (img-src 'none'), header (img-src http://mochi.test) should block load"
+ },
+ {
+ /* load image where meta allows and header allows */
+ query: "test6", // triggers speculative load
+ result: "img-loaded",
+ policyLen: 2,
+ desc: "meta (img-src http://mochi.test), header (img-src http://mochi.test) should allow load"
+ },
+ {
+ /* load image where meta1 allows but meta2 blocks */
+ query: "test7",
+ result: "img-blocked",
+ policyLen: 2,
+ desc: "meta1 (img-src http://mochi.test), meta2 (img-src 'none') should allow blocked"
+ },
+ {
+ /* load image where meta1 allows and meta2 allows */
+ query: "test8",
+ result: "img-loaded",
+ policyLen: 2,
+ desc: "meta1 (img-src http://mochi.test), meta2 (img-src http://mochi.test) should allow allowed"
+ },
+];
+
+var curTest;
+var counter = -1;
+
+function finishTest() {
+ window.removeEventListener("message", receiveMessage);
+ SimpleTest.finish();
+}
+
+function checkResults(result) {
+ // make sure the image got loaded or blocked
+ is(result, curTest.result, curTest.query + ": " + curTest.desc);
+
+ if (curTest.policyLen != 0) {
+ // make sure that meta policy got not parsed and appended twice
+ try {
+ // get the csp in JSON notation from the principal
+ var frame = document.getElementById("testframe");
+ var contentDoc = SpecialPowers.wrap(frame.contentDocument);
+ var cspOBJ = JSON.parse(contentDoc.cspJSON);
+ // make sure that the speculative policy and the actual policy
+ // are not appended twice.
+ var policies = cspOBJ["csp-policies"];
+ is(policies.length, curTest.policyLen, curTest.query + " should have: " + curTest.policyLen + " policies");
+ }
+ catch (e) {
+ ok(false, "uuh, something went wrong within cspToJSON in " + curTest.query);
+ }
+ }
+ // move on to the next test
+ runNextTest();
+}
+
+// a postMessage handler used to bubble up the
+// onsuccess/onerror state from within the iframe.
+window.addEventListener("message", receiveMessage);
+function receiveMessage(event) {
+ checkResults(event.data.result);
+}
+
+function runNextTest() {
+ if (++counter == TESTS.length) {
+ finishTest();
+ return;
+ }
+ curTest = TESTS[counter];
+ // load next test
+ document.getElementById("testframe").src = "file_meta_header_dual.sjs?" + curTest.query;
+}
+
+// start the test
+SimpleTest.waitForExplicitFinish();
+runNextTest();
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_meta_whitespace_skipping.html b/dom/security/test/csp/test_meta_whitespace_skipping.html
new file mode 100644
index 0000000000..2f622c3a33
--- /dev/null
+++ b/dom/security/test/csp/test_meta_whitespace_skipping.html
@@ -0,0 +1,81 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Bug 1261634 - Update whitespace skipping for meta csp</title>
+ <!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<iframe style="width:100%;" id="testframe" src="file_meta_whitespace_skipping.html"></iframe>
+
+<script class="testbody" type="text/javascript">
+
+/* Description of the test:
+ * We load a site using meta CSP into an iframe. We make sure that all directives
+ * are parsed correclty by the CSP parser even though the directives are separated
+ * not only by whitespace but also by line breaks
+ */
+
+SimpleTest.waitForExplicitFinish();
+const EXPECTED_DIRS = [
+ "img-src", "script-src", "style-src", "child-src", "font-src"];
+
+function finishTest() {
+ window.removeEventListener("message", receiveMessage);
+ SimpleTest.finish();
+}
+
+function checkResults(result) {
+ // sanity check that the site was loaded and the meta csp was parsed.
+ is(result, "meta-csp-parsed", "loading images should be blocked by meta csp");
+
+ try {
+ // get the csp in JSON notation from the principal
+ var frame = document.getElementById("testframe");
+ var contentDoc = SpecialPowers.wrap(frame.contentDocument);
+ var cspJSON = contentDoc.cspJSON;
+ ok(cspJSON, "CSP applied through meta element");
+
+ // parse the cspJSON in a csp-object
+ var cspOBJ = JSON.parse(cspJSON);
+ ok(cspOBJ, "was able to parse the JSON");
+
+ // make sure we only got one policy
+ var policies = cspOBJ["csp-policies"];
+ is(policies.length, 1, "there should be one policy applied");
+
+ // iterate the policy and make sure to only encounter
+ // expected directives.
+ var policy = policies[0];
+ for (var dir in policy) {
+ // special case handling for report-only which is not a directive
+ // but present in the JSON notation of the CSP.
+ if (dir === "report-only") {
+ continue;
+ }
+ var index = EXPECTED_DIRS.indexOf(dir);
+ isnot(index, -1, "meta csp contains directive: " + dir + "!");
+
+ // take the element out of the array so we can make sure
+ // that we have seen all the expected values in the end.
+ EXPECTED_DIRS.splice(index, 1);
+ }
+ is(EXPECTED_DIRS.length, 0, "have seen all the expected values");
+ }
+ catch (e) {
+ ok(false, "uuh, something went wrong within meta csp test");
+ }
+
+ finishTest();
+}
+
+window.addEventListener("message", receiveMessage);
+function receiveMessage(event) {
+ checkResults(event.data.result);
+}
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_multi_policy_injection_bypass.html b/dom/security/test/csp/test_multi_policy_injection_bypass.html
new file mode 100644
index 0000000000..cbb981405b
--- /dev/null
+++ b/dom/security/test/csp/test_multi_policy_injection_bypass.html
@@ -0,0 +1,119 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=717511
+-->
+<head>
+ <title>Test for Bug 717511</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+
+</div>
+
+<iframe style="width:200px;height:200px;" id='cspframe'></iframe>
+<iframe style="width:200px;height:200px;" id='cspframe2'></iframe>
+<script class="testbody" type="text/javascript">
+
+var path = "/tests/dom/security/test/csp/";
+
+// These are test results: -1 means it hasn't run,
+// true/false is the pass/fail result.
+// This is not exhaustive, just double-checking the 'self' vs * policy conflict in the two HTTP headers.
+window.tests = {
+ img_good: -1,
+ img_bad: -1,
+ script_good: -1,
+ script_bad: -1,
+ img2_good: -1,
+ img2_bad: -1,
+ script2_good: -1,
+ script2_bad: -1,
+};
+
+
+// This is used to watch the blocked data bounce off CSP and allowed data
+// get sent out to the wire.
+function examiner() {
+ SpecialPowers.addObserver(this, "csp-on-violate-policy");
+ SpecialPowers.addObserver(this, "specialpowers-http-notify-request");
+}
+examiner.prototype = {
+ observe(subject, topic, data) {
+ var testpat = new RegExp("testid=([a-z0-9_]+)");
+
+ //_good things better be allowed!
+ //_bad things better be stopped!
+
+ if (topic === "specialpowers-http-notify-request") {
+ //these things were allowed by CSP
+ var asciiSpec = data;
+ if (!testpat.test(asciiSpec)) return;
+ var testid = testpat.exec(asciiSpec)[1];
+ window.testResult(testid,
+ /_good/.test(testid),
+ asciiSpec + " allowed by csp");
+
+ }
+
+ if(topic === "csp-on-violate-policy") {
+ // subject should be an nsIURI for csp-on-violate-policy
+ if (!SpecialPowers.can_QI(subject)) {
+ return;
+ }
+
+ //these were blocked... record that they were blocked
+ var asciiSpec = SpecialPowers.getPrivilegedProps(
+ SpecialPowers.do_QueryInterface(subject, "nsIURI"),
+ "asciiSpec");
+ if (!testpat.test(asciiSpec)) return;
+ var testid = testpat.exec(asciiSpec)[1];
+ window.testResult(testid,
+ /_bad/.test(testid),
+ asciiSpec + " blocked by \"" + data + "\"");
+ }
+ },
+
+ // must eventually call this to remove the listener,
+ // or mochitests might get borked.
+ remove() {
+ SpecialPowers.removeObserver(this, "csp-on-violate-policy");
+ SpecialPowers.removeObserver(this, "specialpowers-http-notify-request");
+ }
+}
+
+window.examiner = new examiner();
+
+window.testResult = function(testname, result, msg) {
+
+ //test already complete.... forget it... remember the first result.
+ if (window.tests[testname] != -1)
+ return;
+
+ window.tests[testname] = result;
+ is(result, true, testname + ' test: ' + msg);
+
+ // if any test is incomplete, keep waiting
+ for (var v in window.tests)
+ if(tests[v] == -1)
+ return;
+
+ // ... otherwise, finish
+ window.examiner.remove();
+ SimpleTest.finish();
+}
+
+SimpleTest.waitForExplicitFinish();
+
+// save this for last so that our listeners are registered.
+// ... this loads the testbed of good and bad requests.
+document.getElementById('cspframe').src = 'file_multi_policy_injection_bypass.html';
+document.getElementById('cspframe2').src = 'file_multi_policy_injection_bypass_2.html';
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_multipartchannel.html b/dom/security/test/csp/test_multipartchannel.html
new file mode 100644
index 0000000000..2708611e6d
--- /dev/null
+++ b/dom/security/test/csp/test_multipartchannel.html
@@ -0,0 +1,68 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Bug 1416045/Bug 1223743 - CSP: Check baseChannel for CSP when loading multipart channel</title>
+ <!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<iframe style="width:100%;" id="testframe"></iframe>
+<iframe style="width:100%;" id="testPartCSPframe"></iframe>
+
+<script class="testbody" type="text/javascript">
+
+var testsToRunMultipartCSP = {
+ rootCSP_test: false,
+ part1CSP_test: false,
+ part2CSP_test: false,
+};
+
+SimpleTest.waitForExplicitFinish();
+
+function checkTestsCompleted() {
+ for (var prop in testsToRunMultipartCSP) {
+ // some test hasn't run yet so we're not done
+ if (!testsToRunMultipartCSP[prop]) {
+ return;
+ }
+ }
+ window.removeEventListener("message", receiveMessage);
+ SimpleTest.finish();
+}
+/* Description of the test:
+ * We apply a CSP to a multipart channel and then try to load an image
+ * within a segment making sure the image is blocked correctly by CSP.
+ * We also provide CSP for each part and try to load an image in each
+ * part and make sure the image is loaded in first part and blocked in
+ * second part correctly based on its CSP accordingly.
+ */
+
+window.addEventListener("message", receiveMessage);
+function receiveMessage(event) {
+ switch (event.data.test) {
+ case "rootCSP_test":
+ is(event.data.msg, "img-blocked", "image should be blocked");
+ testsToRunMultipartCSP.rootCSP_test = true;
+ break;
+ case "part1CSP_test":
+ is(event.data.msg, "part1-img-loaded", "Part1 image should be loaded");
+ testsToRunMultipartCSP.part1CSP_test = true;
+ break;
+ case "part2CSP_test":
+ is(event.data.msg, "part2-img-blocked", "Part2 image should be blocked");
+ testsToRunMultipartCSP.part2CSP_test = true;
+ break;
+ }
+ checkTestsCompleted();
+}
+
+// start the test
+document.getElementById("testframe").src = "file_multipart_testserver.sjs?doc";
+document.getElementById("testPartCSPframe").src =
+ "file_multipart_testserver.sjs?partcspdoc";
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_navigate_to.html b/dom/security/test/csp/test_navigate_to.html
new file mode 100644
index 0000000000..357b35bb05
--- /dev/null
+++ b/dom/security/test/csp/test_navigate_to.html
@@ -0,0 +1,158 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 1529068 Implement CSP 'navigate-to' directive</title>
+ <!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+ <p id="display"></p>
+ <div id="content">
+ <iframe style="width:100%;" id="testframe"></iframe>
+ </div>
+
+<script class="testbody" type="text/javascript">
+
+/*
+ * Description of the test:
+ * We load a page with a given CSP and verify that navigations are correctly
+ * evaluated through the "navigate-to" directive.
+ */
+SpecialPowers.pushPrefEnv({"set": [["security.csp.enableNavigateTo", true]]});
+SimpleTest.waitForExplicitFinish();
+
+// Note: The final website for the navigation chain must always be: www.example.com
+var tests = [
+ {
+ result : "blocked",
+ policy : "navigate-to www.mozilla.com",
+ target : "http://www.example.com/"
+ },
+ {
+ result : "allowed",
+ policy : "navigate-to www.example.com",
+ target : "http://www.example.com/"
+ },
+ {
+ // Test path-sensitivity
+ result : "blocked",
+ policy : "navigate-to http://www.example.com/full/path/to/file",
+ target : "http://www.example.com/"
+ },
+ {
+ // Test scheme
+ result : "blocked",
+ policy : "navigate-to https://www.example.com/",
+ target : "http://www.example.com/"
+ },
+ {
+ // Redirect from tracking.example.com to www.example.com
+ result : "blocked",
+ policy : "navigate-to www.example.com",
+ target : "http://tracking.example.com/tests/dom/security/test/csp/file_navigate_to.sjs?redir=http://www.example.com/"
+ },
+ {
+ // Redirect from tracking.example.com to www.example.com (Explicitly allowed)
+ result : "allowed",
+ policy : "navigate-to tracking.example.com www.example.com",
+ target : "http://tracking.example.com/tests/dom/security/test/csp/file_navigate_to.sjs?redir=http://www.example.com/"
+ },
+ {
+ // Redirect from tracking.example.com to www.example.com ('unsafe-allow-redirects')
+ result : "allowed",
+ policy : "navigate-to 'unsafe-allow-redirects' www.example.com",
+ target : "http://tracking.example.com/tests/dom/security/test/csp/file_navigate_to.sjs?redir=http://www.example.com/"
+ },
+ // No path-sensitivity after redirect
+ {
+ result : "allowed",
+ policy : "navigate-to tracking.example.com http://www.example.com/full/path/to/file",
+ target : "http://tracking.example.com/tests/dom/security/test/csp/file_navigate_to.sjs?redir=http://www.example.com/"
+ },
+ // Multiple CSP directives, first block (origin) second allow
+ {
+ result : "allowed",
+ policy : "img-src 'none'; navigate-to www.example.com",
+ target : "http://www.example.com/"
+ },
+ // Multiple CSP directives, first allow (origin) second block
+ {
+ result : "blocked",
+ policy : "img-src www.example.com mochi.test:8888; navigate-to www.mozilla.com",
+ target : "http://www.example.com/"
+ },
+ // Multiple CSPs, first allow second block
+ {
+ result : "blocked",
+ policy : "navigate-to www.example.com",
+ policy2 : "navigate-to www.mozilla.com",
+ target : "http://www.example.com/"
+ },
+ // Multiple CSPs, first block second allow
+ {
+ result : "blocked",
+ policy : "navigate-to www.mozilla.com",
+ policy2 : "navigate-to www.example.com",
+ target : "http://www.example.com/"
+ },
+];
+
+// initializing to -1 so we start at index 0 when we start the test
+var counter = -1;
+
+function checkResult(aResult) {
+ is(aResult, tests[counter].result, "should be " + tests[counter].result + " in test " + counter +
+ "(" + tests[counter].policy + ", " + tests[counter].target + ")!");
+ loadNextTest();
+}
+
+// We use the examiner to identify requests that hit the wire and requests
+// that are blocked by CSP and bubble up the result to the including iframe
+// document (parent).
+function examiner() {
+ SpecialPowers.addObserver(this, "csp-on-violate-policy");
+}
+examiner.prototype = {
+ observe(subject, topic, data) {
+ if (topic === "csp-on-violate-policy" && data === "navigate-to") {
+ checkResult("blocked");
+ }
+
+ },
+ remove() {
+ SpecialPowers.removeObserver(this, "csp-on-violate-policy");
+ }
+}
+window.NavigationActionExaminer = new examiner();
+// We use iframe onload to check if requests are not blocked by CSP
+var iframe = document.getElementById("testframe");
+iframe.onload = function() {
+ checkResult("allowed");
+}
+
+function loadNextTest() {
+ counter++;
+ if (counter == tests.length) {
+ window.NavigationActionExaminer.remove();
+ SimpleTest.finish();
+ return;
+ }
+
+ var src = "file_navigate_to.sjs";
+ // append the CSP that should be used to serve the file
+ src += "?csp=" + escape(tests[counter].policy);
+ if( tests[counter].policy2 ) {
+ src += "&csp2=" + escape(tests[counter].policy2);
+ }
+ src += "&target=" + escape(tests[counter].target);
+
+ iframe.src = src;
+}
+
+// start running the tests
+loadNextTest();
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_nonce_redirects.html b/dom/security/test/csp/test_nonce_redirects.html
new file mode 100644
index 0000000000..9b9e5e347d
--- /dev/null
+++ b/dom/security/test/csp/test_nonce_redirects.html
@@ -0,0 +1,47 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Bug 1469150:Scripts with valid nonce get blocked if URL redirects</title>
+ <!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<iframe style="width:100%;" id="testframe"></iframe>
+
+<script class="testbody" type="text/javascript">
+
+/* Description of the test:
+ * We load a script with a matching nonce, which redirects
+ * and we make sure that script is allowed.
+ */
+
+SimpleTest.waitForExplicitFinish();
+
+function finishTest() {
+ window.removeEventListener("message", receiveMessage);
+ SimpleTest.finish();
+}
+
+function checkResults(aResult) {
+
+ if (aResult === "script-loaded") {
+ ok(true, "expected result: script loaded");
+ }
+ else {
+ ok(false, "unexpected result: script blocked");
+ }
+ finishTest();
+}
+
+window.addEventListener("message", receiveMessage);
+function receiveMessage(event) {
+ checkResults(event.data.result);
+}
+
+document.getElementById("testframe").src = "file_nonce_redirects.html";
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_nonce_snapshot.html b/dom/security/test/csp/test_nonce_snapshot.html
new file mode 100644
index 0000000000..6670d6868f
--- /dev/null
+++ b/dom/security/test/csp/test_nonce_snapshot.html
@@ -0,0 +1,35 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Bug 1509738 - Snapshot nonce at load start time</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<iframe style="width:100%;" id="testframe"></iframe>
+
+<script class="testbody" type="text/javascript">
+
+/* Description of the test:
+ * a) the test starts loading a script using allowlisted nonce
+ * b) the nonce of the script gets modified
+ * c) the script hits a 302 server side redirect
+ * d) we ensure the script still loads and does not use the modified nonce
+ */
+
+window.addEventListener("message", receiveMessage);
+function receiveMessage(event) {
+ is(event.data, "script-loaded", "script loaded even though nonce was dynamically modified");
+ window.removeEventListener("message", receiveMessage);
+ SimpleTest.finish();
+}
+
+
+SimpleTest.waitForExplicitFinish();
+let src = "file_nonce_snapshot.sjs?load-frame";
+document.getElementById("testframe").src = src;
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_nonce_source.html b/dom/security/test/csp/test_nonce_source.html
new file mode 100644
index 0000000000..e11452c6e1
--- /dev/null
+++ b/dom/security/test/csp/test_nonce_source.html
@@ -0,0 +1,122 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test CSP 1.1 nonce-source for scripts and styles</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="visibility:hidden">
+ <iframe style="width:100%;" id='cspframe'></iframe>
+</div>
+<script class="testbody" type="text/javascript">
+
+var testsRun = 0;
+var totalTests = 20;
+
+// This is used to watch the blocked data bounce off CSP
+function examiner() {
+ SpecialPowers.addObserver(this, "specialpowers-http-notify-request");
+ SpecialPowers.addObserver(this, "csp-on-violate-policy");
+}
+
+examiner.prototype = {
+ observe(subject, topic, data) {
+ var testid_re = new RegExp("testid=([a-z0-9_]+)");
+
+ //_good things better be allowed!
+ //_bad things better be blocked!
+
+ if (topic === "specialpowers-http-notify-request") {
+ var uri = data;
+ if (!testid_re.test(uri)) return;
+ var testid = testid_re.exec(uri)[1];
+ ok(/_good/.test(testid), "should allow URI with good testid " + testid);
+ ranTests(1);
+ }
+
+ if (topic === "csp-on-violate-policy") {
+ try {
+ // if it is an blocked external load, subject will be the URI of the resource
+ var blocked_uri = SpecialPowers.getPrivilegedProps(SpecialPowers.do_QueryInterface(subject, "nsIURI"), "asciiSpec");
+ if (!testid_re.test(blocked_uri)) return;
+ var testid = testid_re.exec(blocked_uri)[1];
+ ok(/_bad/.test(testid), "should block URI with bad testid " + testid);
+ ranTests(1);
+ } catch (e) {
+ // if the subject is blocked inline, data will be a violation message
+ // we can't distinguish which resources triggered these, so we ignore them
+ }
+ }
+ },
+ // must eventually call this to remove the listener, or mochitests might get borked.
+ remove() {
+ SpecialPowers.removeObserver(this, "specialpowers-http-notify-request");
+ SpecialPowers.removeObserver(this, "csp-on-violate-policy");
+ }
+}
+
+function cleanup() {
+ // remove the observer so we don't bork other tests
+ window.examiner.remove();
+ // finish the tests
+ SimpleTest.finish();
+}
+
+function ranTests(num) {
+ testsRun += num;
+ if (testsRun < totalTests) {
+ return;
+ }
+ cleanup();
+}
+
+function checkInlineScriptsAndStyles () {
+ var cspframe = document.getElementById('cspframe');
+ var getElementColorById = function (id) {
+ return window.getComputedStyle(cspframe.contentDocument.getElementById(id)).color;
+ };
+ // Inline style tries to change an element's color to green. If blocked, the
+ // element's color will be the (unchanged) default black.
+ var green = "rgb(0, 128, 0)";
+ var red = "rgb(255,0,0)";
+ var black = "rgb(0, 0, 0)";
+
+ // inline script tests
+ is(getElementColorById('inline-script-correct-nonce'), green,
+ "Inline script with correct nonce should execute");
+ is(getElementColorById('inline-script-incorrect-nonce'), black,
+ "Inline script with incorrect nonce should not execute");
+ is(getElementColorById('inline-script-correct-style-nonce'), black,
+ "Inline script with correct nonce for styles (but not for scripts) should not execute");
+ is(getElementColorById('inline-script-no-nonce'), black,
+ "Inline script with no nonce should not execute");
+
+ // inline style tests
+ is(getElementColorById('inline-style-correct-nonce'), green,
+ "Inline style with correct nonce should be allowed");
+ is(getElementColorById('inline-style-incorrect-nonce'), black,
+ "Inline style with incorrect nonce should be blocked");
+ is(getElementColorById('inline-style-correct-script-nonce'), black,
+ "Inline style with correct nonce for scripts (but incorrect nonce for styles) should be blocked");
+ is(getElementColorById('inline-style-no-nonce'), black,
+ "Inline style with no nonce should be blocked");
+
+ ranTests(8);
+}
+
+//////////////////////////////////////////////////////////////////////
+// set up and go
+window.examiner = new examiner();
+SimpleTest.waitForExplicitFinish();
+
+// save this for last so that our listeners are registered.
+// ... this loads the testbed of good and bad requests.
+document.getElementById('cspframe').src = 'file_nonce_source.html';
+document.getElementById('cspframe').addEventListener('load', checkInlineScriptsAndStyles);
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_null_baseuri.html b/dom/security/test/csp/test_null_baseuri.html
new file mode 100644
index 0000000000..324b644f83
--- /dev/null
+++ b/dom/security/test/csp/test_null_baseuri.html
@@ -0,0 +1,67 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 1121857 - document.baseURI should not get blocked if baseURI is null</title>
+ <!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+ <p id="display"></p>
+ <div id="content" style="visibility: hidden">
+ <iframe style="width:100%;" id="testframe"></iframe>
+ </div>
+
+<script class="testbody" type="text/javascript">
+
+/* Description of the test:
+ * Creating a 'base' element and appending that element
+ * to document.head. After setting baseTag.href and finally
+ * removing the created element from the head, the baseURI
+ * should be the inital baseURI of the page.
+ */
+
+const TOTAL_TESTS = 3;
+var test_counter = 0;
+
+// a postMessage handler to communicate the results back to the parent.
+window.addEventListener("message", receiveMessage);
+
+function receiveMessage(event)
+{
+ // make sure the base-uri before and after the test is the initial base uri of the page
+ if (event.data.test === "initial_base_uri") {
+ ok(event.data.baseURI.startsWith("http://mochi.test"), "baseURI should be 'http://mochi.test'!");
+ }
+ // check that appending the child and setting the base tag actually affects the base-uri
+ else if (event.data.test === "changed_base_uri") {
+ ok(event.data.baseURI === "http://www.base-tag.com/", "baseURI should be 'http://www.base-tag.com'!");
+ }
+ // we shouldn't get here, but just in case, throw an error.
+ else {
+ ok(false, "unrecognized test!");
+ }
+
+ if (++test_counter === TOTAL_TESTS) {
+ SimpleTest.finish();
+ }
+}
+
+function startTest() {
+ var src = "file_testserver.sjs";
+ // append the file that should be served
+ src += "?file=" + escape("tests/dom/security/test/csp/file_null_baseuri.html");
+ // using 'unsafe-inline' since we load the testcase using an inline script
+ // within file_null_baseuri.html
+ src += "&csp=" + escape("default-src * 'unsafe-inline';");
+
+ document.getElementById("testframe").src = src;
+}
+
+
+SimpleTest.waitForExplicitFinish();
+startTest();
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_object_inherit.html b/dom/security/test/csp/test_object_inherit.html
new file mode 100644
index 0000000000..0d563bde3f
--- /dev/null
+++ b/dom/security/test/csp/test_object_inherit.html
@@ -0,0 +1,30 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 1457100: Test OBJECT inherits CSP if needed</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<iframe style="width:100%;" id="testframe"></iframe>
+
+<script class="testbody" type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+
+window.addEventListener("message", receiveMessage);
+function receiveMessage(event) {
+ window.removeEventListener("message", receiveMessage);
+
+ var cspJSON = event.data.cspJSON;
+ ok(cspJSON.includes("img-src"), "found img-src directive");
+ ok(cspJSON.includes("https://bug1457100.test.com"), "found img-src value");
+
+ SimpleTest.finish();
+}
+
+document.getElementById("testframe").src = "file_object_inherit.html";
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_parent_location_js.html b/dom/security/test/csp/test_parent_location_js.html
new file mode 100644
index 0000000000..d456c809f2
--- /dev/null
+++ b/dom/security/test/csp/test_parent_location_js.html
@@ -0,0 +1,38 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 1550414: Add CSP test for setting parent location to javascript:</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<iframe style="width:100%;" id="testframe"></iframe>
+
+<script class="testbody" type="text/javascript">
+
+/**
+ * Description of the test:
+ * Load a document with a CSP of essentially script-src 'none' which includes a
+ * same origin iframe which tries to modify the parent.location using a javascript:
+ * URI -> make sure the javascript: URI is blocked correctly!
+ */
+
+SimpleTest.waitForExplicitFinish();
+
+function receiveMessage(event) {
+ window.removeEventListener("message", receiveMessage);
+ is(event.data.blockedURI, "inline", "blockedURI");
+ is(event.data.violatedDirective, "script-src-elem", "violatedDirective")
+ is(event.data.originalPolicy, "script-src 'nonce-bug1550414'", "originalPolicy");
+ SimpleTest.finish();
+}
+
+// using a postMessage handler to report the result back from
+// within the sandboxed iframe without 'allow-same-origin'.
+window.addEventListener("message", receiveMessage);
+
+document.getElementById("testframe").src = "file_parent_location_js.html";
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_path_matching.html b/dom/security/test/csp/test_path_matching.html
new file mode 100644
index 0000000000..a54de0a25c
--- /dev/null
+++ b/dom/security/test/csp/test_path_matching.html
@@ -0,0 +1,115 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 808292 - Implement path-level host-source matching to CSP</title>
+ <!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+ <p id="display"></p>
+ <div id="content" style="visibility: hidden">
+ <iframe style="width:100%;" id="testframe"></iframe>
+ </div>
+
+<script class="testbody" type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+
+/* Description of the test:
+ * We are loading the following url (including a fragment portion):
+ * http://test1.example.com/tests/dom/security/test/csp/file_path_matching.js#foo
+ * using different policies and verify that the applied policy is accurately enforced.
+ */
+
+var policies = [
+ ["allowed", "*"],
+ ["allowed", "http://*"], // test for bug 1075230, enforcing scheme and wildcard
+ ["allowed", "test1.example.com"],
+ ["allowed", "test1.example.com/"],
+ ["allowed", "test1.example.com/tests/dom/security/test/csp/"],
+ ["allowed", "test1.example.com/tests/dom/security/test/csp/file_path_matching.js"],
+
+ ["allowed", "test1.example.com?foo=val"],
+ ["allowed", "test1.example.com/?foo=val"],
+ ["allowed", "test1.example.com/tests/dom/security/test/csp/?foo=val"],
+ ["allowed", "test1.example.com/tests/dom/security/test/csp/file_path_matching.js?foo=val"],
+
+ ["allowed", "test1.example.com#foo"],
+ ["allowed", "test1.example.com/#foo"],
+ ["allowed", "test1.example.com/tests/dom/security/test/csp/#foo"],
+ ["allowed", "test1.example.com/tests/dom/security/test/csp/file_path_matching.js#foo"],
+
+ ["allowed", "*.example.com"],
+ ["allowed", "*.example.com/"],
+ ["allowed", "*.example.com/tests/dom/security/test/csp/"],
+ ["allowed", "*.example.com/tests/dom/security/test/csp/file_path_matching.js"],
+
+ ["allowed", "test1.example.com:80"],
+ ["allowed", "test1.example.com:80/"],
+ ["allowed", "test1.example.com:80/tests/dom/security/test/csp/"],
+ ["allowed", "test1.example.com:80/tests/dom/security/test/csp/file_path_matching.js"],
+
+ ["allowed", "test1.example.com:*"],
+ ["allowed", "test1.example.com:*/"],
+ ["allowed", "test1.example.com:*/tests/dom/security/test/csp/"],
+ ["allowed", "test1.example.com:*/tests/dom/security/test/csp/file_path_matching.js"],
+
+ ["blocked", "test1.example.com/tests"],
+ ["blocked", "test1.example.com/tests/dom/security/test/csp"],
+ ["blocked", "test1.example.com/tests/dom/security/test/csp/file_path_matching.py"],
+
+ ["blocked", "test1.example.com:8888/tests"],
+ ["blocked", "test1.example.com:8888/tests/dom/security/test/csp"],
+ ["blocked", "test1.example.com:8888/tests/dom/security/test/csp/file_path_matching.py"],
+
+ // case insensitive matching for scheme and host, but case sensitive matching for paths
+ ["allowed", "HTTP://test1.EXAMPLE.com/tests/"],
+ ["allowed", "test1.EXAMPLE.com/tests/"],
+ ["blocked", "test1.example.com/tests/dom/security/test/CSP/?foo=val"],
+ ["blocked", "test1.example.com/tests/dom/security/test/csp/FILE_path_matching.js?foo=val"],
+]
+
+var counter = 0;
+var policy;
+
+function loadNextTest() {
+ if (counter == policies.length) {
+ SimpleTest.finish();
+ }
+ else {
+ policy = policies[counter++];
+ var src = "file_testserver.sjs?file=";
+ // append the file that should be served
+ src += (counter % 2 == 0)
+ // load url including ref: example.com#foo
+ ? escape("tests/dom/security/test/csp/file_path_matching.html")
+ // load url including query: example.com?val=foo (bug 1147026)
+ : escape("tests/dom/security/test/csp/file_path_matching_incl_query.html");
+
+ // append the CSP that should be used to serve the file
+ src += "&csp=" + escape("default-src 'none'; script-src " + policy[1]);
+
+ document.getElementById("testframe").addEventListener("load", test);
+ document.getElementById("testframe").src = src;
+ }
+}
+
+function test() {
+ try {
+ document.getElementById("testframe").removeEventListener('load', test);
+ var testframe = document.getElementById("testframe");
+ var divcontent = testframe.contentWindow.document.getElementById('testdiv').innerHTML;
+ is(divcontent, policy[0], "should be " + policy[0] + " in test " + (counter - 1) + "!");
+ }
+ catch (e) {
+ ok(false, "ERROR: could not access content in test " + (counter - 1) + "!");
+ }
+ loadNextTest();
+}
+
+loadNextTest();
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_path_matching_redirect.html b/dom/security/test/csp/test_path_matching_redirect.html
new file mode 100644
index 0000000000..d3b2771d0a
--- /dev/null
+++ b/dom/security/test/csp/test_path_matching_redirect.html
@@ -0,0 +1,89 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 808292 - Implement path-level host-source matching to CSP (redirects)</title>
+ <!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+ <p id="display"></p>
+ <div id="content" style="visibility: hidden">
+ <iframe style="width:100%;" id="testframe"></iframe>
+ </div>
+
+<script class="testbody" type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+
+/* Description of the test:
+ * First, we try to load a script where the *path* does not match.
+ * Second, we try to load a script which is allowed by the CSPs
+ * script-src directive. The script then gets redirected to
+ * an URL where the host matches, but the path wouldn't.
+ * Since 'paths' should not be taken into account after redirects,
+ * that load should succeed. We are using a similar test setup
+ * as described in the spec, see:
+ * http://www.w3.org/TR/CSP11/#source-list-paths-and-redirects
+ */
+
+var policy = "script-src http://example.com http://test1.example.com/CSPAllowsScriptsInThatFolder";
+
+var tests = [
+ {
+ // the script in file_path_matching.html
+ // <script src="http://test1.example.com/tests/dom/security/..">
+ // is not within the allowlisted path by the csp-policy
+ // hence the script is 'blocked' by CSP.
+ expected: "blocked",
+ uri: "tests/dom/security/test/csp/file_path_matching.html"
+ },
+ {
+ // the script in file_path_matching_redirect.html
+ // <script src="http://example.com/tests/dom/..">
+ // gets redirected to: http://test1.example.com/tests/dom
+ // where after the redirect the path of the policy is not enforced
+ // anymore and hence execution of the script is 'allowed'.
+ expected: "allowed",
+ uri: "tests/dom/security/test/csp/file_path_matching_redirect.html"
+ },
+];
+
+var counter = 0;
+var curTest;
+
+function checkResult() {
+ try {
+ document.getElementById("testframe").removeEventListener('load', checkResult);
+ var testframe = document.getElementById("testframe");
+ var divcontent = testframe.contentWindow.document.getElementById('testdiv').innerHTML;
+ is(divcontent, curTest.expected, "should be blocked in test " + (counter - 1) + "!");
+ }
+ catch (e) {
+ ok(false, "ERROR: could not access content in test " + (counter - 1) + "!");
+ }
+ loadNextTest();
+}
+
+function loadNextTest() {
+ if (counter == tests.length) {
+ SimpleTest.finish();
+ }
+ else {
+ curTest = tests[counter++];
+ var src = "file_testserver.sjs";
+ // append the file that should be served
+ src += "?file=" + escape(curTest.uri);
+ // append the CSP that should be used to serve the file
+ src += "&csp=" + escape(policy);
+
+ document.getElementById("testframe").addEventListener("load", checkResult);
+ document.getElementById("testframe").src = src;
+ }
+}
+
+loadNextTest();
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_ping.html b/dom/security/test/csp/test_ping.html
new file mode 100644
index 0000000000..3f911b7b6a
--- /dev/null
+++ b/dom/security/test/csp/test_ping.html
@@ -0,0 +1,103 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 1100181 - CSP: Enforce connect-src when submitting pings</title>
+ <!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<iframe style="width:100%;" id="testframe"></iframe>
+
+<script class="testbody" type="text/javascript">
+
+/*
+ * Description of the test:
+ * We load a page with a given CSP and verify that hyperlink auditing
+ * is correctly evaluated through the "connect-src" directive.
+ */
+
+// Need to pref hyperlink auditing on since it's disabled by default.
+SpecialPowers.setBoolPref("browser.send_pings", true);
+
+SimpleTest.waitForExplicitFinish();
+
+var tests = [
+ {
+ result : "allowed",
+ policy : "connect-src 'self'"
+ },
+ {
+ result : "blocked",
+ policy : "connect-src 'none'"
+ }
+];
+
+// initializing to -1 so we start at index 0 when we start the test
+var counter = -1;
+
+function checkResult(aResult) {
+ is(aResult, tests[counter].result, "should be " + tests[counter].result + " in test " + counter + "!");
+ loadNextTest();
+}
+
+// We use the examiner to identify requests that hit the wire and requests
+// that are blocked by CSP and bubble up the result to the including iframe
+// document (parent).
+function examiner() {
+ SpecialPowers.addObserver(this, "csp-on-violate-policy");
+ SpecialPowers.addObserver(this, "specialpowers-http-notify-request");
+}
+examiner.prototype = {
+ observe(subject, topic, data) {
+ if (topic === "specialpowers-http-notify-request") {
+ // making sure we do not bubble a result for something
+ // other then the request in question.
+ if (!data.includes("send-ping")) {
+ return;
+ }
+ checkResult("allowed");
+ return;
+ }
+
+ if (topic === "csp-on-violate-policy") {
+ // making sure we do not bubble a result for something
+ // other then the request in question.
+ var asciiSpec = SpecialPowers.getPrivilegedProps(
+ SpecialPowers.do_QueryInterface(subject, "nsIURI"), "asciiSpec");
+ if (!asciiSpec.includes("send-ping")) {
+ return;
+ }
+ checkResult("blocked");
+ }
+ },
+ remove() {
+ SpecialPowers.removeObserver(this, "csp-on-violate-policy");
+ SpecialPowers.removeObserver(this, "specialpowers-http-notify-request");
+ }
+}
+window.ConnectSrcExaminer = new examiner();
+
+function loadNextTest() {
+ counter++;
+ if (counter == tests.length) {
+ window.ConnectSrcExaminer.remove();
+ SimpleTest.finish();
+ return;
+ }
+
+ var src = "file_testserver.sjs";
+ // append the file that should be served
+ src += "?file=" + escape("tests/dom/security/test/csp/file_ping.html");
+ // append the CSP that should be used to serve the file
+ src += "&csp=" + escape(tests[counter].policy);
+
+ document.getElementById("testframe").src = src;
+}
+
+// start running the tests
+loadNextTest();
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_policyuri_regression_from_multipolicy.html b/dom/security/test/csp/test_policyuri_regression_from_multipolicy.html
new file mode 100644
index 0000000000..8838f2fc45
--- /dev/null
+++ b/dom/security/test/csp/test_policyuri_regression_from_multipolicy.html
@@ -0,0 +1,27 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for Bug 924708</title>
+ <!--
+ test that a report-only policy that uses policy-uri is not incorrectly
+ enforced due to regressions introduced by Bug 836922.
+ -->
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<iframe style="width:200px;height:200px;" id='testframe'></iframe>
+<script class="testbody" type="text/javascript">
+SimpleTest.waitForExplicitFinish();
+
+var testframe = document.getElementById('testframe');
+testframe.src = 'file_policyuri_regression_from_multipolicy.html';
+testframe.addEventListener('load', function checkInlineScriptExecuted () {
+ is(this.contentDocument.getElementById('testdiv').innerHTML,
+ 'Inline Script Executed',
+ 'Inline script should execute (it would be blocked by the policy, but the policy is report-only)');
+ SimpleTest.finish();
+});
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_punycode_host_src.html b/dom/security/test/csp/test_punycode_host_src.html
new file mode 100644
index 0000000000..3735275d34
--- /dev/null
+++ b/dom/security/test/csp/test_punycode_host_src.html
@@ -0,0 +1,81 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Bug 1224225 - CSP source matching should work for punycoded domain names</title>
+ <!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<iframe style="width:100%;" id="testframe"></iframe>
+
+<script class="testbody" type="text/javascript">
+
+/* Description of the test:
+ * We load scripts within an iframe and make sure that the
+ * CSP matching is same for punycode domain names as well as IDNA.
+ */
+
+SimpleTest.waitForExplicitFinish();
+
+
+var curTest;
+var counter = -1;
+
+const tests = [
+ { // test 1
+ description: "loads script as sub2.ält.example.org, but allowlist in CSP as sub2.xn--lt-uia.example.org",
+ action: "script-unicode-csp-punycode",
+ csp: "script-src http://sub2.xn--lt-uia.example.org;",
+ expected: "script-allowed",
+
+ },
+ { // test 2
+ description: "loads script as sub2.xn--lt-uia.example.org, and allowlist in CSP as sub2.xn--lt-uia.example.org",
+ action: "script-punycode-csp-punycode",
+ csp: "script-src http://sub2.xn--lt-uia.example.org;",
+ expected: "script-allowed",
+
+ },
+ { // test 3
+ description: "loads script as sub2.xn--lt-uia.example.org, and allowlist in CSP as sub2.xn--lt-uia.example.org",
+ action: "script-punycode-csp-punycode",
+ csp: "script-src *.xn--lt-uia.example.org;",
+ expected: "script-allowed",
+
+ },
+
+];
+
+function finishTest() {
+ window.removeEventListener("message", receiveMessage);
+ SimpleTest.finish();
+}
+
+function checkResults(result) {
+ is(result, curTest.expected, curTest.description);
+ loadNextTest();
+}
+
+window.addEventListener("message", receiveMessage);
+function receiveMessage(event) {
+ checkResults(event.data.result);
+}
+
+function loadNextTest() {
+ counter++;
+ if (counter == tests.length) {
+ finishTest();
+ return;
+ }
+ curTest = tests[counter];
+ var testframe = document.getElementById("testframe");
+ testframe.src = `file_punycode_host_src.sjs?action=${curTest.action}&csp=${curTest.csp}`;
+}
+
+loadNextTest();
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_redirects.html b/dom/security/test/csp/test_redirects.html
new file mode 100644
index 0000000000..9cc569ed72
--- /dev/null
+++ b/dom/security/test/csp/test_redirects.html
@@ -0,0 +1,143 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Tests for Content Security Policy during redirects</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+
+<iframe style="width:100%;height:300px;" id="harness"></iframe>
+<pre id="log"></pre>
+<script class="testbody" type="text/javascript">
+
+var path = "/tests/dom/security/test/csp/";
+
+// debugging
+function log(s) {
+ return;
+ dump("**" + s + "\n");
+ var log = document.getElementById("log");
+ log.textContent = log.textContent+s+"\n";
+}
+
+SpecialPowers.registerObservers("csp-on-violate-policy");
+
+// used to watch if requests are blocked by CSP or allowed through
+function examiner() {
+ SpecialPowers.addObserver(this, "csp-on-violate-policy");
+ SpecialPowers.addObserver(this, "specialpowers-csp-on-violate-policy");
+ SpecialPowers.addObserver(this, "specialpowers-http-notify-request");
+}
+examiner.prototype = {
+ observe(subject, topic, data) {
+ var testpat = new RegExp("testid=([a-z0-9-]+)");
+ var asciiSpec;
+ var testid;
+
+ if (topic === "specialpowers-http-notify-request") {
+ // request was sent
+ var allowedUri = data;
+ if (!testpat.test(allowedUri)) return;
+ testid = testpat.exec(allowedUri)[1];
+ if (testExpectedResults[testid] == "completed") return;
+ log("allowed: "+allowedUri);
+ window.testResult(testid, allowedUri, true);
+ }
+
+ else if (topic === "csp-on-violate-policy" || topic === "specialpowers-csp-on-violate-policy") {
+ // request was blocked
+ asciiSpec = SpecialPowers.getPrivilegedProps(SpecialPowers.do_QueryInterface(subject, "nsIURI"), "asciiSpec");
+ if (!testpat.test(asciiSpec)) return;
+ testid = testpat.exec(asciiSpec)[1];
+ // had to add this check because http-on-modify-request can fire after
+ // csp-on-violate-policy, apparently, even though the request does
+ // not hit the wire.
+ if (testExpectedResults[testid] == "completed") return;
+ log("BLOCKED: "+asciiSpec);
+ window.testResult(testid, asciiSpec, false);
+ }
+ },
+
+ remove() {
+ SpecialPowers.removeObserver(this, "csp-on-violate-policy");
+ SpecialPowers.removeObserver(this, "specialpowers-csp-on-violate-policy");
+ SpecialPowers.removeObserver(this, "specialpowers-http-notify-request");
+ }
+}
+window.examiner = new examiner();
+
+// contains { test_frame_id : expected_result }
+var testExpectedResults = { "font-src": true,
+ "font-src-redir": false,
+ "frame-src": true,
+ "frame-src-redir": false,
+ "img-src": true,
+ "img-src-redir": false,
+ "media-src": true,
+ "media-src-redir": false,
+ "object-src": true,
+ "object-src-redir": false,
+ "script-src": true,
+ "script-src-redir": false,
+ "style-src": true,
+ "style-src-redir": false,
+ "xhr-src": true,
+ "xhr-src-redir": false,
+ "from-worker": true,
+ "script-src-redir-from-worker": true, // redir is allowed since policy isn't inherited
+ "xhr-src-redir-from-worker": true, // redir is allowed since policy isn't inherited
+ "fetch-src-redir-from-worker": true, // redir is allowed since policy isn't inherited
+ "from-blob-worker": true,
+ "script-src-redir-from-blob-worker": false,
+ "xhr-src-redir-from-blob-worker": false,
+ "fetch-src-redir-from-blob-worker": false,
+ "img-src-from-css": true,
+ "img-src-redir-from-css": false,
+ };
+
+// takes the name of the test, the URL that was tested, and whether the
+// load occurred
+var testResult = function(testName, url, result) {
+ log(" testName: "+testName+", result: "+result+", expected: "+testExpectedResults[testName]+"\n");
+ is(result, testExpectedResults[testName], testName+" test: "+url);
+
+ // mark test as completed
+ testExpectedResults[testName] = "completed";
+
+ // don't finish until we've run all the tests
+ for (var t in testExpectedResults) {
+ if (testExpectedResults[t] != "completed") {
+ return;
+ }
+ }
+
+ window.examiner.remove();
+ SimpleTest.finish();
+}
+
+SimpleTest.waitForExplicitFinish();
+
+SpecialPowers.pushPrefEnv(
+ {'set':[// On a cellular connection the default preload value is 0 ("preload
+ // none"). Our Android emulators emulate a cellular connection, and
+ // so by default preload no media data. This causes the media_* tests
+ // to timeout. We set the default used by cellular connections to the
+ // same as used by non-cellular connections in order to get
+ // consistent behavior across platforms/devices.
+ ["media.preload.default", 2],
+ ["media.preload.default.cellular", 2]]},
+ function() {
+ // save this for last so that our listeners are registered.
+ // ... this loads the testbed of good and bad requests.
+ document.getElementById("harness").src = "file_redirects_main.html";
+ });
+</script>
+</pre>
+
+</body>
+</html>
diff --git a/dom/security/test/csp/test_report.html b/dom/security/test/csp/test_report.html
new file mode 100644
index 0000000000..fc10cd0341
--- /dev/null
+++ b/dom/security/test/csp/test_report.html
@@ -0,0 +1,113 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=548193
+-->
+<head>
+ <title>Test for Bug 548193</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+
+<iframe style="width:200px;height:200px;" id='cspframe'></iframe>
+<script class="testbody" type="text/javascript">
+
+/*
+ * Description of the test:
+ * We try to load an inline-src using a policy that constrains
+ * all scripts from running (default-src 'none'). We verify that
+ * the generated csp-report contains the expceted values. If any
+ * of the JSON is not formatted properly (e.g. not properly escaped)
+ * then JSON.parse will fail, which allows to pinpoint such errors
+ * in the catch block, and the test will fail. Since we use an
+ * observer, we can set the actual report-uri to a foo value.
+ */
+
+const testfile = "tests/dom/security/test/csp/file_report.html";
+const reportURI = "http://mochi.test:8888/foo.sjs";
+const policy = "default-src 'none' 'report-sample'; report-uri " + reportURI;
+const docUri = "http://mochi.test:8888/tests/dom/security/test/csp/file_testserver.sjs" +
+ "?file=tests/dom/security/test/csp/file_report.html" +
+ "&csp=default-src%20%27none%27%20%27report-sample%27%3B%20report-uri%20http%3A//mochi.test%3A8888/foo.sjs";
+
+window.checkResults = function(reportObj) {
+ var cspReport = reportObj["csp-report"];
+
+ // The following uris' fragments should be stripped before reporting:
+ // * document-uri
+ // * blocked-uri
+ // * source-file
+ // see http://www.w3.org/TR/CSP11/#violation-reports
+ is(cspReport["document-uri"], docUri, "Incorrect document-uri");
+
+ // we can not test for the whole referrer since it includes platform specific information
+ ok(cspReport.referrer.startsWith("http://mochi.test:8888/tests/dom/security/test/csp/test_report.html"),
+ "Incorrect referrer");
+
+ is(cspReport["blocked-uri"], "inline", "Incorrect blocked-uri");
+
+ is(cspReport["effective-directive"], "script-src-elem", "Incorrect effective-directive");
+ is(cspReport["violated-directive"], "script-src-elem", "Incorrect violated-directive");
+
+ is(cspReport["original-policy"], "default-src 'none' 'report-sample'; report-uri http://mochi.test:8888/foo.sjs",
+ "Incorrect original-policy");
+
+ is(cspReport.disposition, "enforce", "Incorrect disposition");
+
+ is(cspReport["status-code"], 200, "Incorrect status-code");
+
+ is(cspReport["source-file"], docUri, "Incorrect source-file");
+
+ is(cspReport["script-sample"], "\n var foo = \"propEscFoo\";\n var bar…",
+ "Incorrect script-sample");
+
+ is(cspReport["line-number"], 7, "Incorrect line-number");
+}
+
+var chromeScriptUrl = SimpleTest.getTestFileURL("file_report_chromescript.js");
+var script = SpecialPowers.loadChromeScript(chromeScriptUrl);
+
+script.addMessageListener('opening-request-completed', function ml(msg) {
+ if (msg.error) {
+ ok(false, "Could not query report (exception: " + msg.error + ")");
+ } else {
+ try {
+ var reportObj = JSON.parse(msg.report);
+ } catch (e) {
+ ok(false, "Could not parse JSON (exception: " + e + ")");
+ }
+ try {
+ // test for the proper values in the report object
+ window.checkResults(reportObj);
+ } catch (e) {
+ ok(false, "Could not query report (exception: " + e + ")");
+ }
+ }
+
+ script.removeMessageListener('opening-request-completed', ml);
+ script.sendAsyncMessage("finish");
+ SimpleTest.finish();
+});
+
+SimpleTest.waitForExplicitFinish();
+
+// load the resource which will generate a CSP violation report
+// save this for last so that our listeners are registered.
+var src = "file_testserver.sjs";
+// append the file that should be served
+src += "?file=" + escape(testfile);
+// append the CSP that should be used to serve the file
+src += "&csp=" + escape(policy);
+// appending a fragment so we can test that it's correctly stripped
+// for document-uri and source-file.
+src += "#foo";
+document.getElementById("cspframe").src = src;
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_report_font_cache.html b/dom/security/test/csp/test_report_font_cache.html
new file mode 100644
index 0000000000..40577a1e00
--- /dev/null
+++ b/dom/security/test/csp/test_report_font_cache.html
@@ -0,0 +1,56 @@
+<!DOCTYPE html>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css">
+<iframe id="f"></iframe>
+
+<script>
+var chromeScriptUrl = SimpleTest.getTestFileURL("file_report_chromescript.js");
+var script = SpecialPowers.loadChromeScript(chromeScriptUrl);
+
+var reportedFont1 = false;
+var reportedFont3 = false;
+
+function reportListener(msg) {
+ if (!msg.error) {
+ // Step 3: Check the specific blocked URLs from the CSP reports.
+ let blocked = JSON.parse(msg.report)["csp-report"]["blocked-uri"]
+ .replace(/^.*\//, "");
+ switch (blocked) {
+ case "Ahem.ttf?report_font_cache-1":
+ ok(!reportedFont1, "should not have already reported Test Font 1");
+ ok(!reportedFont3, "should not have reported Test Font 3 before Test Font 1");
+ reportedFont1 = true;
+ break;
+ case "Ahem.ttf?report_font_cache-2":
+ ok(false, "should not have reported Test Font 2");
+ break;
+ case "Ahem.ttf?report_font_cache-3":
+ ok(!reportedFont3, "should not have already reported Test Font 3");
+ reportedFont3 = true;
+ break;
+ }
+ if (reportedFont1 && reportedFont3) {
+ script.removeMessageListener("opening-request-completed", reportListener);
+ script.sendAsyncMessage("finish");
+ SimpleTest.finish();
+ }
+ }
+}
+
+SimpleTest.waitForExplicitFinish();
+
+script.addMessageListener("opening-request-completed", reportListener);
+
+window.onmessage = function(message) {
+ // Step 2: Navigate to the second document, which will attempt to use the
+ // cached "Test Font 1" and then a new "Test Font 3", both of which will
+ // generate CSP reports. The "Test Font 2" entry in the user font cache
+ // should not cause a CSP report from this document.
+ is(message.data, "first-doc-ready");
+ f.src = "file_report_font_cache-2.html";
+};
+
+// Step 1: Prime the user font cache with entries for "Test Font 1",
+// "Test Font 2" and "Test Font 3".
+f.src = "file_report_font_cache-1.html";
+</script>
diff --git a/dom/security/test/csp/test_report_for_import.html b/dom/security/test/csp/test_report_for_import.html
new file mode 100644
index 0000000000..ddeee3b507
--- /dev/null
+++ b/dom/security/test/csp/test_report_for_import.html
@@ -0,0 +1,109 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=548193
+-->
+<head>
+ <title>Test for Bug 548193</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+
+<iframe style="width:200px;height:200px;" id='cspframe'></iframe>
+<script class="testbody" type="text/javascript">
+
+/*
+ * Description of the test:
+ * We are loading a stylesheet using a csp policy that only allows styles from 'self'
+ * to be loaded. In other words, the *.css file itself should be allowed to load, but
+ * the @import file within the CSS should get blocked. We verify that the generated
+ * csp-report is sent and contains all the expected values.
+ * In detail, the test starts by sending an XHR request to the report-server
+ * which waits on the server side till the report was received and hands the
+ * report in JSON format back to the testfile which then verifies accuracy
+ * of all the different report fields in the CSP report.
+ */
+
+const TEST_FILE = "tests/dom/security/test/csp/file_report_for_import.html";
+const REPORT_URI =
+ "http://mochi.test:8888/tests/dom/security/test/csp/file_report_for_import_server.sjs?report";
+const POLICY = "style-src 'self'; report-uri " + REPORT_URI;
+
+const DOC_URI =
+ "http://mochi.test:8888/tests/dom/security/test/csp/file_testserver.sjs?" +
+ "file=tests/dom/security/test/csp/file_report_for_import.html&" +
+ "csp=style-src%20%27self%27%3B%20" +
+ "report-uri%20http%3A//mochi.test%3A8888/tests/dom/security/test/csp/" +
+ "file_report_for_import_server.sjs%3Freport";
+
+function checkResults(reportStr) {
+ try {
+ var reportObj = JSON.parse(reportStr);
+ var cspReport = reportObj["csp-report"];
+
+ is(cspReport["document-uri"], DOC_URI, "Incorrect document-uri");
+ is(cspReport.referrer,
+ "http://mochi.test:8888/tests/dom/security/test/csp/test_report_for_import.html",
+ "Incorrect referrer");
+ is(cspReport["violated-directive"],
+ "style-src-elem",
+ "Incorrect violated-directive");
+ is(cspReport["original-policy"], POLICY, "Incorrect original-policy");
+ is(cspReport["blocked-uri"],
+ "http://example.com/tests/dom/security/test/csp/file_report_for_import_server.sjs?stylesheet",
+ "Incorrect blocked-uri");
+
+ // we do not always set the following fields
+ is(cspReport["source-file"], undefined, "Incorrect source-file");
+ is(cspReport["script-sample"], undefined, "Incorrect script-sample");
+ is(cspReport["line-number"], undefined, "Incorrect line-number");
+ }
+ catch (e) {
+ ok(false, "Could not parse JSON (exception: " + e + ")");
+ }
+}
+
+function loadTestPageIntoFrame() {
+ // load the resource which will generate a CSP violation report
+ // save this for last so that our listeners are registered.
+ var src = "file_testserver.sjs";
+ // append the file that should be served
+ src += "?file=" + escape(TEST_FILE);
+ // append the CSP that should be used to serve the file
+ src += "&csp=" + escape(POLICY);
+ // appending a fragment so we can test that it's correctly stripped
+ // for document-uri and source-file.
+ src += "#foo";
+ document.getElementById("cspframe").src = src;
+}
+
+function runTest() {
+ // send an xhr request to the server which is processed async, which only
+ // returns after the server has received the csp report.
+ var myXHR = new XMLHttpRequest();
+ myXHR.open("GET", "file_report_for_import_server.sjs?queryresult");
+ myXHR.onload = function(e) {
+ checkResults(myXHR.responseText);
+ SimpleTest.finish();
+ }
+ myXHR.onerror = function(e) {
+ ok(false, "could not query results from server (" + e.message + ")");
+ SimpleTest.finish();
+ }
+ myXHR.send();
+
+ // give it some time and run the testpage
+ SimpleTest.executeSoon(loadTestPageIntoFrame);
+}
+
+SimpleTest.waitForExplicitFinish();
+runTest();
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_report_uri_missing_in_report_only_header.html b/dom/security/test/csp/test_report_uri_missing_in_report_only_header.html
new file mode 100644
index 0000000000..0bdfd57bc9
--- /dev/null
+++ b/dom/security/test/csp/test_report_uri_missing_in_report_only_header.html
@@ -0,0 +1,57 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=847081
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 847081</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=847081">Mozilla Bug 847081</a>
+<p id="display"></p>
+<div id="content" style="display: none"></div>
+<iframe id="cspframe"></iframe>
+
+<pre id="test">
+<script class="testbody" type="text/javascript">
+var stringBundleService = SpecialPowers.Cc["@mozilla.org/intl/stringbundle;1"]
+ .getService(SpecialPowers.Ci.nsIStringBundleService);
+var localizer = stringBundleService.createBundle("chrome://global/locale/security/csp.properties");
+var warningMsg = localizer.formatStringFromName("reportURInotInReportOnlyHeader", [window.location.origin]);
+
+function cleanup() {
+ SpecialPowers.postConsoleSentinel();
+ SimpleTest.finish();
+}
+
+// Since Bug 1584993 we parse the CSP in the parent too, hence the
+// same error message appears twice in the console.
+var recordConsoleMsgOnce = false;
+
+SpecialPowers.registerConsoleListener(function ConsoleMsgListener(aMsg) {
+ if (aMsg.message.indexOf(warningMsg) > -1) {
+ if (recordConsoleMsgOnce) {
+ return;
+ }
+ recordConsoleMsgOnce = true;
+
+ ok(true, "report-uri not specified in Report-Only should throw a CSP warning.");
+ SimpleTest.executeSoon(cleanup);
+ return;
+ } else {
+ // if some other console message is present, we wait
+ return;
+ }
+});
+
+
+// set up and start testing
+SimpleTest.waitForExplicitFinish();
+document.getElementById('cspframe').src = 'file_report_uri_missing_in_report_only_header.html';
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_sandbox.html b/dom/security/test/csp/test_sandbox.html
new file mode 100644
index 0000000000..9fa123eadf
--- /dev/null
+++ b/dom/security/test/csp/test_sandbox.html
@@ -0,0 +1,249 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Tests for bugs 886164 and 671389</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<p id="display"></p>
+<div id="content">
+</div>
+
+<script class="testbody" type="text/javascript">
+
+var testCases = [
+ {
+ // Test 1: don't load image from non-same-origin; allow loading
+ // images from same-same origin
+ sandboxAttribute: "allow-same-origin",
+ csp: "default-src 'self'",
+ file: "file_sandbox_1.html",
+ results: { img1a_good: -1, img1_bad: -1 }
+ // fails if scripts execute
+ },
+ {
+ // Test 2: don't load image from non-same-origin; allow loading
+ // images from same-same origin, even without allow-same-origin
+ // flag
+ sandboxAttribute: "",
+ csp: "default-src 'self'",
+ file: "file_sandbox_2.html",
+ results: { img2_bad: -1, img2a_good: -1 }
+ // fails if scripts execute
+ },
+ {
+ // Test 3: disallow loading images from any host, even with
+ // allow-same-origin flag set
+ sandboxAttribute: "allow-same-origin",
+ csp: "default-src 'none'",
+ file: "file_sandbox_3.html",
+ results: { img3_bad: -1, img3a_bad: -1 },
+ // fails if scripts execute
+ },
+ {
+ // Test 4: disallow loading images from any host
+ sandboxAttribute: "",
+ csp: "default-src 'none'",
+ file: "file_sandbox_4.html",
+ results: { img4_bad: -1, img4a_bad: -1 }
+ // fails if scripts execute
+ },
+ {
+ // Test 5: disallow loading images or scripts, allow inline scripts
+ sandboxAttribute: "allow-scripts",
+ csp: "default-src 'none'; script-src 'unsafe-inline';",
+ file: "file_sandbox_5.html",
+ results: { img5_bad: -1, img5a_bad: -1, script5_bad: -1, script5a_bad: -1 },
+ nrOKmessages: 2 // sends 2 ok message
+ // fails if scripts execute
+ },
+ {
+ // Test 6: disallow non-same-origin images, allow inline and same origin scripts
+ sandboxAttribute: "allow-same-origin allow-scripts",
+ csp: "default-src 'self' 'unsafe-inline';",
+ file: "file_sandbox_6.html",
+ results: { img6_bad: -1, script6_bad: -1 },
+ nrOKmessages: 4 // sends 4 ok message
+ // fails if forms are not disallowed
+ },
+ {
+ // Test 7: same as Test 1
+ csp: "default-src 'self'; sandbox allow-same-origin",
+ file: "file_sandbox_7.html",
+ results: { img7a_good: -1, img7_bad: -1 }
+ },
+ {
+ // Test 8: same as Test 2
+ csp: "sandbox allow-same-origin; default-src 'self'",
+ file: "file_sandbox_8.html",
+ results: { img8_bad: -1, img8a_good: -1 }
+ },
+ {
+ // Test 9: same as Test 3
+ csp: "default-src 'none'; sandbox allow-same-origin",
+ file: "file_sandbox_9.html",
+ results: { img9_bad: -1, img9a_bad: -1 }
+ },
+ {
+ // Test 10: same as Test 4
+ csp: "default-src 'none'; sandbox allow-same-origin",
+ file: "file_sandbox_10.html",
+ results: { img10_bad: -1, img10a_bad: -1 }
+ },
+ {
+ // Test 11: same as Test 5
+ csp: "default-src 'none'; script-src 'unsafe-inline'; sandbox allow-scripts allow-same-origin",
+ file: "file_sandbox_11.html",
+ results: { img11_bad: -1, img11a_bad: -1, script11_bad: -1, script11a_bad: -1 },
+ nrOKmessages: 2 // sends 2 ok message
+ },
+ {
+ // Test 12: same as Test 6
+ csp: "sandbox allow-same-origin allow-scripts; default-src 'self' 'unsafe-inline';",
+ file: "file_sandbox_12.html",
+ results: { img12_bad: -1, script12_bad: -1 },
+ nrOKmessages: 4 // sends 4 ok message
+ },
+ {
+ // Test 13: same as Test 5 and Test 11, but:
+ // * using sandbox flag 'allow-scripts' in CSP and not as iframe attribute
+ // * not using allow-same-origin in CSP (so a new NullPrincipal is created).
+ csp: "default-src 'none'; script-src 'unsafe-inline'; sandbox allow-scripts",
+ file: "file_sandbox_13.html",
+ results: { img13_bad: -1, img13a_bad: -1, script13_bad: -1, script13a_bad: -1 },
+ nrOKmessages: 2 // sends 2 ok message
+ },
+];
+
+// a postMessage handler that is used by sandboxed iframes without
+// 'allow-same-origin' to communicate pass/fail back to this main page.
+// it expects to be called with an object like:
+// { ok: true/false,
+// desc: <description of the test> which it then forwards to ok() }
+window.addEventListener("message", receiveMessage);
+
+function receiveMessage(event) {
+ ok_wrapper(event.data.ok, event.data.desc);
+}
+
+var completedTests = 0;
+var passedTests = 0;
+
+var totalTests = (function() {
+ var nrCSPloadTests = 0;
+ for(var i = 0; i < testCases.length; i++) {
+ nrCSPloadTests += Object.keys(testCases[i].results).length;
+ if (testCases[i].nrOKmessages) {
+ // + number of expected postMessages from iframe
+ nrCSPloadTests += testCases[i].nrOKmessages;
+ }
+ }
+ return nrCSPloadTests;
+})();
+
+function ok_wrapper(result, desc) {
+ ok(result, desc);
+
+ completedTests++;
+
+ if (result) {
+ passedTests++;
+ }
+
+ if (completedTests === totalTests) {
+ window.examiner.remove();
+ SimpleTest.finish();
+ }
+}
+
+// Set the iframe src and sandbox attribute
+function runTest(test) {
+ var iframe = document.createElement('iframe');
+
+ document.getElementById('content').appendChild(iframe);
+
+ // set sandbox attribute
+ if (test.sandboxAttribute !== undefined) {
+ iframe.sandbox = test.sandboxAttribute;
+ }
+
+ // set query string
+ var src = 'file_testserver.sjs';
+ // path where the files are
+ var path = '/tests/dom/security/test/csp/';
+
+ src += '?file=' + escape(path+test.file);
+
+ if (test.csp !== undefined) {
+ src += '&csp=' + escape(test.csp);
+ }
+
+ iframe.src = src;
+ iframe.width = iframe.height = 10;
+}
+
+// Examiner related
+
+// This is used to watch the blocked data bounce off CSP and allowed data
+// get sent out to the wire.
+function examiner() {
+ SpecialPowers.addObserver(this, "csp-on-violate-policy");
+ SpecialPowers.addObserver(this, "specialpowers-http-notify-request");
+}
+
+examiner.prototype = {
+ observe(subject, topic, data) {
+ var testpat = new RegExp("testid=([a-z0-9_]+)");
+
+ //_good things better be allowed!
+ //_bad things better be stopped!
+
+ if (topic === "specialpowers-http-notify-request") {
+ //these things were allowed by CSP
+ var uri = data;
+ if (!testpat.test(uri)) return;
+ var testid = testpat.exec(uri)[1];
+
+ if(/_good/.test(testid)) {
+ ok_wrapper(true, uri + " is allowed by csp");
+ } else {
+ ok_wrapper(false, uri + " should not be allowed by csp");
+ }
+ }
+
+ if(topic === "csp-on-violate-policy") {
+ //these were blocked... record that they were blocked
+ var asciiSpec = SpecialPowers.getPrivilegedProps(SpecialPowers.do_QueryInterface(subject, "nsIURI"), "asciiSpec");
+ if (!testpat.test(asciiSpec)) return;
+ var testid = testpat.exec(asciiSpec)[1];
+ if(/_bad/.test(testid)) {
+ ok_wrapper(true, asciiSpec + " was blocked by \"" + data + "\"");
+ } else {
+ ok_wrapper(false, asciiSpec + " should have been blocked by \"" + data + "\"");
+ }
+ }
+ },
+
+ // must eventually call this to remove the listener,
+ // or mochitests might get borked.
+ remove() {
+ SpecialPowers.removeObserver(this, "csp-on-violate-policy");
+ SpecialPowers.removeObserver(this, "specialpowers-http-notify-request");
+ }
+}
+
+window.examiner = new examiner();
+
+SimpleTest.waitForExplicitFinish();
+
+(function() { // Run tests:
+ for(var i = 0; i < testCases.length; i++) {
+ runTest(testCases[i]);
+ }
+})();
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_sandbox_allow_scripts.html b/dom/security/test/csp/test_sandbox_allow_scripts.html
new file mode 100644
index 0000000000..68544a5178
--- /dev/null
+++ b/dom/security/test/csp/test_sandbox_allow_scripts.html
@@ -0,0 +1,31 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 1396320: Fix CSP sandbox regression for allow-scripts</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<iframe style="width:100%;" id="testframe"></iframe>
+<script class="testbody" type="text/javascript">
+
+/* Description of the test:
+ * Load an iframe using a CSP of 'sandbox allow-scripts' and make sure
+ * the security context of the iframe is sandboxed (cross origin)
+ */
+SimpleTest.waitForExplicitFinish();
+
+window.addEventListener("message", receiveMessage);
+function receiveMessage(event) {
+ is(event.data.result, "",
+ "document.domain of sandboxed iframe should be opaque");
+ window.removeEventListener("message", receiveMessage);
+ SimpleTest.finish();
+}
+
+let testframe = document.getElementById("testframe");
+testframe.src = "file_sandbox_allow_scripts.html";
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_scheme_relative_sources.html b/dom/security/test/csp/test_scheme_relative_sources.html
new file mode 100644
index 0000000000..3de3d98d69
--- /dev/null
+++ b/dom/security/test/csp/test_scheme_relative_sources.html
@@ -0,0 +1,91 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 921493 - CSP: test allowlisting of scheme-relative sources</title>
+ <!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<iframe style="width:100%;" id="testframe"></iframe>
+
+<script class="testbody" type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+
+/* Description of the test:
+ * We load http and https pages and verify that scheme relative sources
+ * are allowed unless its a downgrade from https -> http.
+ *
+ * Please note that the policy contains 'unsafe-inline' so we can use
+ * an inline script to query the result from within the sandboxed iframe
+ * and report it back to the parent document.
+ */
+
+var POLICY = "default-src 'none'; script-src 'unsafe-inline' example.com;";
+
+var tests = [
+ {
+ description: "http -> http",
+ from: "http",
+ to: "http",
+ result: "allowed",
+ },
+ {
+ description: "http -> https",
+ from: "http",
+ to: "https",
+ result: "allowed",
+ },
+ {
+ description: "https -> https",
+ from: "https",
+ to: "https",
+ result: "allowed",
+ },
+ {
+ description: "https -> http",
+ from: "https",
+ to: "http",
+ result: "blocked",
+ }
+];
+
+var counter = 0;
+var curTest;
+
+function loadNextTest() {
+ if (counter == tests.length) {
+ window.removeEventListener("message", receiveMessage);
+ SimpleTest.finish();
+ return;
+ }
+
+ curTest = tests[counter++];
+
+ var src = curTest.from +
+ "://example.com/tests/dom/security/test/csp/file_scheme_relative_sources.sjs" +
+ "?scheme=" + curTest.to +
+ "&policy=" + escape(POLICY);
+
+ document.getElementById("testframe").src = src;
+}
+
+// using a postMessage handler to report the result back from
+// within the sandboxed iframe without 'allow-same-origin'.
+window.addEventListener("message", receiveMessage);
+
+function receiveMessage(event) {
+
+ is(event.data.result, curTest.result,
+ "should be " + curTest.result + " in test (" + curTest.description + ")!");
+
+ loadNextTest();
+}
+
+// get the test started
+loadNextTest();
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_script_template.html b/dom/security/test/csp/test_script_template.html
new file mode 100644
index 0000000000..a71ebfe960
--- /dev/null
+++ b/dom/security/test/csp/test_script_template.html
@@ -0,0 +1,60 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 1548385 - CSP: Test script template</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<iframe style="width:100%;" id="testframe"></iframe>
+
+<script class="testbody" type="text/javascript">
+
+/**
+ * Description of the test:
+ * We load a document using a CSP of "default-src 'unsafe-inline'"
+ * and make sure that an external script within a template gets
+ * blocked correctly.
+ */
+
+const CSP_BLOCKED_SUBJECT = "csp-on-violate-policy";
+const CSP_ALLOWED_SUBJECT = "specialpowers-http-notify-request";
+
+SimpleTest.waitForExplicitFinish();
+
+function examiner() {
+ SpecialPowers.addObserver(this, CSP_BLOCKED_SUBJECT);
+ SpecialPowers.addObserver(this, CSP_ALLOWED_SUBJECT);
+}
+
+examiner.prototype = {
+ observe(subject, topic, data) {
+ if (topic == CSP_BLOCKED_SUBJECT) {
+ let jsFileName = SpecialPowers.getPrivilegedProps(SpecialPowers.do_QueryInterface(subject, "nsIURI"), "asciiSpec");
+ if (jsFileName.endsWith("file_script_template.js")) {
+ ok(true, "js file blocked by CSP");
+ this.removeAndFinish();
+ }
+ }
+
+ if (topic == CSP_ALLOWED_SUBJECT) {
+ if (data.endsWith("file_script_template.js")) {
+ ok(false, "js file allowed by CSP");
+ this.removeAndFinish();
+ }
+ }
+ },
+
+ removeAndFinish() {
+ SpecialPowers.removeObserver(this, CSP_BLOCKED_SUBJECT);
+ SpecialPowers.removeObserver(this, CSP_ALLOWED_SUBJECT);
+ SimpleTest.finish();
+ }
+}
+
+window.examiner = new examiner();
+document.getElementById("testframe").src = "file_script_template.html";
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_security_policy_violation_event.html b/dom/security/test/csp/test_security_policy_violation_event.html
new file mode 100644
index 0000000000..0d5cfade9c
--- /dev/null
+++ b/dom/security/test/csp/test_security_policy_violation_event.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<meta http-equiv="Content-Security-Policy" content="img-src 'none'">
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<script>
+SimpleTest.waitForExplicitFinish();
+
+document.addEventListener("securitypolicyviolation", (e) => {
+ SimpleTest.is(e.blockedURI, "http://mochi.test:8888/foo/bar.jpg", "blockedURI");
+ SimpleTest.is(e.violatedDirective, "img-src", "violatedDirective")
+ SimpleTest.is(e.originalPolicy, "img-src 'none'", "originalPolicy");
+ SimpleTest.finish();
+});
+</script>
+<img src="http://mochi.test:8888/foo/bar.jpg">
diff --git a/dom/security/test/csp/test_self_none_as_hostname_confusion.html b/dom/security/test/csp/test_self_none_as_hostname_confusion.html
new file mode 100644
index 0000000000..50627711ff
--- /dev/null
+++ b/dom/security/test/csp/test_self_none_as_hostname_confusion.html
@@ -0,0 +1,55 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=587377
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 587377</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=587377">Mozilla Bug 587377</a>
+<p id="display"></p>
+
+<iframe id="cspframe"></iframe>
+
+<pre id="test">
+
+<script class="testbody" type="text/javascript">
+// Load locale string during mochitest
+var stringBundleService = SpecialPowers.Cc["@mozilla.org/intl/stringbundle;1"]
+ .getService(SpecialPowers.Ci.nsIStringBundleService);
+var localizer = stringBundleService.createBundle("chrome://global/locale/security/csp.properties");
+var confusionMsg = localizer.formatStringFromName("hostNameMightBeKeyword", ["SELF", "self"]);
+
+function cleanup() {
+ SpecialPowers.postConsoleSentinel();
+ SimpleTest.finish();
+};
+
+// To prevent the test from asserting twice and calling SimpleTest.finish() twice,
+// startTest will be marked false as soon as the confusionMsg is detected.
+startTest = false;
+SpecialPowers.registerConsoleListener(function ConsoleMsgListener(aMsg) {
+ if (startTest) {
+ if (aMsg.message.indexOf(confusionMsg) > -1) {
+ startTest = false;
+ ok(true, "CSP header with a hostname similar to keyword should be warned");
+ SimpleTest.executeSoon(cleanup);
+ } else {
+ // don't see the warning yet? wait.
+ return;
+ }
+ }
+});
+
+// set up and start testing
+SimpleTest.waitForExplicitFinish();
+document.getElementById('cspframe').src = 'file_self_none_as_hostname_confusion.html';
+startTest = true;
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_sendbeacon.html b/dom/security/test/csp/test_sendbeacon.html
new file mode 100644
index 0000000000..3b0df34c05
--- /dev/null
+++ b/dom/security/test/csp/test_sendbeacon.html
@@ -0,0 +1,34 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Bug 1234813 - sendBeacon should not throw if blocked by Content Policy</title>
+ <!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<p id="display"></p>
+<iframe style="width:100%;" id="testframe" src="file_sendbeacon.html"></iframe>
+
+<script class="testbody" type="text/javascript">
+
+/* Description of the test:
+ * Let's try to fire a sendBeacon which gets blocked by CSP. Let's make sure
+ * sendBeacon does not throw an exception.
+ */
+SimpleTest.waitForExplicitFinish();
+
+// a postMessage handler used to bubble up the
+// result from within the iframe.
+window.addEventListener("message", receiveMessage);
+function receiveMessage(event) {
+ var result = event.data.result;
+ is(result, "blocked-beacon-does-not-throw", "sendBeacon should not throw");
+ window.removeEventListener("message", receiveMessage);
+ SimpleTest.finish();
+}
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_service_worker.html b/dom/security/test/csp/test_service_worker.html
new file mode 100644
index 0000000000..dc3b3b43d2
--- /dev/null
+++ b/dom/security/test/csp/test_service_worker.html
@@ -0,0 +1,62 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 1208559 - ServiceWorker registration not governed by CSP</title>
+ <!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<iframe style="width:100%;" id="testframe"></iframe>
+
+<script class="testbody" type="text/javascript">
+
+/* Description of the test:
+ * Spawning a worker from https://example.com but script-src is 'test1.example.com'
+ * CSP is not consulted
+ */
+SimpleTest.waitForExplicitFinish();
+
+var tests = [
+ {
+ policy: "default-src 'self'; script-src 'unsafe-inline'; child-src test1.example.com;",
+ expected: "blocked"
+ },
+];
+
+var counter = 0;
+var curTest;
+
+window.addEventListener("message", receiveMessage);
+function receiveMessage(event) {
+ is(event.data.result, curTest.expected, "Should be (" + curTest.expected + ") in Test " + counter + "!");
+ loadNextTest();
+}
+
+onload = function() {
+ SpecialPowers.pushPrefEnv({"set": [
+ ["dom.serviceWorkers.exemptFromPerDomainMax", true],
+ ["dom.serviceWorkers.enabled", true],
+ ["dom.serviceWorkers.testing.enabled", true],
+ ["dom.caches.enabled", true],
+ ["privacy.partition.serviceWorkers", true],
+ ]}, loadNextTest);
+}
+
+function loadNextTest() {
+ if (counter == tests.length) {
+ SimpleTest.finish();
+ return;
+ }
+ curTest = tests[counter++];
+ var src = "https://example.com/tests/dom/security/test/csp/file_testserver.sjs";
+ // append the file that should be served
+ src += "?file=" + escape("tests/dom/security/test/csp/file_service_worker.html");
+ // append the CSP that should be used to serve the file
+ src += "&csp=" + escape(curTest.policy);
+ document.getElementById("testframe").src = src;
+}
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_strict_dynamic.html b/dom/security/test/csp/test_strict_dynamic.html
new file mode 100644
index 0000000000..f894e6d447
--- /dev/null
+++ b/dom/security/test/csp/test_strict_dynamic.html
@@ -0,0 +1,133 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 1299483 - CSP: Implement 'strict-dynamic'</title>
+ <!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+ <iframe style="width:100%;" id="testframe"></iframe>
+
+<script class="testbody" type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+
+/* Description of the test:
+ * We load scripts with a CSP of 'strict-dynamic' with valid
+ * and invalid nonces and make sure scripts are allowed/blocked
+ * accordingly. Different tests load inline and external scripts
+ * also using a CSP including http: and https: making sure
+ * other srcs are invalided by 'strict-dynamic'.
+ */
+
+var tests = [
+ {
+ desc: "strict-dynamic with valid nonce should be allowed",
+ result: "allowed",
+ file: "file_strict_dynamic_script_extern.html",
+ policy: "script-src 'strict-dynamic' 'nonce-foo' https: 'none' 'self'"
+ },
+ {
+ desc: "strict-dynamic with invalid nonce should be blocked",
+ result: "blocked",
+ file: "file_strict_dynamic_script_extern.html",
+ policy: "script-src 'strict-dynamic' 'nonce-bar' http: http://example.com"
+ },
+ {
+ desc: "strict-dynamic, allowlist and invalid nonce should be blocked",
+ result: "blocked",
+ file: "file_strict_dynamic_script_extern.html",
+ policy: "script-src 'strict-dynamic' 'nonce-bar' 'unsafe-inline' http: http://example.com"
+ },
+ {
+ desc: "strict-dynamic with no 'nonce-' should be blocked",
+ result: "blocked",
+ file: "file_strict_dynamic_script_extern.html",
+ policy: "script-src 'strict-dynamic'"
+ },
+ // inline scripts
+ {
+ desc: "strict-dynamic with valid nonce should be allowed",
+ result: "allowed",
+ file: "file_strict_dynamic_script_inline.html",
+ policy: "script-src 'strict-dynamic' 'nonce-foo' https: 'none' 'self'"
+ },
+ {
+ desc: "strict-dynamic with invalid nonce should be blocked",
+ result: "blocked",
+ file: "file_strict_dynamic_script_inline.html",
+ policy: "script-src 'strict-dynamic' 'nonce-bar' http: http://example.com"
+ },
+ {
+ desc: "strict-dynamic, unsafe-inline and invalid nonce should be blocked",
+ result: "blocked",
+ file: "file_strict_dynamic_script_inline.html",
+ policy: "script-src 'strict-dynamic' 'nonce-bar' 'unsafe-inline' http: http://example.com"
+ },
+ {
+ desc: "strict-dynamic with no 'nonce-' should be blocked",
+ result: "blocked",
+ file: "file_strict_dynamic_script_inline.html",
+ policy: "script-src 'strict-dynamic'"
+ },
+ {
+ desc: "strict-dynamic with DOM events should be blocked",
+ result: "blocked",
+ file: "file_strict_dynamic_script_events.html",
+ policy: "script-src 'strict-dynamic' 'nonce-foo'"
+ },
+ {
+ // marquee is a special snowflake
+ desc: "strict-dynamic with DOM events should be blocked (marquee)",
+ result: "blocked",
+ file: "file_strict_dynamic_script_events_marquee.html",
+ policy: "script-src 'strict-dynamic' 'nonce-foo'"
+ },
+ {
+ desc: "strict-dynamic with JS URLs should be blocked",
+ result: "blocked",
+ file: "file_strict_dynamic_js_url.html",
+ policy: "script-src 'strict-dynamic' 'nonce-foo'"
+ },
+];
+
+var counter = 0;
+var curTest;
+
+function loadNextTest() {
+ if (counter == tests.length) {
+ SimpleTest.finish();
+ return;
+ }
+
+ curTest = tests[counter++];
+ var src = "file_testserver.sjs?file=";
+ // append the file that should be served
+ src += escape("tests/dom/security/test/csp/" + curTest.file)
+ // append the CSP that should be used to serve the file
+ src += "&csp=" + escape(curTest.policy);
+
+ document.getElementById("testframe").addEventListener("load", test);
+ document.getElementById("testframe").src = src;
+}
+
+function test() {
+ try {
+ document.getElementById("testframe").removeEventListener('load', test);
+ var testframe = document.getElementById("testframe");
+ var divcontent = testframe.contentWindow.document.getElementById('testdiv').innerHTML;
+ is(divcontent, curTest.result, curTest.desc);
+ }
+ catch (e) {
+ ok(false, "ERROR: could not access content for test: '" + curTest.desc + "'");
+ }
+ loadNextTest();
+}
+
+// start running the tests
+loadNextTest();
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_strict_dynamic_default_src.html b/dom/security/test/csp/test_strict_dynamic_default_src.html
new file mode 100644
index 0000000000..53eb899ab2
--- /dev/null
+++ b/dom/security/test/csp/test_strict_dynamic_default_src.html
@@ -0,0 +1,136 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 1299483 - CSP: Implement 'strict-dynamic'</title>
+ <!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+ <iframe style="width:100%;" id="testframe"></iframe>
+
+<script class="testbody" type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+
+/* Description of the test:
+ * We load scripts and images with a CSP of 'strict-dynamic' making sure
+ * allowlists get ignored for scripts but not for images when strict-dynamic
+ * appears in default-src.
+ *
+ * Please note that we do not support strict-dynamic within default-src yet,
+ * see Bug 1313937. When updating this test please do not change the
+ * csp policies, but only replace todo_is() with is().
+ */
+
+var tests = [
+ {
+ script_desc: "(test1) script should be allowed because of valid nonce",
+ img_desc: "(test1) img should be allowed because of 'self'",
+ script_result: "allowed",
+ img_result: "allowed",
+ policy: "default-src 'strict-dynamic' 'self'; script-src 'nonce-foo'"
+ },
+ {
+ script_desc: "(test 2) script should be blocked because of invalid nonce",
+ img_desc: "(test 2) img should be allowed because of valid scheme-src",
+ script_result: "blocked",
+ img_result: "allowed",
+ policy: "default-src 'strict-dynamic' http:; script-src 'nonce-bar' http:"
+ },
+ {
+ script_desc: "(test 3) script should be blocked because of invalid nonce",
+ img_desc: "(test 3) img should be allowed because of valid host-src",
+ script_result: "blocked",
+ script_enforced: "",
+ img_result: "allowed",
+ policy: "default-src 'strict-dynamic' mochi.test; script-src 'nonce-bar' http:"
+ },
+ {
+ script_desc: "(test 4) script should be allowed because of valid nonce",
+ img_desc: "(test 4) img should be blocked because of default-src 'strict-dynamic'",
+ script_result: "allowed",
+ img_result: "blocked",
+ policy: "default-src 'strict-dynamic'; script-src 'nonce-foo'"
+ },
+ // some reverse order tests (have script-src appear before default-src)
+ {
+ script_desc: "(test 5) script should be allowed because of valid nonce",
+ img_desc: "(test 5) img should be blocked because of default-src 'strict-dynamic'",
+ script_result: "allowed",
+ img_result: "blocked",
+ policy: "script-src 'nonce-foo'; default-src 'strict-dynamic';"
+ },
+ {
+ script_desc: "(test 6) script should be allowed because of valid nonce",
+ img_desc: "(test 6) img should be blocked because of default-src http:",
+ script_result: "blocked",
+ img_result: "blocked",
+ policy: "script-src 'nonce-bar' http:; default-src 'strict-dynamic' http:;"
+ },
+ {
+ script_desc: "(test 7) script should be allowed because of invalid nonce",
+ img_desc: "(test 7) img should be blocked because of image-src http:",
+ script_result: "blocked",
+ img_result: "blocked",
+ policy: "script-src 'nonce-bar' http:; default-src 'strict-dynamic' http:; img-src http:"
+ },
+];
+
+var counter = 0;
+var curTest;
+
+function loadNextTest() {
+ if (counter == tests.length) {
+ SimpleTest.finish();
+ return;
+ }
+
+ curTest = tests[counter++];
+ var src = "file_testserver.sjs?file=";
+ // append the file that should be served
+ src += escape("tests/dom/security/test/csp/file_strict_dynamic_default_src.html");
+ // append the CSP that should be used to serve the file
+ src += "&csp=" + escape(curTest.policy);
+
+ document.getElementById("testframe").addEventListener("load", checkResults);
+ document.getElementById("testframe").src = src;
+}
+
+function checkResults() {
+ try {
+ var testframe = document.getElementById("testframe");
+ testframe.removeEventListener('load', checkResults);
+
+ // check if script loaded
+ var divcontent = testframe.contentWindow.document.getElementById('testdiv').innerHTML;
+ var imgcontent = testframe.contentWindow.document.getElementById('testimage').dataset.result;
+ if (curTest.script_result === "blocked") {
+ todo_is(divcontent, curTest.script_result, curTest.script_desc);
+ }
+ else {
+ is(divcontent, curTest.script_result, curTest.script_desc);
+ }
+
+ // check if image loaded
+ var testimg = testframe.contentWindow.document.getElementById("testimage");
+ if (curTest.img_result === "allowed") {
+ todo_is(imgcontent, curTest.img_result, curTest.img_desc);
+ }
+ else {
+ is(imgcontent, curTest.img_result, curTest.img_desc);
+ }
+ }
+ catch (e) {
+ ok(false, "ERROR: could not access content for test: '" + curTest.script_desc + "'");
+ }
+
+ loadNextTest();
+}
+
+// start running the tests
+loadNextTest();
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_strict_dynamic_parser_inserted.html b/dom/security/test/csp/test_strict_dynamic_parser_inserted.html
new file mode 100644
index 0000000000..63d2c5a256
--- /dev/null
+++ b/dom/security/test/csp/test_strict_dynamic_parser_inserted.html
@@ -0,0 +1,94 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 1299483 - CSP: Implement 'strict-dynamic'</title>
+ <!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+ <iframe style="width:100%;" id="testframe"></iframe>
+
+<script class="testbody" type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+
+/* Description of the test:
+ * We loader parser and non parser inserted scripts making sure that
+ * parser inserted scripts are blocked if strict-dynamic is present
+ * and no valid nonce and also making sure that non-parser inserted
+ * scripts are allowed to execute.
+ */
+
+var tests = [
+ {
+ desc: "(parser inserted script) using doc.write(<script>) should be blocked",
+ result: "blocked",
+ file: "file_strict_dynamic_parser_inserted_doc_write.html",
+ policy: "script-src 'strict-dynamic' 'nonce-foo' http:"
+ },
+ {
+ desc: "(parser inserted script with valid nonce) using doc.write(<script>) should be allowed",
+ result: "allowed",
+ file: "file_strict_dynamic_parser_inserted_doc_write_correct_nonce.html",
+ policy: "script-src 'strict-dynamic' 'nonce-foo' https:"
+ },
+ {
+ desc: "(non parser inserted script) using appendChild() should allow external script",
+ result: "allowed",
+ file: "file_strict_dynamic_non_parser_inserted.html",
+ policy: "script-src 'strict-dynamic' 'nonce-foo' https:"
+ },
+ {
+ desc: "(non parser inserted script) using appendChild() should allow inline script",
+ result: "allowed",
+ file: "file_strict_dynamic_non_parser_inserted_inline.html",
+ policy: "script-src 'strict-dynamic' 'nonce-foo' https:"
+ },
+ {
+ desc: "strict-dynamic should not invalidate 'unsafe-eval'",
+ result: "allowed",
+ file: "file_strict_dynamic_unsafe_eval.html",
+ policy: "script-src 'strict-dynamic' 'nonce-foo' 'unsafe-eval'"
+ },
+];
+
+var counter = 0;
+var curTest;
+
+function loadNextTest() {
+ if (counter == tests.length) {
+ SimpleTest.finish();
+ return;
+ }
+
+ curTest = tests[counter++];
+ var src = "file_testserver.sjs?file=";
+ // append the file that should be served
+ src += escape("tests/dom/security/test/csp/" + curTest.file)
+ // append the CSP that should be used to serve the file
+ src += "&csp=" + escape(curTest.policy);
+
+ document.getElementById("testframe").addEventListener("load", test);
+ document.getElementById("testframe").src = src;
+}
+
+function test() {
+ try {
+ document.getElementById("testframe").removeEventListener('load', test);
+ var testframe = document.getElementById("testframe");
+ var divcontent = testframe.contentWindow.document.getElementById('testdiv').innerHTML;
+ is(divcontent, curTest.result, curTest.desc);
+ }
+ catch (e) {
+ ok(false, "ERROR: could not access content for test: '" + curTest.desc + "'");
+ }
+ loadNextTest();
+}
+
+// start running the tests
+loadNextTest();
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_subframe_run_js_if_allowed.html b/dom/security/test/csp/test_subframe_run_js_if_allowed.html
new file mode 100644
index 0000000000..fbf5a885cd
--- /dev/null
+++ b/dom/security/test/csp/test_subframe_run_js_if_allowed.html
@@ -0,0 +1,33 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=702439
+
+This test verifies that child iframes of CSP documents are
+permitted to execute javascript: URLs assuming the policy
+allows this.
+-->
+<head>
+ <title>Test for Bug 702439</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<iframe id="i"></iframe>
+<script class="testbody" type="text/javascript">
+var javascript_link_ran = false;
+
+// check that the script in the child frame's javascript: URL ran
+function checkResult()
+{
+ is(javascript_link_ran, true,
+ "javascript URL didn't execute");
+
+ SimpleTest.finish();
+}
+
+SimpleTest.waitForExplicitFinish();
+document.getElementById('i').src = 'file_subframe_run_js_if_allowed.html';
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_svg_inline_style.html b/dom/security/test/csp/test_svg_inline_style.html
new file mode 100644
index 0000000000..c05ca20467
--- /dev/null
+++ b/dom/security/test/csp/test_svg_inline_style.html
@@ -0,0 +1,135 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 1262842: Test CSP inline style within svg image</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/WindowSnapshot.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<iframe id="img_base"></iframe>
+<iframe id="img_csp"></iframe>
+<iframe id="img_base_srcset"></iframe>
+<iframe id="img_csp_srcset"></iframe>
+<iframe id="doc_base"></iframe>
+<iframe id="doc_csp"></iframe>
+
+<script class="testbody" type="text/javascript">
+
+// Description of the two tests:
+// * CSP should not apply to SVGs loaded as images (in src or srcset)
+// * CSP should apply to SVGs loaded as document
+// Since we have to test inline styles within SVGs, we loaded the SVGs
+// and then take screenshots to comopare that the two SVGs are identical.
+
+SimpleTest.waitForExplicitFinish();
+
+let img_base = document.getElementById("img_base");
+let img_csp = document.getElementById("img_csp");
+let img_base_srcset = document.getElementById("img_base_srcset");
+let img_csp_srcset = document.getElementById("img_csp_srcset");
+let doc_base = document.getElementById("doc_base");
+let doc_csp = document.getElementById("doc_csp");
+
+let loadedFrames = 0;
+
+async function compareSVGs() {
+ loadedFrames++;
+ if (loadedFrames != 6) {
+ return;
+ }
+ // compare the two iframes where SVGs are loaded as images
+ try {
+ let img_base_snap = await snapshotWindow(img_base.contentWindow);
+ let img_csp_snap = await snapshotWindow(img_csp.contentWindow);
+
+ ok(compareSnapshots(img_base_snap, img_csp_snap, true)[0],
+ "CSP should not apply to SVG loaded as image");
+ } catch(err) {
+ ok(false, "img error: " + err.message);
+ }
+
+ // compare the two iframes where SVGs are loaded as images with srcset
+ try {
+ let img_base_snap_srcset = await snapshotWindow(img_base_srcset.contentWindow);
+ let img_csp_snap_srcset = await snapshotWindow(img_csp_srcset.contentWindow);
+
+ ok(compareSnapshots(img_base_snap_srcset, img_csp_snap_srcset, true)[0],
+ "CSP should not apply to SVG loaded as image with srcset");
+ } catch(err) {
+ ok(false, "img error: " + err.message);
+ }
+
+ // compare the two iframes where SVGs are loaded as documents
+ try {
+ let doc_base_snap = await snapshotWindow(doc_base.contentWindow);
+ let doc_csp_snap = await snapshotWindow(doc_csp.contentWindow);
+
+ ok(compareSnapshots(doc_base_snap, doc_csp_snap, true)[0],
+ "CSP should apply to SVG loaded as document");
+ } catch(err) {
+ ok(false, "doc error: " + err.message);
+ }
+
+ SimpleTest.finish();
+}
+
+// load SVG as images
+img_base.onerror = function() {
+ ok(false, "sanity: img_base onerror should not fire");
+}
+img_base.onload = function() {
+ ok(true, "sanity: img_base onload should fire");
+ compareSVGs();
+}
+img_base.src = "file_svg_inline_style_base.html";
+
+img_csp.onerror = function() {
+ ok(false, "sanity: img_csp onerror should not fire");
+}
+img_csp.onload = function() {
+ ok(true, "sanity: img_csp onload should fire");
+ compareSVGs();
+}
+img_csp.src = "file_svg_inline_style_csp.html";
+
+img_base_srcset.onerror = function() {
+ ok(false, "sanity: img_base_srcset onerror should not fire");
+}
+img_base_srcset.onload = function() {
+ ok(true, "sanity: img_base_srcset onload should fire");
+ compareSVGs();
+}
+img_base_srcset.src = "file_svg_srcset_inline_style_base.html";
+
+img_csp_srcset.onerror = function() {
+ ok(false, "sanity: img_csp_srcset onerror should not fire");
+}
+img_csp_srcset.onload = function() {
+ ok(true, "sanity: img_csp_srcset onload should fire");
+ compareSVGs();
+}
+img_csp_srcset.src = "file_svg_srcset_inline_style_csp.html";
+
+// load SVG as documnents
+doc_base.onerror = function() {
+ ok(false, "sanity: doc_base onerror should not fire");
+}
+doc_base.onload = function() {
+ ok(true, "sanity: doc_base onload should fire");
+ compareSVGs();
+}
+doc_base.src = "file_svg_inline_style_server.sjs?svg_no_inline_style&5";
+
+doc_csp.onerror = function() {
+ ok(false, "sanity: doc_csp onerror should not fire");
+}
+doc_csp.onload = function() {
+ ok(true, "sanity: doc_csp onload should fire");
+ compareSVGs();
+}
+doc_csp.src = "file_svg_inline_style_server.sjs?svg_inline_style_csp&6";
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_uir_top_nav.html b/dom/security/test/csp/test_uir_top_nav.html
new file mode 100644
index 0000000000..57005ba6f9
--- /dev/null
+++ b/dom/security/test/csp/test_uir_top_nav.html
@@ -0,0 +1,53 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 1391011: Test uir for toplevel navigations</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<iframe style="width:100%;" id="testframe"></iframe>
+
+<script class="testbody" type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+
+/* Description of the test:
+ * We load an https page which defines upgrade-insecure-requests into an iframe
+ * and perform a same origin and a cross origin toplevel load and make sure that
+ * upgrade-insecure-requests applies to the same origin load.
+ */
+
+let totalTests = 2;
+let testCounter = 0;
+
+function checkResults(aResult) {
+ ok(aResult == "https://example.com/tests/dom/security/test/csp/file_uir_top_nav_dummy.html" ||
+ aResult == "http://test1.example.com/tests/dom/security/test/csp/file_uir_top_nav_dummy.html",
+ "same origin should be upgraded to https, cross origin should remain http");
+ if (++testCounter < totalTests) {
+ return;
+ }
+ window.removeEventListener("message", receiveMessage);
+ SimpleTest.finish();
+}
+
+window.addEventListener("message", receiveMessage);
+function receiveMessage(event) {
+ checkResults(event.data.result);
+}
+
+function startTest() {
+ document.getElementById("testframe").src =
+ "https://example.com/tests/dom/security/test/csp/file_uir_top_nav.html";
+}
+
+// Don't upgrade to https to test that upgrade-insecure-requests acts correctly and
+// start test
+SpecialPowers.pushPrefEnv({ set: [
+ ["dom.security.https_first", false]
+ ]}, startTest);
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_uir_windowwatcher.html b/dom/security/test/csp/test_uir_windowwatcher.html
new file mode 100644
index 0000000000..f16b3c93a6
--- /dev/null
+++ b/dom/security/test/csp/test_uir_windowwatcher.html
@@ -0,0 +1,31 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Bug 1529893 - Test upgrade-insecure-requests for opening window through nsWindowWatcher</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+
+<iframe name='frameA' width="100%" src="http://example.com/tests/dom/security/test/csp/file_windowwatcher_frameA.html"></iframe>
+
+<script class="testbody" type="text/javascript">
+
+// The CSP of subframe C should cause the window to be opened to be upgraded from http to https.
+
+SimpleTest.waitForExplicitFinish();
+
+let finalURI = "https://example.com/tests/dom/security/test/csp/file_windowwatcher_win_open.html";
+
+window.addEventListener("message", receiveMessage);
+
+function receiveMessage(event) {
+ is(event.data.result, finalURI, "opened window correctly upgraded to https");
+ window.removeEventListener("message", receiveMessage);
+ SimpleTest.finish();
+}
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_upgrade_insecure.html b/dom/security/test/csp/test_upgrade_insecure.html
new file mode 100644
index 0000000000..b0dcdeefd4
--- /dev/null
+++ b/dom/security/test/csp/test_upgrade_insecure.html
@@ -0,0 +1,192 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Bug 1139297 - Implement CSP upgrade-insecure-requests directive</title>
+ <!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<iframe style="width:100%;" id="testframe"></iframe>
+
+<script class="testbody" type="text/javascript">
+
+/* Description of the test:
+ * We load resources (img, script, sytle, etc) over *http* and make sure
+ * that all the resources get upgraded to use >> https << when the
+ * csp-directive "upgrade-insecure-requests" is specified. We further
+ * test that subresources within nested contexts (iframes) get upgraded
+ * and also test the handling of server side redirects.
+ *
+ * In detail:
+ * We perform an XHR request to the *.sjs file which is processed async on
+ * the server and waits till all the requests were processed by the server.
+ * Once the server received all the different requests, the server responds
+ * to the initial XHR request with an array of results which must match
+ * the expected results from each test, making sure that all requests
+ * received by the server (*.sjs) were actually *https* requests.
+ */
+
+const { AppConstants } = SpecialPowers.ChromeUtils.import(
+ "resource://gre/modules/AppConstants.jsm"
+);
+
+const UPGRADE_POLICY =
+ "upgrade-insecure-requests;" + // upgrade all http requests to https
+ "block-all-mixed-content;" + // upgrade should be enforced before block-all.
+ "default-src https: wss: 'unsafe-inline';" + // only allow https: and wss:
+ "form-action https:;"; // explicit, no fallback to default-src
+
+const UPGRADE_POLICY_NO_DEFAULT_SRC =
+ "upgrade-insecure-requests;" + // upgrade all http requests to https
+ "script-src 'unsafe-inline' *"; // we have to allowlist the inline scripts
+ // in the test.
+const NO_UPGRADE_POLICY =
+ "default-src http: ws: 'unsafe-inline';" + // allow http:// and ws://
+ "form-action http:;"; // explicit, no fallback to default-src
+
+var tests = [
+ { // (1) test that all requests within an >> https << page get updated
+ policy: UPGRADE_POLICY,
+ topLevelScheme: "https://",
+ description: "upgrade all requests on toplevel https",
+ deliveryMethod: "header",
+ results: [
+ "iframe-ok", "script-ok", "img-ok", "img-redir-ok", "font-ok", "xhr-ok", "style-ok",
+ "media-ok", "object-ok", "form-ok", "nested-img-ok"
+ ]
+ },
+ { // (2) test that all requests within an >> http << page get updated
+ policy: UPGRADE_POLICY,
+ topLevelScheme: "http://",
+ description: "upgrade all requests on toplevel http",
+ deliveryMethod: "header",
+ results: [
+ "iframe-ok", "script-ok", "img-ok", "img-redir-ok", "font-ok", "xhr-ok", "style-ok",
+ "media-ok", "object-ok", "form-ok", "nested-img-ok"
+ ]
+ },
+ { // (3) test that all requests within an >> http << page get updated, but do
+ // not specify a default-src directive.
+ policy: UPGRADE_POLICY_NO_DEFAULT_SRC,
+ topLevelScheme: "http://",
+ description: "upgrade all requests on toplevel http where default-src is not specified",
+ deliveryMethod: "header",
+ results: [
+ "iframe-ok", "script-ok", "img-ok", "img-redir-ok", "font-ok", "xhr-ok", "style-ok",
+ "media-ok", "object-ok", "form-ok", "nested-img-ok"
+ ]
+ },
+ { // (4) test that no requests get updated if >> upgrade-insecure-requests << is not used
+ policy: NO_UPGRADE_POLICY,
+ topLevelScheme: "http://",
+ description: "do not upgrade any requests on toplevel http",
+ deliveryMethod: "header",
+ results: [
+ "iframe-error", "script-error", "img-error", "img-redir-error", "font-error",
+ "xhr-error", "style-error", "media-error", "object-error", "form-error",
+ "nested-img-error"
+ ]
+ },
+ { // (5) test that all requests within an >> https << page using meta CSP get updated
+ // policy: UPGRADE_POLICY, that test uses UPGRADE_POLICY within
+ // file_upgrade_insecure_meta.html
+ // no need to define it within that object.
+ topLevelScheme: "https://",
+ description: "upgrade all requests on toplevel https using meta csp",
+ deliveryMethod: "meta",
+ results: [
+ "iframe-ok", "script-ok", "img-ok", "img-redir-ok", "font-ok", "xhr-ok", "style-ok",
+ "media-ok", "object-ok", "form-ok", "nested-img-ok"
+ ]
+ },
+];
+
+// TODO: WebSocket tests are not supported on Android Yet. Bug 1566168.
+if (AppConstants.platform !== "android") {
+ for (let test of tests) {
+ test.results.push(test.results[0] == "iframe-ok" ? "websocket-ok" : "websocket-error");
+ }
+}
+
+var counter = 0;
+var curTest;
+
+function loadTestPage() {
+ curTest = tests[counter++];
+ var src = curTest.topLevelScheme + "example.com/tests/dom/security/test/csp/file_testserver.sjs?file=";
+ if (curTest.deliveryMethod === "header") {
+ // append the file that should be served
+ src += escape("tests/dom/security/test/csp/file_upgrade_insecure.html");
+ // append the CSP that should be used to serve the file
+ src += "&csp=" + escape(curTest.policy);
+ }
+ else {
+ src += escape("tests/dom/security/test/csp/file_upgrade_insecure_meta.html");
+ // no csp here, since it's in the meta element
+ }
+ document.getElementById("testframe").src = src;
+}
+
+function finishTest() {
+ window.removeEventListener("message", receiveMessage);
+ SimpleTest.finish();
+}
+
+function checkResults(result) {
+ // try to find the expected result within the results array
+ var index = curTest.results.indexOf(result);
+ isnot(index, -1, curTest.description + " (result: " + result + ")");
+
+ // take the element out the array and continue till the results array is empty
+ if (index != -1) {
+ curTest.results.splice(index, 1);
+ }
+ // lets check if we are expecting more results to bubble up
+ if (curTest.results.length) {
+ return;
+ }
+ // lets see if we ran all the tests
+ if (counter == tests.length) {
+ finishTest();
+ return;
+ }
+ // otherwise it's time to run the next test
+ runNextTest();
+}
+
+// a postMessage handler that is used by sandboxed iframes without
+// 'allow-same-origin' to bubble up results back to this main page.
+window.addEventListener("message", receiveMessage);
+function receiveMessage(event) {
+ checkResults(event.data.result);
+}
+
+function runNextTest() {
+ // sends an xhr request to the server which is processed async, which only
+ // returns after the server has received all the expected requests.
+ var myXHR = new XMLHttpRequest();
+ myXHR.open("GET", "file_upgrade_insecure_server.sjs?queryresult");
+ myXHR.onload = function(e) {
+ var results = myXHR.responseText.split(",");
+ for (var index in results) {
+ checkResults(results[index]);
+ }
+ }
+ myXHR.onerror = function(e) {
+ ok(false, "could not query results from server (" + e.message + ")");
+ finishTest();
+ }
+ myXHR.send();
+
+ // give it some time and run the testpage
+ SimpleTest.executeSoon(loadTestPage);
+}
+
+SimpleTest.waitForExplicitFinish();
+runNextTest();
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_upgrade_insecure_cors.html b/dom/security/test/csp/test_upgrade_insecure_cors.html
new file mode 100644
index 0000000000..3ed53d8108
--- /dev/null
+++ b/dom/security/test/csp/test_upgrade_insecure_cors.html
@@ -0,0 +1,86 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Bug 1139297 - Implement CSP upgrade-insecure-requests directive</title>
+ <!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<iframe style="width:100%;" id="testframe"></iframe>
+
+<script class="testbody" type="text/javascript">
+
+/* Description of the test:
+ * We load a page serving two XHR requests (including being redirected);
+ * one that should not require CORS and one that should require cors, in particular:
+ *
+ * Test 1:
+ * Main page: https://test1.example.com
+ * XHR request: http://test1.example.com
+ * Redirect to: http://test1.example.com
+ * Description: Upgrade insecure should upgrade from http to https and also
+ * surpress CORS for that case.
+ *
+ * Test 2:
+ * Main page: https://test1.example.com
+ * XHR request: http://test1.example.com
+ * Redirect to: http://test1.example.com:443
+ * Description: Upgrade insecure should upgrade from http to https and also
+ * prevent CORS for that case.
+ * Note: If redirecting to a different port, then CORS *should* be enforced (unless
+ * it's port 443). Unfortunately we can't test that because of the setup of our
+ * *.sjs files; they only are able to listen to port 443, see:
+ * http://mxr.mozilla.org/mozilla-central/source/build/pgo/server-locations.txt#98
+ *
+ * Test 3:
+ * Main page: https://test1.example.com
+ * XHR request: http://test2.example.com
+ * Redirect to: http://test1.example.com
+ * Description: Upgrade insecure should *not* prevent CORS since
+ * the page performs a cross origin xhr.
+ *
+ */
+
+const CSP_POLICY = "upgrade-insecure-requests; script-src 'unsafe-inline'";
+var tests = 3;
+
+function loadTest() {
+ var src = "https://test1.example.com/tests/dom/security/test/csp/file_testserver.sjs?file=";
+ // append the file that should be served
+ src += escape("tests/dom/security/test/csp/file_upgrade_insecure_cors.html")
+ // append the CSP that should be used to serve the file
+ src += "&csp=" + escape(CSP_POLICY);
+ document.getElementById("testframe").src = src;
+}
+
+function checkResult(result) {
+ if (result === "test1-no-cors-ok" ||
+ result === "test2-no-cors-diffport-ok" ||
+ result === "test3-cors-ok") {
+ ok(true, "'upgrade-insecure-requests' acknowledges CORS (" + result + ")");
+ }
+ else {
+ ok(false, "'upgrade-insecure-requests' acknowledges CORS (" + result + ")");
+ }
+ if (--tests > 0) {
+ return;
+ }
+ window.removeEventListener("message", receiveMessage);
+ SimpleTest.finish();
+}
+
+// a postMessage handler that is used to bubble up results from
+// within the iframe.
+window.addEventListener("message", receiveMessage);
+function receiveMessage(event) {
+ checkResult(event.data);
+}
+
+SimpleTest.waitForExplicitFinish();
+loadTest();
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_upgrade_insecure_docwrite_iframe.html b/dom/security/test/csp/test_upgrade_insecure_docwrite_iframe.html
new file mode 100644
index 0000000000..dc6039ec35
--- /dev/null
+++ b/dom/security/test/csp/test_upgrade_insecure_docwrite_iframe.html
@@ -0,0 +1,54 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Bug 1273430 - Test CSP upgrade-insecure-requests for doc.write(iframe)</title>
+ <!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<iframe style="width:100%;" id="testframe"></iframe>
+
+<script class="testbody" type="text/javascript">
+
+/* Description of the test:
+ * Load an iframe which ships with a CSP of upgrade-insecure-requests.
+ * Within that iframe a script performs doc.write(iframe) using an
+ * *http* URL. Make sure, the URL is upgraded to *https*.
+ *
+ * +-----------------------------------------+
+ * | |
+ * | http(s); csp: upgrade-insecure-requests | |
+ * | +---------------------------------+ |
+ * | | | |
+ * | | doc.write(<iframe src='http'>); | <--------- upgrade to https
+ * | | | |
+ * | +---------------------------------+ |
+ * | |
+ * +-----------------------------------------+
+ *
+ */
+
+const TEST_FRAME_URL =
+ "https://example.com/tests/dom/security/test/csp/file_upgrade_insecure_docwrite_iframe.sjs?testframe";
+
+// important: the RESULT should have a scheme of *https*
+const RESULT =
+ "https://example.com/tests/dom/security/test/csp/file_upgrade_insecure_docwrite_iframe.sjs?docwriteframe";
+
+window.addEventListener("message", receiveMessage);
+function receiveMessage(event) {
+ is(event.data.result, RESULT, "doc.write(iframe) of http should be upgraded to https!");
+ window.removeEventListener("message", receiveMessage);
+ SimpleTest.finish();
+}
+
+// start the test
+SimpleTest.waitForExplicitFinish();
+var testframe = document.getElementById("testframe");
+testframe.src = TEST_FRAME_URL;
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_upgrade_insecure_loopback.html b/dom/security/test/csp/test_upgrade_insecure_loopback.html
new file mode 100644
index 0000000000..f72f95215e
--- /dev/null
+++ b/dom/security/test/csp/test_upgrade_insecure_loopback.html
@@ -0,0 +1,91 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Bug 1447784 - Implement CSP upgrade-insecure-requests directive</title>
+ <!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<iframe style="width:100%;" id="testframe"></iframe>
+
+<script class="testbody" type="text/javascript">
+
+/* Description of the test:
+ * We load a page that performs a CORS XHR to 127.0.0.1 which shouldn't be upgraded to https:
+ *
+ * Test 1:
+ * Main page: https://127.0.0.1:8080
+ * XHR request: http://127.0.0.1:8080
+ * No redirect to https://
+ * Description: Upgrade insecure should *NOT* upgrade from http to https.
+ */
+
+const CSP_POLICY = "upgrade-insecure-requests; script-src 'unsafe-inline'";
+let testFiles = ["tests/dom/security/test/csp/file_upgrade_insecure_loopback.html",
+ "tests/dom/security/test/csp/file_upgrade_insecure_loopback_form.html"];
+
+function examiner() {
+ SpecialPowers.addObserver(this, "specialpowers-http-notify-request");
+}
+examiner.prototype = {
+ observe(subject, topic, data) {
+ if (topic === "specialpowers-http-notify-request") {
+ // we skip looking at other requests that might be observed accidentally
+ // e.g., we saw kinto requests when running this test locally
+ if (data.includes("bug-1661423-dont-upgrade-localhost")) {
+ let urlObj = new URL(data);
+ is(urlObj.protocol, "http:", "Didn't upgrade localhost URL");
+ loadTest();
+ }
+ }
+ },
+ remove() {
+ SpecialPowers.removeObserver(this, "specialpowers-http-notify-request");
+ }
+};
+
+window.examiner = new examiner();
+
+
+function loadTest() {
+ if (!testFiles.length) {
+ removeAndFinish();
+ return;
+ }
+ var src = "https://example.com/tests/dom/security/test/csp/file_testserver.sjs?file=";
+ // append the file that should be served
+ src += escape(testFiles.shift())
+ // append the CSP that should be used to serve the file
+ src += "&csp=" + escape(CSP_POLICY);
+ document.getElementById("testframe").src = src;
+}
+
+function removeAndFinish() {
+ window.removeEventListener("message", receiveMessage);
+ window.examiner.remove();
+ SimpleTest.finish();
+}
+
+// a postMessage handler that is used to bubble up results from
+// within the iframe.
+window.addEventListener("message", receiveMessage);
+function receiveMessage(event) {
+ if (event.data === "request-not-https") {
+ ok(true, "Didn't upgrade 127.0.0.1:8080 to https://");
+ loadTest();
+ }
+}
+
+SimpleTest.waitForExplicitFinish();
+
+// By default, proxies don't apply to 127.0.0.1.
+// We need them to for this test (at least on android), though:
+SpecialPowers.pushPrefEnv({set: [
+ ["network.proxy.allow_hijacking_localhost", true]
+]}).then(loadTest);
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_upgrade_insecure_navigation.html b/dom/security/test/csp/test_upgrade_insecure_navigation.html
new file mode 100644
index 0000000000..5694deb15a
--- /dev/null
+++ b/dom/security/test/csp/test_upgrade_insecure_navigation.html
@@ -0,0 +1,105 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 1271173 - Missing spec on Upgrade Insecure Requests(Navigational Upgrades) </title>
+ <!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<iframe style="width:100%;" id="testframe"></iframe>
+<iframe style="width:100%;" id="sandboxedtestframe"
+ sandbox="allow-scripts allow-top-navigation allow-same-origin allow-pointer-lock allow-popups"></iframe>
+
+<script class="testbody" type="text/javascript">
+/*
+ * Description of the test:
+ * We load a page into an iframe that performs a navigational request.
+ * We make sure that upgrade-insecure-requests applies and the page
+ * gets upgraded to https if same origin.
+ * Please note that uir only applies to sandboxed iframes if
+ * the value 'allow-same-origin' is specified.
+ */
+
+SimpleTest.waitForExplicitFinish();
+
+var tests = [
+ {
+ csp: "upgrade-insecure-requests;",
+ result: "https",
+ origin: "http://example.com",
+ desc: "upgrade-insecure-requests same origin should upgrade"
+ },
+ {
+ csp: "",
+ result: "http",
+ origin: "http://example.com",
+ desc: "No upgrade-insecure-requests same origin should not upgrade"
+ },
+ {
+ csp: "upgrade-insecure-requests;",
+ result: "http",
+ origin: "http://mochi.test:8888",
+ desc: "upgrade-insecure-requests cross origin should not upgrade"
+ },
+ {
+ csp: "",
+ result: "http",
+ origin: "http://mochi.test:8888",
+ desc: "No upgrade-insecure-requests cross origin should not upgrade"
+ },
+];
+
+// initializing to -1 so we start at index 0 when we start the test
+var counter = -1;
+
+function finishTest() {
+ window.removeEventListener("message", receiveMessage);
+ SimpleTest.finish();
+}
+
+var subtests = 0;
+
+window.addEventListener("message", receiveMessage);
+function receiveMessage(event) {
+ var result = event.data.result;
+ // query the scheme from the URL before comparing the result
+ var scheme = result.substring(0, result.indexOf(":"));
+ is(scheme, tests[counter].result, tests[counter].desc);
+
+ // @hardcoded 4:
+ // each test run contains of two subtests (frame and top-level)
+ // and we load each test into a regular iframe and into a
+ // sandboxed iframe. only move on to the next test once all
+ // four results from the subtests have bubbled up.
+ subtests++;
+ if (subtests != 4) {
+ return;
+ }
+ subtests = 0;
+ loadNextTest();
+}
+
+function loadNextTest() {
+ counter++;
+ if (counter == tests.length) {
+ finishTest();
+ return;
+ }
+
+ var src = tests[counter].origin;
+ src += "/tests/dom/security/test/csp/file_upgrade_insecure_navigation.sjs";
+ src += "?csp=" + escape(tests[counter].csp);
+ src += "&action=perform_navigation";
+ document.getElementById("testframe").src = src;
+ document.getElementById("sandboxedtestframe").src = src;
+}
+// Don't upgrade to https to test that upgrade-insecure-requests acts correctly
+// start running the tests
+SpecialPowers.pushPrefEnv({
+ set: [["dom.security.https_first", false]]
+}, loadNextTest);
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_upgrade_insecure_navigation_redirect.html b/dom/security/test/csp/test_upgrade_insecure_navigation_redirect.html
new file mode 100644
index 0000000000..af25577cbb
--- /dev/null
+++ b/dom/security/test/csp/test_upgrade_insecure_navigation_redirect.html
@@ -0,0 +1,67 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 1422284 - Upgrade insecure requests should only apply to top-level same-origin redirects </title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<iframe id="redirect_same_origin_frame"></iframe>
+<iframe id="redirect_cross_origin_frame"></iframe>
+
+<script class="testbody" type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+
+let testCounter = 0;
+
+function checkFinished() {
+ // hardcoded 2 because we have a same-origin and a cross-origin test
+ if (++testCounter == 2) {
+ window.removeEventListener("message", receiveMessage);
+ SimpleTest.finish();
+ return;
+ }
+}
+
+window.addEventListener("message", receiveMessage);
+function receiveMessage(event) {
+ let docURI = event.data.docURI;
+ let url = docURI.split('?')[0];
+ let query = docURI.split('?')[1];
+
+ if (query === "finaldoc_same_origin_redirect") {
+ // scheme schould be https
+ is (
+ url,
+ "https://example.com/tests/dom/security/test/csp/file_upgrade_insecure_navigation_redirect.sjs",
+ "upgrade-insecure-requests same origin redirect should upgrade",
+ );
+ }
+ else if (query === "finaldoc_cross_origin_redirect") {
+ // scheme schould be http
+ is (
+ url,
+ "http://test1.example.com/tests/dom/security/test/csp/file_upgrade_insecure_navigation_redirect.sjs",
+ "upgrade-insecure-requests cross origin redirect should not upgrade",
+ );
+ }
+ else {
+ ok(false, "sanity: how can we ever get here?");
+ }
+ checkFinished();
+}
+
+function startTest() {
+ document.getElementById("redirect_same_origin_frame").src =
+ "http://example.com/tests/dom/security/test/csp/file_upgrade_insecure_navigation_redirect_same_origin.html";
+ document.getElementById("redirect_cross_origin_frame").src =
+ "http://example.com/tests/dom/security/test/csp/file_upgrade_insecure_navigation_redirect_cross_origin.html";
+}
+
+// do not upgrade tests by https-first, only by UIR for this test
+SpecialPowers.pushPrefEnv({ set: [["dom.security.https_first", false]]}, startTest);
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_upgrade_insecure_reporting.html b/dom/security/test/csp/test_upgrade_insecure_reporting.html
new file mode 100644
index 0000000000..4966b8627e
--- /dev/null
+++ b/dom/security/test/csp/test_upgrade_insecure_reporting.html
@@ -0,0 +1,69 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Bug 1139297 - Implement CSP upgrade-insecure-requests directive</title>
+ <!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<iframe style="width:100%;" id="testframe"></iframe>
+
+<script class="testbody" type="text/javascript">
+
+/* Description of the test:
+ * We load an https page which includes an http image. We make sure that
+ * the image request gets upgraded to https but also make sure that a report
+ * is sent when a CSP report only is used which only allows https requests.
+ */
+
+var expectedResults = 2;
+
+function finishTest() {
+ // let's wait till the image was loaded and the report was received
+ if (--expectedResults > 0) {
+ return;
+ }
+ window.removeEventListener("message", receiveMessage);
+ SimpleTest.finish();
+}
+
+function runTest() {
+ // (1) Lets send off an XHR request which will return once the server receives
+ // the violation report from the report only policy.
+ var myXHR = new XMLHttpRequest();
+ myXHR.open("GET", "file_upgrade_insecure_reporting_server.sjs?queryresult");
+ myXHR.onload = function(e) {
+ is(myXHR.responseText, "report-ok", "csp-report was sent correctly");
+ finishTest();
+ }
+ myXHR.onerror = function(e) {
+ ok(false, "could not query result for csp-report from server (" + e.message + ")");
+ finishTest();
+ }
+ myXHR.send();
+
+ // (2) We load a page that is served using a CSP and a CSP report only which loads
+ // an image over http.
+ SimpleTest.executeSoon(function() {
+ document.getElementById("testframe").src =
+ "https://example.com/tests/dom/security/test/csp/file_upgrade_insecure_reporting_server.sjs?toplevel";
+ });
+}
+
+// a postMessage handler that is used by sandboxed iframes without
+// 'allow-same-origin' to bubble up results back to this main page.
+window.addEventListener("message", receiveMessage);
+function receiveMessage(event) {
+ // (3) make sure the image was correctly loaded
+ is(event.data.result, "img-ok", "upgraded insecure image load from http -> https");
+ finishTest();
+}
+
+SimpleTest.waitForExplicitFinish();
+runTest();
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_websocket_localhost.html b/dom/security/test/csp/test_websocket_localhost.html
new file mode 100644
index 0000000000..6bcc93fceb
--- /dev/null
+++ b/dom/security/test/csp/test_websocket_localhost.html
@@ -0,0 +1,40 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Bug 1729897: Allow unsecure websocket from localhost page with CSP: upgrade-insecure </title>
+ <!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<iframe style="width:100%;" id="test_ws_self_frame"></iframe>
+
+<script class="testbody" type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+
+function finishTest() {
+ window.removeEventListener("message", receiveMessage);
+ SimpleTest.finish();
+}
+
+window.addEventListener("message", receiveMessage);
+function receiveMessage(event) {
+ is(event.data.result, "self-ws-loaded", "websocket loaded");
+ ok(event.data.url.startsWith("ws://"), `scheme must be ws:// but got ${event.data.url}`);
+ finishTest();
+}
+
+SpecialPowers.pushPrefEnv({set: [
+ ["network.proxy.allow_hijacking_localhost", true],
+ ["network.proxy.testing_localhost_is_secure_when_hijacked", true],
+]}).then(function() {
+ const HOST = "http://localhost/tests/dom/security/test/csp/";
+ var test_ws_self_frame = document.getElementById("test_ws_self_frame");
+ test_ws_self_frame.src = HOST + "file_websocket_csp_upgrade.html";
+});
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_websocket_self.html b/dom/security/test/csp/test_websocket_self.html
new file mode 100644
index 0000000000..3eae83bfbf
--- /dev/null
+++ b/dom/security/test/csp/test_websocket_self.html
@@ -0,0 +1,61 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Bug 1345615: Allow websocket schemes when using 'self' in CSP</title>
+ <!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<iframe style="width:100%;" id="test_ws_self_frame"></iframe>
+<iframe style="width:100%;" id="test_ws_explicit_frame"></iframe>
+
+<script class="testbody" type="text/javascript">
+
+/* Description of the test:
+ * We load an iframe using connect-src 'self' and one
+ * iframe using connect-src ws: and make
+ * sure that in both cases ws: as well as wss: is allowed to load.
+ */
+
+SimpleTest.waitForExplicitFinish();
+
+function finishTest() {
+ window.removeEventListener("message", receiveMessage);
+ SimpleTest.finish();
+}
+
+const TOTAL_TESTS = 4;
+var counter = 0;
+
+function checkResults(result) {
+ counter++;
+ if (result === "self-ws-loaded" || result === "self-wss-loaded" ||
+ result === "explicit-ws-loaded" || result === "explicit-wss-loaded") {
+ ok(true, "Evaluating: " + result);
+ }
+ else {
+ ok(false, "Evaluating: " + result);
+ }
+ if (counter < TOTAL_TESTS) {
+ return;
+ }
+ finishTest();
+}
+
+window.addEventListener("message", receiveMessage);
+function receiveMessage(event) {
+ checkResults(event.data.result);
+}
+
+const HOST = "http://example.com/tests/dom/security/test/csp/";
+var test_ws_self_frame = document.getElementById("test_ws_self_frame");
+test_ws_self_frame.src = HOST + "file_websocket_self.html";
+
+var test_ws_explicit_frame = document.getElementById("test_ws_explicit_frame");
+test_ws_explicit_frame.src = HOST + "file_websocket_explicit.html";
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_win_open_blocked.html b/dom/security/test/csp/test_win_open_blocked.html
new file mode 100644
index 0000000000..1335c9d272
--- /dev/null
+++ b/dom/security/test/csp/test_win_open_blocked.html
@@ -0,0 +1,52 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <!-- we have to allowlist the actual script that spawns the tests,
+ hence the nonce.-->
+ <meta http-equiv="Content-Security-Policy" content="default-src 'none';
+ script-src 'nonce-foo'; style-src 'nonce-foo'">
+ <script nonce="foo" src="/tests/SimpleTest/SimpleTest.js">
+ </script>
+ <link nonce="foo" rel="stylesheet" type="text/css"
+ href="/tests/SimpleTest/test.css"/>
+ <!-- this script block with window.open and document.open will not
+ be executed, since default-src is none -->
+ <script>
+ let win = window.open('file_default_src_none_csp.html');
+ document.open();
+ document.write("<script type='application/javascript'>" +
+ " window.opener.postMessage('document-opened', '*');" +
+ "<\/script>");
+ document.close();
+ </script>
+ <script nonce="foo">
+ SimpleTest.waitForExplicitFinish();
+ SimpleTest.requestFlakyTimeout("have to test that opening a " +
+ "new window/document has not succeeded");
+ window.addEventListener("message", receiveMessage);
+ let checkWindowStatus = false;
+ let checkDocumentStatus = false;
+
+ function receiveMessage(event) {
+ window.removeEventListener("message", receiveMessage);
+ if (event.data == "window-opened") {
+ checkWindowStatus = true;
+ win.close();
+ }
+ if (event.data == "document-opened") {
+ checkDocumentStatus = true;
+ doc.close();
+ }
+ }
+ setTimeout(function () {
+ is(checkWindowStatus, false,
+ "window shouldn't be opened");
+ is(checkDocumentStatus, false,
+ "document shouldn't be opened");
+ SimpleTest.finish();
+ }, 1500);
+ </script>
+</head>
+<body>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_worker_src.html b/dom/security/test/csp/test_worker_src.html
new file mode 100644
index 0000000000..5aa8f7bc56
--- /dev/null
+++ b/dom/security/test/csp/test_worker_src.html
@@ -0,0 +1,105 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Bug 1302667 - Test worker-src</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<iframe style="width:100%;" id="testframe"></iframe>
+
+<script class="testbody" type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+SimpleTest.requestLongerTimeout(3);
+
+/* Description of the test:
+ * We load a page inlcuding a worker, a shared worker as well as a
+ * service worker with a CSP of:
+ * >> worker-src https://example.com; child-src 'none'; script-src 'nonce-foo'
+ * and make sure that worker-src governs these three kinds of workers correctly.
+ * In addition, we make sure that child-src as well as script-src is discarded
+ * in case worker-src is specified. Ideally we would use "script-src 'none'" but
+ * we have to allowlist the actual script that spawns the workers, hence the nonce.
+ */
+
+let ALLOWED_HOST = "https://example.com/tests/dom/security/test/csp/";
+let BLOCKED_HOST = "https://test1.example.com/tests/dom/security/test/csp/";
+
+let TESTS = [
+ // allowed
+ ALLOWED_HOST + "file_worker_src_worker_governs.html",
+ ALLOWED_HOST + "file_worker_src_child_governs.html",
+ ALLOWED_HOST + "file_worker_src_script_governs.html",
+ // blocked
+ BLOCKED_HOST + "file_worker_src_worker_governs.html",
+ BLOCKED_HOST + "file_worker_src_child_governs.html",
+ BLOCKED_HOST + "file_worker_src_script_governs.html",
+];
+
+let numberSubTests = 3; // 1 web worker, 1 shared worker, 1 service worker
+let subTestCounter = 0; // keeps track of how many
+let testIndex = 0;
+
+function checkFinish() {
+ subTestCounter = 0;
+ testIndex++;
+ if (testIndex < TESTS.length) {
+ runNextTest();
+ return;
+ }
+ window.removeEventListener("message", receiveMessage);
+ SimpleTest.finish();
+}
+
+window.addEventListener("message", receiveMessage);
+function receiveMessage(event) {
+ let href = event.data.href;
+ let result = event.data.result;
+
+ if (href.startsWith("https://example.com")) {
+ if (result == "worker-allowed" ||
+ result == "shared-worker-allowed" ||
+ result == "service-worker-allowed") {
+ ok(true, "allowing worker from https://example.com (" + result + ")");
+ }
+ else {
+ ok(false, "blocking worker from https://example.com (" + result + ")");
+ }
+ }
+ else if (href.startsWith("https://test1.example.com")) {
+ if (result == "worker-blocked" ||
+ result == "shared-worker-blocked" ||
+ result == "service-worker-blocked") {
+ ok(true, "blocking worker from https://test1.example.com (" + result + ")");
+ }
+ else {
+ ok(false, "allowing worker from https://test1.example.com (" + result + ")");
+ }
+ }
+ else {
+ // sanity check, we should never enter that branch, bust just in case...
+ ok(false, "unexpected result: " + result);
+ }
+ subTestCounter++;
+ if (subTestCounter < numberSubTests) {
+ return;
+ }
+ checkFinish();
+}
+
+function runNextTest() {
+ document.getElementById("testframe").src = TESTS[testIndex];
+}
+
+SpecialPowers.pushPrefEnv({"set": [
+ ["dom.serviceWorkers.enabled", true],
+ ["dom.serviceWorkers.testing.enabled", true],
+]}, function() {
+ runNextTest();
+});
+
+</script>
+</body>
+</html>
diff --git a/dom/security/test/csp/test_xslt_inherits_csp.html b/dom/security/test/csp/test_xslt_inherits_csp.html
new file mode 100644
index 0000000000..90e8372db1
--- /dev/null
+++ b/dom/security/test/csp/test_xslt_inherits_csp.html
@@ -0,0 +1,33 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Bug 1597645: Make sure XSLT inherits the CSP r=ckerschb</title>
+ <!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<body>
+ <iframe src="file_xslt_inherits_csp.xml"></iframe>
+
+<script class="testbody">
+ SimpleTest.requestCompleteLog();
+ SimpleTest.waitForExplicitFinish();
+
+ let frame = document.querySelector("iframe");
+
+ window.addEventListener("load",()=>{
+ let link = frame.contentWindow.document.querySelector("a");
+ link.click(); //
+
+ requestAnimationFrame(()=>{
+ // Wait one Frame to let the browser catch up
+ // before checking the dom.
+ let res = !frame.contentWindow.document.body.innerText.includes("JS DID EXCECUTE");
+ ok(res, "The CSP did block injected JS ");
+ SimpleTest.finish();
+ });
+ })
+</script>
+</html>
diff --git a/dom/security/test/csp/worker.sjs b/dom/security/test/csp/worker.sjs
new file mode 100644
index 0000000000..e85df3382a
--- /dev/null
+++ b/dom/security/test/csp/worker.sjs
@@ -0,0 +1,114 @@
+Components.utils.importGlobalProperties(["URLSearchParams"]);
+
+const SJS = "http://mochi.test:8888/tests/dom/security/test/csp/worker.sjs";
+
+function createFetchWorker(url) {
+ return `fetch("${url}");`;
+}
+
+function createXHRWorker(url) {
+ return `
+ try {
+ var xhr = new XMLHttpRequest();
+ xhr.open("GET", "${url}");
+ xhr.send();
+ } catch(ex) {}
+ `;
+}
+
+function createImportScriptsWorker(url) {
+ return `
+ try {
+ importScripts("${url}");
+ } catch(ex) {}
+ `;
+}
+
+function createChildWorkerURL(params) {
+ let url = SJS + "?" + params.toString();
+ return `new Worker("${url}");`;
+}
+
+function createChildWorkerBlob(params) {
+ let url = SJS + "?" + params.toString();
+ return `
+ try {
+ var xhr = new XMLHttpRequest();
+ xhr.open("GET", "${url}");
+ xhr.responseType = "blob";
+ xhr.send();
+ xhr.onload = () => {
+ new Worker(URL.createObjectURL(xhr.response));};
+ } catch(ex) {}
+ `;
+}
+
+function handleRequest(request, response) {
+ let params = new URLSearchParams(request.queryString);
+
+ let id = params.get("id");
+ let base = unescape(params.get("base"));
+ let child = params.has("child") ? params.get("child") : "";
+
+ //avoid confusing cache behaviors
+ response.setHeader("Cache-Control", "no-cache", false);
+ response.setHeader("Content-Type", "application/javascript");
+
+ // Deliver the CSP policy encoded in the URL
+ if (params.has("csp")) {
+ response.setHeader(
+ "Content-Security-Policy",
+ unescape(params.get("csp")),
+ false
+ );
+ }
+
+ if (child) {
+ let childCsp = params.has("childCsp") ? params.get("childCsp") : "";
+ params.delete("csp");
+ params.delete("child");
+ params.delete("childCsp");
+ params.append("csp", childCsp);
+
+ switch (child) {
+ case "blob":
+ response.write(createChildWorkerBlob(params));
+ break;
+
+ case "url":
+ response.write(createChildWorkerURL(params));
+ break;
+
+ default:
+ response.setStatusLine(request.httpVersion, 400, "Bad request");
+ break;
+ }
+
+ return;
+ }
+
+ if (params.has("action")) {
+ switch (params.get("action")) {
+ case "fetch":
+ response.write(createFetchWorker(base + "?id=" + id));
+ break;
+
+ case "xhr":
+ response.write(createXHRWorker(base + "?id=" + id));
+ break;
+
+ case "importScripts":
+ response.write(createImportScriptsWorker(base + "?id=" + id));
+ break;
+
+ default:
+ response.setStatusLine(request.httpVersion, 400, "Bad request");
+ break;
+ }
+
+ return;
+ }
+
+ response.write("I don't know action ");
+ return;
+}
diff --git a/dom/security/test/csp/worker_helper.js b/dom/security/test/csp/worker_helper.js
new file mode 100644
index 0000000000..3cadec9ea1
--- /dev/null
+++ b/dom/security/test/csp/worker_helper.js
@@ -0,0 +1,91 @@
+/**
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+var _tests = [];
+function addTest(test) {
+ _tests.push(test);
+}
+
+function addAsyncTest(fn) {
+ _tests.push(() => fn().catch(ok.bind(null, false)));
+}
+
+function runNextTest() {
+ if (!_tests.length) {
+ SimpleTest.finish();
+ return;
+ }
+ const fn = _tests.shift();
+ try {
+ fn();
+ } catch (ex) {
+ info(
+ "Test function " +
+ (fn.name ? "'" + fn.name + "' " : "") +
+ "threw an exception: " +
+ ex
+ );
+ }
+}
+
+/**
+ * Helper to perform an XHR then blob response to create worker
+ */
+function doXHRGetBlob(uri) {
+ return new Promise(resolve => {
+ const xhr = new XMLHttpRequest();
+ xhr.open("GET", uri);
+ xhr.responseType = "blob";
+ xhr.addEventListener("load", function () {
+ is(
+ xhr.status,
+ 200,
+ "doXHRGetBlob load uri='" + uri + "' status=" + xhr.status
+ );
+ resolve(xhr.response);
+ });
+ xhr.send();
+ });
+}
+
+function removeObserver(observer) {
+ SpecialPowers.removeObserver(observer, "specialpowers-http-notify-request");
+ SpecialPowers.removeObserver(observer, "csp-on-violate-policy");
+}
+
+/**
+ * Helper to perform an assert to check if the request should be blocked or
+ * allowed by CSP
+ */
+function assertCSPBlock(url, shouldBlock) {
+ return new Promise((resolve, reject) => {
+ let observer = {
+ observe(subject, topic, data) {
+ if (topic === "specialpowers-http-notify-request") {
+ if (data == url) {
+ is(shouldBlock, false, "Should allow request uri='" + url);
+ removeObserver(observer);
+ resolve();
+ }
+ }
+
+ if (topic === "csp-on-violate-policy") {
+ let asciiSpec = SpecialPowers.getPrivilegedProps(
+ SpecialPowers.do_QueryInterface(subject, "nsIURI"),
+ "asciiSpec"
+ );
+ if (asciiSpec == url) {
+ is(shouldBlock, true, "Should block request uri='" + url);
+ removeObserver(observer);
+ resolve();
+ }
+ }
+ },
+ };
+
+ SpecialPowers.addObserver(observer, "csp-on-violate-policy");
+ SpecialPowers.addObserver(observer, "specialpowers-http-notify-request");
+ });
+}