我正在使用 SDK 创建一个 Firefox 插件。我的目标很简单,拦截特定的 iframe 并加载我自己的 HTML 页面(用我的插件打包为资源)而不是最初请求的内容。
到目前为止我有以下代码:
var httpRequestObserver =
{
observe: function(subject, topic, data)
{
var httpChannel, requestURL;
if (topic == "http-on-modify-request") {
httpChannel = subject.QueryInterface(Ci.nsIHttpChannel);
requestURL = httpChannel.URI.spec;
var newRequestURL, i;
if (/someurl/.test(requestURL)) {
var ioService = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
httpChannel.redirectTo(ioService.newURI(self.data.url('pages/test.html'), undefined, undefined));
}
return;
}
}
};
var observerService = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
observerService.addObserver(httpRequestObserver, "http-on-modify-request", false);
此代码的工作原理是它检测正确的 iframe 加载并正确执行重定向。但是,我收到以下错误:
安全错误:http://url.com 上的内容可能无法加载或链接到 jar:file:///.../pages/test.html.
如何克服这个限制?
其实我真的想太多了。
当我改为使用 loadContext 时,它已经解决了。现在,当您获得 loadContext 时,您将获得任何浏览器元素(选项卡浏览器、框架或 iframe)的 contentWindow,然后像您正在做的那样中止 http 请求,然后
loadContext.associatedWindow.document.location = self.data('pages/tests.html');
完成
将代码粘贴到此处,删除所有私有内容。您可能需要 chrome.manifest 我测试一下并将代码粘贴回此处
Cu.import('resource://gre/modules/Services.jsm');
var httpRequestObserver = {
observe: function (subject, topic, data) {
var httpChannel, requestURL;
if (topic == "http-on-modify-request") {
httpChannel = subject.QueryInterface(Ci.nsIHttpChannel);
requestURL = httpChannel.URI.spec;
var newRequestURL, i;
if (/someurl/.test(requestURL)) {
var goodies = loadContextGoodies(httpChannel);
if (goodies) {
httpChannel.cancel(Cr.NS_BINDING_ABORTED);
goodies.contentWindow.location = self.data.url('pages/test.html');
} else {
//dont do anything as there is no contentWindow associated with the httpChannel, liekly a google ad is loading or some ajax call or something, so this is not an error
}
}
return;
}
}
};
Services.obs.addObserver(httpRequestObserver, "http-on-modify-request", false);
//this function gets the contentWindow and other good stuff from loadContext of httpChannel
function loadContextGoodies(httpChannel) {
//httpChannel must be the subject of http-on-modify-request QI'ed to nsiHTTPChannel as is done on line 8 "httpChannel = subject.QueryInterface(Ci.nsIHttpChannel);"
//start loadContext stuff
var loadContext;
try {
var interfaceRequestor = httpChannel.notificationCallbacks.QueryInterface(Ci.nsIInterfaceRequestor);
//var DOMWindow = interfaceRequestor.getInterface(Components.interfaces.nsIDOMWindow); //not to be done anymore because: https://developer.mozilla.org/en-US/docs/Updating_extensions_for_Firefox_3.5#Getting_a_load_context_from_a_request //instead do the loadContext stuff below
try {
loadContext = interfaceRequestor.getInterface(Ci.nsILoadContext);
} catch (ex) {
try {
loadContext = subject.loadGroup.notificationCallbacks.getInterface(Ci.nsILoadContext);
} catch (ex2) {
}
}
} catch (ex0) {
}
if (!loadContext) {
//no load context so dont do anything although you can run this, which is your old code
//this probably means that its loading an ajax call or like a google ad thing
return null;
} else {
var contentWindow = loadContext.associatedWindow;
if (!contentWindow) {
//this channel does not have a window, its probably loading a resource
//this probably means that its loading an ajax call or like a google ad thing
return null;
} else {
var aDOMWindow = contentWindow.top.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShellTreeItem)
.rootTreeItem
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindow);
var gBrowser = aDOMWindow.gBrowser;
var aTab = gBrowser._getTabForContentWindow(contentWindow.top); //this is the clickable tab xul element, the one found in the tab strip of the firefox window, aTab.linkedBrowser is same as browser var above //can stylize tab like aTab.style.backgroundColor = 'blue'; //can stylize the tab like aTab.style.fontColor = 'red';
var browser = aTab.linkedBrowser; //this is the browser within the tab //this is where the example in the previous section ends
return {
aDOMWindow: aDOMWindow,
gBrowser: gBrowser,
aTab: aTab,
browser: browser,
contentWindow: contentWindow
};
}
}
//end loadContext stuff
}
注意: 现在先尝试一下,我还没有测试它,如果在尝试重定向时遇到安全错误,请创建一个 chrome.manifest 文件并将其放在根目录中。如果它引发安全错误,那么您肯定需要一个 chrome.manifest 文件,毫无疑问这将修复它。今晚晚些时候,当我有时间的时候,我会亲自测试一下。
chrome.manifest 应该如下所示:
content kaboom-data ./resources/kaboom/data/ contentaccessible=yes
然后在上面的代码中将重定向行从
goodies.contentWindow.location = self.data.url('pages/test.html');
更改为 goodies.contentWindow.location = 'chrome://kaboom-data/pages/test.html');
。
在此处查看此插件:https://addons.mozilla.org/en-US/firefox/addon/ghforkable/?src=search
在 chrome.manifest 文件中,我们将 contentaccessible 参数设置为 yes
您不需要此插件的 sdk。它非常简单,只需将其粘贴到引导程序骨架中即可,如下所示:
具有一些功能的引导程序,例如您需要的 chrome.manifest
如果您真的想将页面重定向到您的网站,也许您想制作自定义页面?如果您愿意,我会为您提供一个有关制作自定义页面的演示。你可以看到有点难以理解的演示这里
在这里发布我的试验,这样可以帮助所有人:
trail 1失败 - 创建了包含内容的 chrome.manifest 文件
content kaboom-data resources/kaboom/data/ contentaccessible=yes
var myuri = Services.io.newURI('chrome://kaboom-data/content/pages/test.html', undefined, undefined);
httpChannel.redirectTo(myuri);
抛出错误
安全错误:内容位于 http://digg.com/tools/diggthis/confirm?可能 不加载或链接到 jar:file:///C:/Documents%20and%20Settings/SONY%20VAIO/Application%20Data/Mozilla/Firefox/Profiles/vr10qb8s.default/extensions/jid1-g4[电子邮件受保护]!/resources/kaboom /data/pages/test.html.
试用 2 失败 - 在 bootstrap.js 中创建资源
别名.spec = file:///C:/Documents%20and%20Settings/SONY%20VAIO/Application%20Data/Mozilla/Firefox/Profiles/vr10qb8s.default/extensions/[电子邮件受保护]
别名已更新为规范: jar:file:///C:/Documents%20and%20Settings/SONY%20VAIO/Application%20Data/Mozilla/Firefox/Profiles/vr10qb8s.default/extensions/[电子邮件受保护]!/
let resource = Services.io.getProtocolHandler("resource").QueryInterface(Ci.nsIResProtocolHandler);
let alias = Services.io.newFileURI(data.installPath);
Cu.reportError('alias.spec = ' + alias.spec);
if (!data.installPath.isDirectory()) {
alias = Services.io.newURI("jar:" + alias.spec + "!/", null, null);
Cu.reportError('alias updated to spec: ' + alias.spec);
}
resource.setSubstitution("kaboom_data", alias);
...
var myuri = Services.io.newURI('resource://kaboom_data/resources/kaboom/data/pages/test.html', undefined, undefined);
httpChannel.redirectTo(myuri);
抛出错误
安全错误:内容位于 http://digg.com/tools/diggthis/confirm?可能 不加载或链接到 jar:file:///C:/Documents%20and%20Settings/SONY%20VAIO/Application%20Data/Mozilla/Firefox/Profiles/vr10qb8s.default/extensions/jid1-g4[电子邮件受保护]!/resources/kaboom /data/pages/test.html.
结论 在上面的两个试验中,这是最奇怪的事情,它不会在抛出的安全错误中显示资源或 chrome 路径,但会给出完整的 jar 路径。让我相信这与redirectTo 函数有关。
有效的解决方案是您的解决方案
var gBrowser = utils.getMostRecentBrowserWindow().gBrowser;
var domWin = httpChannel.notificationCallbacks.getInterface(Ci.nsIDOMWindow);
var browser = gBrowser.getBrowserForDocument(domWin.document);
//redirect
browser.loadURI(self.data.url('pages/test.html'));
但是我将其更改为使用 loadContext 而不是此方法,因为这是推荐的方法。如果 url 加载缓慢并且用户切换到另一个选项卡或窗口,gBrowser 到 getMostRecentBrowserWindow 也会失败
我还更改为使用 Services.jsm,因为您无论如何都导入了 Cu。使用 Services.jsm 速度非常快,甚至眨眼都不会快。它只是一个指针。
我仍在尝试使用redirectTo方法,这真的让我很困扰。我所做的更改是针对我的本地副本。
您是否考虑过将本地 HTML 文件转换为数据 URL 并加载?