tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit 791f95b9599dae1377c95f8e1d35683b40690cfb
parent 019c8e773605623871b7d4fd5a85e6ae7869abbb
Author: Maksim Sadym <69349599+sadym-chromium@users.noreply.github.com>
Date:   Wed, 15 Oct 2025 09:00:11 +0000

Bug 1994238 [wpt PR 55362] - [wdspec] `network.setExtraHeaders`, a=testonly

Automatic update from web-platform-tests
[wdspec] `network.setExtraHeaders` (#55362)

--

wpt-commits: 52ce9bf76911873a2c5c22d05a45aa262c91c675
wpt-pr: 55362

Diffstat:
Mtesting/web-platform/tests/webdriver/tests/bidi/network/set_extra_headers/__init__.py | 26++++++++++++++++++++++++++
Atesting/web-platform/tests/webdriver/tests/bidi/network/set_extra_headers/conftest.py | 130+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Atesting/web-platform/tests/webdriver/tests/bidi/network/set_extra_headers/contexts.py | 117+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Atesting/web-platform/tests/webdriver/tests/bidi/network/set_extra_headers/headers.py | 98+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Atesting/web-platform/tests/webdriver/tests/bidi/network/set_extra_headers/headers_name_standard_tentative.py | 50++++++++++++++++++++++++++++++++++++++++++++++++++
Mtesting/web-platform/tests/webdriver/tests/bidi/network/set_extra_headers/invalid.py | 82++++++++++++++++++++++++++++++++++++++++++-------------------------------------
Atesting/web-platform/tests/webdriver/tests/bidi/network/set_extra_headers/user_contexts.py | 102+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
7 files changed, 567 insertions(+), 38 deletions(-)

diff --git a/testing/web-platform/tests/webdriver/tests/bidi/network/set_extra_headers/__init__.py b/testing/web-platform/tests/webdriver/tests/bidi/network/set_extra_headers/__init__.py @@ -0,0 +1,26 @@ +SOME_HEADER_NAME = "some_header_name" +BROWSING_CONTEXT_VALUE = "browsing_context_value" +USER_CONTEXT_VALUE = "user_context_value" +GLOBAL_VALUE = "global_value" + +BROWSING_CONTEXT_HEADER = { + "name": SOME_HEADER_NAME, + "value": { + "type": "string", + "value": BROWSING_CONTEXT_VALUE + } +} +USER_CONTEXT_HEADER = { + "name": SOME_HEADER_NAME, + "value": { + "type": "string", + "value": USER_CONTEXT_VALUE + } +} +GLOBAL_HEADER = { + "name": SOME_HEADER_NAME, + "value": { + "type": "string", + "value": GLOBAL_VALUE + } +} diff --git a/testing/web-platform/tests/webdriver/tests/bidi/network/set_extra_headers/conftest.py b/testing/web-platform/tests/webdriver/tests/bidi/network/set_extra_headers/conftest.py @@ -0,0 +1,130 @@ +import json + +import pytest_asyncio + +import webdriver.bidi.error as error +from webdriver.bidi.modules.script import ContextTarget +from webdriver.bidi.undefined import UNDEFINED + + +@pytest_asyncio.fixture +async def set_extra_headers(bidi_session): + extra_headers = [] + + async def set_extra_headers(headers, contexts=UNDEFINED, + user_contexts=UNDEFINED): + extra_headers.append((contexts, user_contexts)) + await bidi_session.network.set_extra_headers( + headers=headers, contexts=contexts, user_contexts=user_contexts) + + yield set_extra_headers + + for (contexts, user_contexts) in extra_headers: + try: + await bidi_session.network.set_extra_headers( + headers=[], contexts=contexts, user_contexts=user_contexts) + except ( + error.InvalidArgumentException, + error.NoSuchUserContextException, + error.NoSuchFrameException): + pass + + +@pytest_asyncio.fixture +async def prepare_context(bidi_session, url): + async def prepare_context(context, domain=""): + await bidi_session.browsing_context.navigate( + context=context["context"], + url=url( + "/webdriver/tests/bidi/browsing_context/support/empty.html", + domain=domain), + wait="complete") + + return prepare_context + + +@pytest_asyncio.fixture +async def get_navigation_headers(bidi_session, url): + async def get_navigation_headers(context): + echo_link = url("webdriver/tests/support/http_handlers/headers_echo.py") + await bidi_session.browsing_context.navigate(context=context["context"], + url=echo_link, + wait="complete") + + result = await bidi_session.script.evaluate( + expression="window.document.body.textContent", + target=ContextTarget(context["context"]), + await_promise=False, + ) + + return (json.JSONDecoder().decode(result["value"]))["headers"] + + return get_navigation_headers + + +@pytest_asyncio.fixture +async def get_fetch_headers(bidi_session, url): + async def get_fetch_headers(context): + echo_link = url("webdriver/tests/support/http_handlers/headers_echo.py") + result = await bidi_session.script.evaluate( + expression=f"fetch('{echo_link}').then(r => r.text())", + target=ContextTarget(context["context"]), + await_promise=True, + ) + + return (json.JSONDecoder().decode(result["value"]))["headers"] + + return get_fetch_headers + + +@pytest_asyncio.fixture(params=["fetch", "navigation"]) +def get_headers_methods_invariant(request, get_fetch_headers, + get_navigation_headers): + if request.param == "fetch": + return get_fetch_headers + if request.param == "navigation": + return get_navigation_headers + raise Exception(f"Unsupported getter {request.param}") + + +@pytest_asyncio.fixture +def assert_header_present(get_fetch_headers): + async def assert_header_present(context, header_name, header_value): + actual_headers = await get_fetch_headers(context) + assert header_name in actual_headers, \ + f"header '{header_name}' should be present" + assert [header_value] == actual_headers[header_name], \ + f"header '{header_name}' should have value '{header_value}'" + + return assert_header_present + + +@pytest_asyncio.fixture +def assert_header_not_present(get_fetch_headers): + async def assert_header_not_present(context, header_name): + actual_headers = await get_fetch_headers(context) + assert header_name not in actual_headers, f"header '{header_name}' should not be present" + + return assert_header_not_present + + +@pytest_asyncio.fixture(params=['default', 'new'], + ids=["Default user context", "Custom user context"]) +async def target_user_context(request, create_user_context): + return request.param + + +@pytest_asyncio.fixture +async def affected_user_context(target_user_context, create_user_context): + """ Returns either a new or default user context. """ + if target_user_context == 'default': + return 'default' + return await create_user_context() + + +@pytest_asyncio.fixture +async def not_affected_user_context(target_user_context, create_user_context): + """ Returns opposite to `affected_user_context user context. """ + if target_user_context == 'new': + return 'default' + return await create_user_context() diff --git a/testing/web-platform/tests/webdriver/tests/bidi/network/set_extra_headers/contexts.py b/testing/web-platform/tests/webdriver/tests/bidi/network/set_extra_headers/contexts.py @@ -0,0 +1,117 @@ +import pytest + +from tests.bidi.network.set_extra_headers import SOME_HEADER_NAME, \ + BROWSING_CONTEXT_HEADER, BROWSING_CONTEXT_VALUE, USER_CONTEXT_HEADER, \ + USER_CONTEXT_VALUE, GLOBAL_HEADER, GLOBAL_VALUE +from tests.bidi.network.set_extra_headers.conftest import prepare_context + +pytestmark = pytest.mark.asyncio + + +async def test_isolation(bidi_session, top_context, prepare_context, + assert_header_present, assert_header_not_present, set_extra_headers): + another_context = await bidi_session.browsing_context.create( + type_hint="tab") + await prepare_context(top_context) + await prepare_context(another_context) + + await assert_header_not_present(top_context, SOME_HEADER_NAME) + await assert_header_not_present(another_context, SOME_HEADER_NAME) + + await set_extra_headers(headers=[BROWSING_CONTEXT_HEADER], + contexts=[top_context["context"]]) + + await assert_header_present(top_context, SOME_HEADER_NAME, + BROWSING_CONTEXT_VALUE) + await assert_header_not_present(another_context, SOME_HEADER_NAME) + + await set_extra_headers(headers=[], contexts=[top_context["context"]]) + + await assert_header_not_present(top_context, SOME_HEADER_NAME) + await assert_header_not_present(another_context, SOME_HEADER_NAME) + + +@pytest.mark.parametrize("domain", ["", "alt"], + ids=["same_origin", "cross_origin"]) +async def test_frame(bidi_session, url, assert_header_present, + assert_header_not_present, set_extra_headers, top_context, + create_iframe, domain, prepare_context): + # Change top-level frame's origin to allow for fetch from the iframe. + await prepare_context(top_context, domain) + iframe_id = await create_iframe(top_context, url('/', domain="")); + + await assert_header_not_present(iframe_id, SOME_HEADER_NAME) + + await set_extra_headers(headers=[BROWSING_CONTEXT_HEADER], + contexts=[top_context["context"]]) + + await assert_header_present(iframe_id, SOME_HEADER_NAME, + BROWSING_CONTEXT_VALUE) + + await set_extra_headers(headers=[], contexts=[top_context["context"]]) + + await assert_header_not_present(iframe_id, SOME_HEADER_NAME) + + +async def test_overrides_user_contexts(bidi_session, url, assert_header_present, + assert_header_not_present, set_extra_headers, top_context, + prepare_context, affected_user_context): + affected_context = await bidi_session.browsing_context.create( + type_hint="tab", user_context=affected_user_context) + await prepare_context(affected_context) + + await assert_header_not_present(affected_context, SOME_HEADER_NAME) + + await set_extra_headers(headers=[USER_CONTEXT_HEADER], + user_contexts=[affected_user_context]) + + await assert_header_present(affected_context, SOME_HEADER_NAME, + USER_CONTEXT_VALUE) + + await set_extra_headers(headers=[BROWSING_CONTEXT_HEADER], + contexts=[affected_context["context"]]) + + await assert_header_present(affected_context, SOME_HEADER_NAME, + BROWSING_CONTEXT_VALUE) + + await set_extra_headers(headers=[], + contexts=[affected_context["context"]]) + + await assert_header_present(affected_context, SOME_HEADER_NAME, + USER_CONTEXT_VALUE) + + await set_extra_headers(headers=[], + user_contexts=[affected_user_context]) + + await assert_header_not_present(affected_context, SOME_HEADER_NAME) + + +async def test_overrides_global(bidi_session, url, assert_header_present, + assert_header_not_present, set_extra_headers, top_context, + prepare_context, affected_user_context): + affected_context = await bidi_session.browsing_context.create( + type_hint="tab", user_context=affected_user_context) + await prepare_context(affected_context) + + await assert_header_not_present(affected_context, SOME_HEADER_NAME) + + await set_extra_headers(headers=[GLOBAL_HEADER]) + + await assert_header_present(affected_context, SOME_HEADER_NAME, + GLOBAL_VALUE) + + await set_extra_headers(headers=[BROWSING_CONTEXT_HEADER], + contexts=[affected_context["context"]]) + + await assert_header_present(affected_context, SOME_HEADER_NAME, + BROWSING_CONTEXT_VALUE) + + await set_extra_headers(headers=[], + contexts=[affected_context["context"]]) + + await assert_header_present(affected_context, SOME_HEADER_NAME, + GLOBAL_VALUE) + + await set_extra_headers(headers=[]) + + await assert_header_not_present(affected_context, SOME_HEADER_NAME) diff --git a/testing/web-platform/tests/webdriver/tests/bidi/network/set_extra_headers/headers.py b/testing/web-platform/tests/webdriver/tests/bidi/network/set_extra_headers/headers.py @@ -0,0 +1,98 @@ +import pytest + +pytestmark = pytest.mark.asyncio + + +async def test_set_and_remove(bidi_session, top_context, + prepare_context, get_headers_methods_invariant, url, set_extra_headers): + await prepare_context(top_context) + + original_headers = await get_headers_methods_invariant(top_context) + await set_extra_headers( + headers=[{ + "name": "some_header_name", + "value": { + "type": "string", + "value": "some_header_value" + }}], + contexts=[top_context["context"]]) + new_headers = await get_headers_methods_invariant(top_context) + assert new_headers["some_header_name"] == ["some_header_value"] + + await set_extra_headers(headers=[], contexts=[top_context["context"]]) + assert original_headers == await get_headers_methods_invariant(top_context) + + +async def test_multiple_headers(bidi_session, top_context, + prepare_context, get_headers_methods_invariant, url, set_extra_headers): + await prepare_context(top_context) + + original_headers = await get_headers_methods_invariant(top_context) + await set_extra_headers( + headers=[{ + "name": "some_header_name", + "value": { + "type": "string", + "value": "some_header_value_1" + } + }, { + "name": "some_header_name", + "value": { + "type": "string", + "value": "some_header_value_2" + } + }, { + "name": "another_header_name", + "value": { + "type": "string", + "value": "another_header_value" + } + }], + contexts=[top_context["context"]]) + new_headers = await get_headers_methods_invariant(top_context) + assert new_headers["some_header_name"] == [ + "some_header_value_1, some_header_value_2"] + assert new_headers["another_header_name"] == ["another_header_value"] + + await set_extra_headers(headers=[], contexts=[top_context["context"]]) + assert original_headers == await get_headers_methods_invariant(top_context) + + +async def test_headers_merged(bidi_session, prepare_context, set_extra_headers, + assert_header_present, affected_user_context): + affected_context = await bidi_session.browsing_context.create( + type_hint="tab", user_context=affected_user_context) + await prepare_context(affected_context) + + await set_extra_headers( + headers=[{ + "name": "some_context_name", + "value": { + "type": "string", + "value": "some_context_value" + }}], + contexts=[affected_context["context"]]) + + await set_extra_headers( + headers=[{ + "name": "some_user_context_name", + "value": { + "type": "string", + "value": "some_user_context_value" + }}], + user_contexts=[affected_user_context]) + + await set_extra_headers( + headers=[{ + "name": "some_global_name", + "value": { + "type": "string", + "value": "some_global_value" + }}]) + + await assert_header_present(affected_context, "some_context_name", + "some_context_value") + await assert_header_present(affected_context, "some_user_context_name", + "some_user_context_value") + await assert_header_present(affected_context, "some_global_name", + "some_global_value") diff --git a/testing/web-platform/tests/webdriver/tests/bidi/network/set_extra_headers/headers_name_standard_tentative.py b/testing/web-platform/tests/webdriver/tests/bidi/network/set_extra_headers/headers_name_standard_tentative.py @@ -0,0 +1,50 @@ +import pytest + +pytestmark = pytest.mark.asyncio + + +@pytest.mark.parametrize( + "header_name, header_value", + [ + # General purpose + ("user-agent", "some nonsense value"), + ("referer", "some nonsense value"), + ("referer", "https://some_valid_url.com/"), + ("accept", "application/json"), + ("accept", "some nonsense value"), + ("accept-language", "some nonsense value"), + # Caching + ("if-none-match", 'some nonsense value'), + # Authentication + ("authorization", "some nonsense value"), + ("cookie", "some nonsense value="), + # Custom + ("x-request-id", "some nonsense value"), + ("x-unicode-value", "你好世界"), + # Protected headers. + ("host", 'some nonsense value'), + ("host", "example.com"), + ("connection", "some nonsense value"), + ("origin", "some nonsense value"), + ("keep-alive", "some nonsense value"), + ("keep-alive", "timeout=5, max=200"), + # Protected prefixes + ("sec-custom-header", "some nonsense value"), + ("proxy-custom-header", "some nonsense value"), + ], +) +async def test_set_standard_headers(bidi_session, top_context, prepare_context, + header_name, header_value, get_headers_methods_invariant, + set_extra_headers): + await prepare_context(top_context) + + await set_extra_headers( + headers=[{ + "name": header_name, + "value": { + "type": "string", + "value": header_value + }}], + contexts=[top_context["context"]]) + new_headers = await get_headers_methods_invariant(top_context) + assert new_headers[header_name] == [header_value] diff --git a/testing/web-platform/tests/webdriver/tests/bidi/network/set_extra_headers/invalid.py b/testing/web-platform/tests/webdriver/tests/bidi/network/set_extra_headers/invalid.py @@ -15,38 +15,42 @@ VALID_HEADERS = [{ @pytest.mark.parametrize("value", get_invalid_cases("list")) -async def test_params_contexts_invalid_type(bidi_session, value): +async def test_params_contexts_invalid_type(bidi_session, value, + set_extra_headers): with pytest.raises(error.InvalidArgumentException): - await bidi_session.network.set_extra_headers( + await set_extra_headers( headers=VALID_HEADERS, contexts=value ) -async def test_params_contexts_empty_list(bidi_session): +async def test_params_contexts_empty_list(bidi_session, set_extra_headers): with pytest.raises(error.InvalidArgumentException): - await bidi_session.network.set_extra_headers( + await set_extra_headers( headers=VALID_HEADERS, contexts=[]) @pytest.mark.parametrize("value", get_invalid_cases("string")) -async def test_params_contexts_entry_invalid_type(bidi_session, value): +async def test_params_contexts_entry_invalid_type(bidi_session, value, + set_extra_headers): with pytest.raises(error.InvalidArgumentException): - await bidi_session.network.set_extra_headers( + await set_extra_headers( headers=VALID_HEADERS, contexts=[value]) -async def test_params_contexts_entry_invalid_value(bidi_session): +async def test_params_contexts_entry_invalid_value(bidi_session, + set_extra_headers): with pytest.raises(error.NoSuchFrameException): - await bidi_session.network.set_extra_headers( + await set_extra_headers( headers=VALID_HEADERS, contexts=["_invalid_"], ) -async def test_params_contexts_iframe(bidi_session, new_tab, get_test_page): +async def test_params_contexts_iframe(bidi_session, new_tab, get_test_page, + set_extra_headers): url = get_test_page(as_frame=True) await bidi_session.browsing_context.navigate( context=new_tab["context"], url=url, wait="complete" @@ -59,81 +63,85 @@ async def test_params_contexts_iframe(bidi_session, new_tab, get_test_page): assert len(frames) == 1 with pytest.raises(error.InvalidArgumentException): - await bidi_session.network.set_extra_headers( + await set_extra_headers( headers=VALID_HEADERS, contexts=[frames[0]["context"]], ) @pytest.mark.parametrize("value", get_invalid_cases("list")) -async def test_params_user_contexts_invalid_type(bidi_session, value): +async def test_params_user_contexts_invalid_type(bidi_session, value, + set_extra_headers): with pytest.raises(error.InvalidArgumentException): - await bidi_session.network.set_extra_headers( + await set_extra_headers( headers=VALID_HEADERS, user_contexts=value, ) -async def test_params_user_contexts_empty_list(bidi_session): +async def test_params_user_contexts_empty_list(bidi_session, set_extra_headers): with pytest.raises(error.InvalidArgumentException): - await bidi_session.network.set_extra_headers( + await set_extra_headers( headers=VALID_HEADERS, user_contexts=[], ) @pytest.mark.parametrize("value", get_invalid_cases("string")) -async def test_params_user_contexts_entry_invalid_type(bidi_session, value): +async def test_params_user_contexts_entry_invalid_type(bidi_session, value, + set_extra_headers): with pytest.raises(error.InvalidArgumentException): - await bidi_session.network.set_extra_headers( + await set_extra_headers( headers=VALID_HEADERS, user_contexts=[value], ) @pytest.mark.parametrize("value", ["", "somestring"]) -async def test_params_user_contexts_entry_invalid_value(bidi_session, value): +async def test_params_user_contexts_entry_invalid_value(bidi_session, value, + set_extra_headers): with pytest.raises(error.NoSuchUserContextException): - await bidi_session.network.set_extra_headers( + await set_extra_headers( headers=VALID_HEADERS, user_contexts=[value], ) -async def test_params_contexts_and_user_contexts(bidi_session, top_context): +async def test_params_contexts_and_user_contexts(bidi_session, top_context, + set_extra_headers): with pytest.raises(error.InvalidArgumentException): - await bidi_session.network.set_extra_headers( + await set_extra_headers( headers=VALID_HEADERS, contexts=[top_context["context"]], user_contexts=["default"], ) -async def test_params_headers_missing(bidi_session, top_context): +async def test_params_headers_missing(bidi_session, top_context, + set_extra_headers): with pytest.raises(error.InvalidArgumentException): - await bidi_session.network.set_extra_headers(headers=UNDEFINED) + await set_extra_headers(headers=UNDEFINED) @pytest.mark.parametrize("value", get_invalid_cases("list", nullable=False)) -async def test_params_headers_invalid_type(bidi_session, top_context, - value): +async def test_params_headers_invalid_type(bidi_session, top_context, value, + set_extra_headers): with pytest.raises(error.InvalidArgumentException): - await bidi_session.network.set_extra_headers(headers=value) + await set_extra_headers(headers=value) @pytest.mark.parametrize("value", get_invalid_cases("dict", nullable=False)) async def test_params_headers_header_invalid_type(bidi_session, top_context, - value): + value, set_extra_headers): with pytest.raises(error.InvalidArgumentException): - await bidi_session.network.set_extra_headers(headers=[value]) + await set_extra_headers(headers=[value]) @pytest.mark.parametrize("value", get_invalid_cases("string", nullable=False)) async def test_params_headers_header_name_invalid_type(bidi_session, - top_context, - value): + top_context, value, set_extra_headers): with pytest.raises(error.InvalidArgumentException): - await bidi_session.network.set_extra_headers( + await set_extra_headers( headers=[{"name": value, "value": "some_value"}], ) @@ -144,19 +152,18 @@ async def test_params_headers_header_name_invalid_type(bidi_session, ';', '<', '=', '>', '?', '@', '[', '\\', ']', '{', '}']) async def test_params_headers_header_name_invalid_value(bidi_session, - top_context, value): + top_context, value, set_extra_headers): with pytest.raises(error.InvalidArgumentException): - await bidi_session.network.set_extra_headers( + await set_extra_headers( headers=[{"name": value, "value": "some_value"}], ) @pytest.mark.parametrize("value", get_invalid_cases("string", nullable=False)) async def test_params_headers_header_value_invalid_type(bidi_session, - top_context, - value): + top_context, value, set_extra_headers): with pytest.raises(error.InvalidArgumentException): - await bidi_session.network.set_extra_headers( + await set_extra_headers( headers=[{"name": "some_name", "value": value}], contexts=[top_context["context"]], ) @@ -172,10 +179,9 @@ async def test_params_headers_header_value_invalid_type(bidi_session, "va\rlue", # CR ]) async def test_params_headers_header_value_invalid_value(bidi_session, - top_context, - value): + top_context, value, set_extra_headers): with pytest.raises(error.InvalidArgumentException): - await bidi_session.network.set_extra_headers( + await set_extra_headers( headers=[{"name": "some_name", "value": value}], contexts=[top_context["context"]], ) diff --git a/testing/web-platform/tests/webdriver/tests/bidi/network/set_extra_headers/user_contexts.py b/testing/web-platform/tests/webdriver/tests/bidi/network/set_extra_headers/user_contexts.py @@ -0,0 +1,102 @@ +import pytest + +from tests.bidi.network.set_extra_headers import SOME_HEADER_NAME, \ + USER_CONTEXT_HEADER, USER_CONTEXT_VALUE, GLOBAL_HEADER, GLOBAL_VALUE +from tests.bidi.network.set_extra_headers.conftest import prepare_context + +pytestmark = pytest.mark.asyncio + + +async def test_isolation(bidi_session, create_user_context, + assert_header_present, assert_header_not_present, affected_user_context, + not_affected_user_context, prepare_context, set_extra_headers): + affected_context = await bidi_session.browsing_context.create( + type_hint="tab", user_context=affected_user_context) + await prepare_context(affected_context) + not_affected_context = await bidi_session.browsing_context.create( + type_hint="tab", user_context=not_affected_user_context) + await prepare_context(not_affected_context) + + await assert_header_not_present(affected_context, SOME_HEADER_NAME) + await assert_header_not_present(not_affected_context, SOME_HEADER_NAME) + + await set_extra_headers(headers=[USER_CONTEXT_HEADER], + user_contexts=[affected_user_context]) + + await assert_header_present(affected_context, SOME_HEADER_NAME, + USER_CONTEXT_VALUE) + await assert_header_not_present(not_affected_context, SOME_HEADER_NAME) + + another_affected_context = await bidi_session.browsing_context.create( + type_hint="tab", user_context=affected_user_context) + await prepare_context(another_affected_context) + another_not_affected_context = await bidi_session.browsing_context.create( + type_hint="tab", user_context=not_affected_user_context) + await prepare_context(another_not_affected_context) + await assert_header_present(another_affected_context, SOME_HEADER_NAME, + USER_CONTEXT_VALUE) + await assert_header_not_present(another_not_affected_context, + SOME_HEADER_NAME) + + await set_extra_headers(headers=[], user_contexts=[affected_user_context]) + + await assert_header_not_present(affected_context, SOME_HEADER_NAME) + await assert_header_not_present(not_affected_context, SOME_HEADER_NAME) + await assert_header_not_present(another_affected_context, SOME_HEADER_NAME) + await assert_header_not_present(another_not_affected_context, + SOME_HEADER_NAME) + + +@pytest.mark.parametrize("domain", ["", "alt"], + ids=["same_origin", "cross_origin"]) +async def test_frame(bidi_session, url, assert_header_present, + assert_header_not_present, set_extra_headers, + create_iframe, domain, prepare_context, affected_user_context): + affected_context = await bidi_session.browsing_context.create( + type_hint="tab", user_context=affected_user_context) + # Change top-level frame's origin to allow for fetch from the iframe. + await prepare_context(affected_context, domain) + iframe_id = await create_iframe(affected_context, url('/', domain="")); + + await assert_header_not_present(iframe_id, SOME_HEADER_NAME) + + await set_extra_headers(headers=[USER_CONTEXT_HEADER], + user_contexts=[affected_user_context]) + + await assert_header_present(iframe_id, SOME_HEADER_NAME, + USER_CONTEXT_VALUE) + + await set_extra_headers(headers=[], user_contexts=[affected_user_context]) + + await assert_header_not_present(iframe_id, SOME_HEADER_NAME) + + +async def test_overrides_global(bidi_session, url, assert_header_present, + assert_header_not_present, set_extra_headers, top_context, + prepare_context, affected_user_context): + affected_context = await bidi_session.browsing_context.create( + type_hint="tab", user_context=affected_user_context) + await prepare_context(affected_context) + + await assert_header_not_present(affected_context, SOME_HEADER_NAME) + + await set_extra_headers(headers=[GLOBAL_HEADER]) + + await assert_header_present(affected_context, SOME_HEADER_NAME, + GLOBAL_VALUE) + + await set_extra_headers(headers=[USER_CONTEXT_HEADER], + user_contexts=[affected_user_context]) + + await assert_header_present(affected_context, SOME_HEADER_NAME, + USER_CONTEXT_VALUE) + + await set_extra_headers(headers=[], + user_contexts=[affected_user_context]) + + await assert_header_present(affected_context, SOME_HEADER_NAME, + GLOBAL_VALUE) + + await set_extra_headers(headers=[]) + + await assert_header_not_present(affected_context, SOME_HEADER_NAME)