[DNR] main_frame redirect to an extension page + accessing the original URL and POST data
Opened this issue · 0 comments
tophf commented
Supersedes #604 with a different, more focused use case: redirecting an entire tab (optionally a frame) to a custom handler.
Extensions like Tapermonkey/Violentmonkey/Stylus/JSONViewer and others want to redirect an entire tab (or frame) based on a URL or on a Content-Type response header (soon will be possible via DNR) to their own built-in UI page. URLs ending on .json, .user.js or .user.css and such, so this is not solved by custom protocol handlers.
Primary goals
- The original URL must be exposed to the extension page.
- The extension page should not be exposed to the web:
- to avoid redundancy as main_frame/sub_frame navigation is done by the browser's DNR handler, not by a web page;
- to improve security as Chrome still doesn't implement
use_dynamic_url
; - to improve API ergonomics by removing a non-obvious requirement.
- Provide
POST
data from submitted forms to allow extensions to preprocess it before uploading to the server.
Optional goal
- Support
sub_frame
redirection in addition tomain_frame
.
Although this is extremely rare to have a custom viewer in a frame, AFAIK, but it seems reasonable for consistency.
ManifestV2
- Redirection: extensions stopped the navigation via webRequestBlocking by returning
{cancel:true}
or{redirectUrl: 'javascript:0'}
and then redirected the tab viachrome.tabs.update(tabId, {url: 'own.html'})
, passed the original URL either as a URL parameter or via messaging. This only worked with main_frame navigation, though. POST
preprocessing:chrome.webRequest.onBeforeRequest(..., ['requestBody', 'blocking'])
ManifestV3
It's complicated and problematic since normal extensions can't use webRequestBlocking anymore:
- requires declaring the background script or adding a visual config page to call updateDynamicRules with chrome.runtime.id;
- requires DNR's regexFilter and regexSubstitution to pass the original URL, but:
- regex is inefficient to match URLs on all domains (DNR doesn't implement cascaded matching of urlFilter + regexFilter),
- there are global limits on regex rules in DNR,
- regex confuses many developers as it's inherently arcane and cryptic;
- requires exposing the html page in web_accessible_resources, but the extension may want to disallow web-initiated redirections in general, allowing them only for its own DNR rules. For example, to improve security, avoid detection.
POST
preprocessing: interceptingsubmit
event in an isolated content script isn't enough, you'd need to spoof HTMLFormElement.prototype.submit in the main world, which is unsafe/unreliable.
Possible solutions for goal 1: exposing the original URL
- As
document.referrer
i.e. not exposed visually. - As an auto-appended URL parameter
?url=....
accessible asnew URLSearchParams(location.search).get('url')
.
It may be appended as&url=...
if the extension path already contains?
e.g."/foo.html?param=1"
.
If deemed desirable, this behavior may be disabled by default, opt-in via"originalUrlAsParameter": "url"
.
Possible solutions for goal 2: redirection without self-exposure
extensionHandler: 'foo.html'
. The name suggests that the extension handles the page, like PDF viewer in Chrome.extensionTabHandler: 'foo.html'
. A more self-explanatory name if we want to support only main_frame navigation.extensionNavigationHandler: 'foo.html'
. Makes it even more obvious that this is only for navigation redirects.extensionPathForNavigation: 'foo.html'
. Also preserves continuity with the existing extensionPath.resourcesTypes: ['main_frame', 'sub_frame']
would automatically allowextensionPath: 'foo.html'
to redirect to the extension's foo.html without exposing it in web_accessible_resources. This is not explicit, though.
Possible solutions for goal 3: POST
data access
chrome.declarativeNetRequest.redirectedRequest
getter orgetRedirectedRequest()
method to get all infochrome.declarativeNetRequest.requestBody
getter orgetRequestBody()
method to get only the body