Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug]: Firefox not preserving fragment after context.route() interception #34518

Open
Disnaming opened this issue Jan 28, 2025 · 3 comments
Open

Comments

@Disnaming
Copy link

Version

1.49.1

Steps to reproduce

from playwright.async_api import async_playwright

async def main():
    playwright = await async_playwright().start()
    browser = await playwright.firefox.launch()
    context = await browser.new_context()
    page = await context.new_page()
    new_page = await context.new_page()
    await page.goto("http://example.com#no-rerouted-navigation")
    print(page.url)
    await context.route("**/*", lambda route, request: route.continue_(url=request.url))
    await page.goto("http://example.com#hashchange-avoided-navigation")
    await new_page.goto("http://example.com#new-navigation-with-reroute")
    print(page.url)
    print(new_page.url) # expecting to see hash, but its not there
    await context.close()
    await browser.close()
    await playwright.stop()

if __name__ == "__main__":
    import asyncio
    asyncio.run(main())

Expected behavior

I expect to see the hash preserved after navigation.

Actual behavior

The hash is gone.

Additional context

No response

Environment

- Operating System: [Ubuntu 22.04]
- CPU: [arm64]
- Browser: [Chromium, Firefox]
- Python Version: [3.12]
- Other info:
@mxschmitt mxschmitt transferred this issue from microsoft/playwright-python Jan 28, 2025
@agg23
Copy link
Contributor

agg23 commented Jan 28, 2025

As I suspected in your sample code, the issue lies in the line:

 await context.route("**/*", lambda route, request: route.continue_(url=request.url))

specifically

route.continue_(url=request.url))

URL fragments (the URL hash) is not intended to be preserved when communicating with a server, thus our routing does not represent them.

The target URI excludes the reference's fragment component, if any, since fragment identifiers are reserved for client-side processing.

From Hypertext Transfer Protocol (HTTP/1.1): Message Syntax and Routing: RFC 7230

When the lambda executes, request.url is simply "http://example.com", thus causing your test to redirect to the page without any fragment.

For your particular example, you can preserve the full URL by not rewriting the URL in the request:

 await context.route("**/*", lambda route, request: route.continue_())

@agg23 agg23 closed this as not planned Won't fix, can't repro, duplicate, stale Jan 28, 2025
@Disnaming
Copy link
Author

Sorry to re-alive this issue, but I just noticed that the Firefox browser type seems to be the only one that drops the hash; Chromium and Webkit keep this, and this should probably be consistent across all browsers to avoid surprises.

Also, while not my current use case, preserving the hash when rerouting requests could be useful if one needed to test client-side behaviour that depends on the URL fragment in a context where service workers/the geolocation API needs to be disabled. (Specifically, useful for prototyping exploits against domains which are hosted over HTTP, sometimes seen in CTFs, where it's common to deploy the challenge server on localhost for testing).

@agg23
Copy link
Contributor

agg23 commented Jan 28, 2025

I'm sorry, you're right. Firefox will drop the fragment when a route intercepts the message, but Chromium and WebKit do not.

@agg23 agg23 reopened this Jan 28, 2025
@agg23 agg23 changed the title [Bug]: URL hash not preserved after context.route() interception [Bug]: Firefox not preserving fragment after context.route() interception Jan 28, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants