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 to main_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 via chrome.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: intercepting submit 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 as new 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 allow extensionPath: '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 or getRedirectedRequest() method to get all info
chrome.declarativeNetRequest.requestBody getter or getRequestBody() method to get only the body
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
use_dynamic_url
;POST
data from submitted forms to allow extensions to preprocess it before uploading to the server.Optional goal
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
{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:
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
document.referrer
i.e. not exposed visually.?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 accesschrome.declarativeNetRequest.redirectedRequest
getter orgetRedirectedRequest()
method to get all infochrome.declarativeNetRequest.requestBody
getter orgetRequestBody()
method to get only the body