[Bug]: Firefox not preserving fragment after `context.route()` interception
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:
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_())
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).
I'm sorry, you're right. Firefox will drop the fragment when a route intercepts the message, but Chromium and WebKit do not.
Why was this issue closed?
Thank you for your contribution to our project. This issue has been closed due to its limited upvotes and recent activity, and insufficient feedback for us to effectively act upon. Our priority is to focus on bugs that reflect higher user engagement and have actionable feedback, to ensure our bug database stays manageable.
Should you feel this closure was in error, please create a new issue and reference this one. We're open to revisiting it given increased support or additional clarity. Your understanding and cooperation are greatly appreciated.