Bug 396203 - Unify checks for DOMLinkAdded. r/a=mconnor
git-svn-id: svn://10.0.0.236/trunk@237088 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
parent
c22c43ae9e
commit
e8e8de756b
@ -935,11 +935,12 @@ function prepareForStartup()
|
|||||||
// hook up UI through progress listener
|
// hook up UI through progress listener
|
||||||
gBrowser.addProgressListener(window.XULBrowserWindow, Components.interfaces.nsIWebProgress.NOTIFY_ALL);
|
gBrowser.addProgressListener(window.XULBrowserWindow, Components.interfaces.nsIWebProgress.NOTIFY_ALL);
|
||||||
|
|
||||||
// Initialize the feedhandler
|
// setup our common DOMLinkAdded listener
|
||||||
FeedHandler.init();
|
gBrowser.addEventListener("DOMLinkAdded",
|
||||||
|
function (event) { DOMLinkHandler.onLinkAdded(event); },
|
||||||
|
false);
|
||||||
|
|
||||||
// Initialize the searchbar
|
gBrowser.addEventListener("pagehide", FeedHandler.onPageHide, false);
|
||||||
BrowserSearch.init();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function delayedStartup()
|
function delayedStartup()
|
||||||
@ -2647,84 +2648,145 @@ var DownloadsButtonDNDObserver = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const BrowserSearch = {
|
const DOMLinkHandler = {
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize the BrowserSearch
|
|
||||||
*/
|
|
||||||
init: function() {
|
|
||||||
gBrowser.addEventListener("DOMLinkAdded",
|
|
||||||
function (event) { BrowserSearch.onLinkAdded(event); },
|
|
||||||
false);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A new <link> tag has been discovered - check to see if it advertises
|
|
||||||
* a OpenSearch engine.
|
|
||||||
*/
|
|
||||||
onLinkAdded: function(event) {
|
onLinkAdded: function(event) {
|
||||||
// XXX this event listener can/should probably be combined with the onLinkAdded
|
var link = event.originalTarget;
|
||||||
// listener in tabbrowser.xml. See comments in FeedHandler.onLinkAdded().
|
var rel = link.rel && link.rel.toLowerCase();
|
||||||
const target = event.target;
|
if (!link || !link.ownerDocument || !rel || !link.href)
|
||||||
var etype = target.type;
|
|
||||||
const searchRelRegex = /(^|\s)search($|\s)/i;
|
|
||||||
const searchHrefRegex = /^(https?|ftp):\/\//i;
|
|
||||||
|
|
||||||
if (!etype)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Bug 349431: If the engine has no suggested title, ignore it rather
|
|
||||||
// than trying to find an alternative.
|
|
||||||
if (!target.title)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (etype == "application/opensearchdescription+xml" &&
|
var feedAdded = false;
|
||||||
searchRelRegex.test(target.rel) && searchHrefRegex.test(target.href))
|
var iconAdded = false;
|
||||||
{
|
var searchAdded = false;
|
||||||
const targetDoc = target.ownerDocument;
|
var relStrings = rel.split(/\s+/);
|
||||||
// Set the attribute of the (first) search-engine button.
|
var rels = {};
|
||||||
var searchButton = document.getAnonymousElementByAttribute(this.getSearchBar(),
|
for (let i = 0; i < relStrings.length; i++)
|
||||||
"anonid", "searchbar-engine-button");
|
rels[relStrings[i]] = true;
|
||||||
if (searchButton) {
|
|
||||||
var browser = gBrowser.getBrowserForDocument(targetDoc);
|
|
||||||
// Append the URI and an appropriate title to the browser data.
|
|
||||||
var iconURL = null;
|
|
||||||
if (gBrowser.shouldLoadFavIcon(browser.currentURI))
|
|
||||||
iconURL = browser.currentURI.prePath + "/favicon.ico";
|
|
||||||
|
|
||||||
var hidden = false;
|
for (let relVal in rels) {
|
||||||
// If this engine (identified by title) is already in the list, add it
|
switch (relVal) {
|
||||||
// to the list of hidden engines rather than to the main list.
|
case "feed":
|
||||||
// XXX This will need to be changed when engines are identified by URL;
|
case "alternate":
|
||||||
// see bug 335102.
|
if (!feedAdded) {
|
||||||
var searchService =
|
if (!rels.feed && rels.alternate && rels.stylesheet)
|
||||||
Components.classes["@mozilla.org/browser/search-service;1"]
|
break;
|
||||||
.getService(Components.interfaces.nsIBrowserSearchService);
|
|
||||||
if (searchService.getEngineByName(target.title))
|
|
||||||
hidden = true;
|
|
||||||
|
|
||||||
var engines = [];
|
var feed = { title: link.title, href: link.href, type: link.type };
|
||||||
if (hidden) {
|
if (isValidFeed(feed, link.ownerDocument.nodePrincipal, rels.feed)) {
|
||||||
if (browser.hiddenEngines)
|
FeedHandler.addFeed(feed, link.ownerDocument);
|
||||||
engines = browser.hiddenEngines;
|
feedAdded = true;
|
||||||
}
|
}
|
||||||
else {
|
}
|
||||||
if (browser.engines)
|
break;
|
||||||
engines = browser.engines;
|
case "icon":
|
||||||
}
|
if (!iconAdded) {
|
||||||
|
if (!gBrowser.mPrefs.getBoolPref("browser.chrome.site_icons"))
|
||||||
|
break;
|
||||||
|
|
||||||
engines.push({ uri: target.href,
|
try {
|
||||||
title: target.title,
|
var contentPolicy = Cc["@mozilla.org/layout/content-policy;1"].
|
||||||
icon: iconURL });
|
getService(Ci.nsIContentPolicy);
|
||||||
|
} catch(e) {
|
||||||
|
break; // Refuse to load if we can't do a security check.
|
||||||
|
}
|
||||||
|
|
||||||
if (hidden) {
|
var targetDoc = link.ownerDocument;
|
||||||
browser.hiddenEngines = engines;
|
var ios = Cc["@mozilla.org/network/io-service;1"].
|
||||||
}
|
getService(Ci.nsIIOService);
|
||||||
else {
|
var uri = ios.newURI(link.href, targetDoc.characterSet, null);
|
||||||
browser.engines = engines;
|
try {
|
||||||
if (browser == gBrowser || browser == gBrowser.mCurrentBrowser)
|
// Verify that the load of this icon is legal.
|
||||||
this.updateSearchButton();
|
// error pages can load their favicon, to be on the safe side,
|
||||||
}
|
// only allow chrome:// favicons
|
||||||
|
const aboutNeterr = "about:neterror?";
|
||||||
|
if (targetDoc.documentURI.substr(0, aboutNeterr.length) != aboutNeterr ||
|
||||||
|
!uri.schemeIs("chrome")) {
|
||||||
|
var ssm = Cc["@mozilla.org/scriptsecuritymanager;1"].
|
||||||
|
getService(Ci.nsIScriptSecurityManager);
|
||||||
|
ssm.checkLoadURIWithPrincipal(targetDoc.nodePrincipal, uri,
|
||||||
|
Ci.nsIScriptSecurityManager.DISALLOW_SCRIPT);
|
||||||
|
}
|
||||||
|
} catch(e) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Security says okay, now ask content policy
|
||||||
|
if (contentPolicy.shouldLoad(Ci.nsIContentPolicy.TYPE_IMAGE,
|
||||||
|
uri, targetDoc.documentURIObject,
|
||||||
|
link, link.type, null)
|
||||||
|
!= Ci.nsIContentPolicy.ACCEPT)
|
||||||
|
break;
|
||||||
|
|
||||||
|
var browserIndex = gBrowser.getBrowserIndexForDocument(targetDoc);
|
||||||
|
// no browser? no favicon.
|
||||||
|
if (browserIndex == -1)
|
||||||
|
break;
|
||||||
|
|
||||||
|
var tab = gBrowser.mTabContainer.childNodes[browserIndex];
|
||||||
|
gBrowser.setIcon(tab, link.href);
|
||||||
|
iconAdded = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "search":
|
||||||
|
if (!searchAdded) {
|
||||||
|
var type = link.type && link.type.toLowerCase();
|
||||||
|
type = type.replace(/^\s+|\s*(?:;.*)?$/g, "");
|
||||||
|
|
||||||
|
if (type == "application/opensearchdescription+xml" && link.title &&
|
||||||
|
/^(https?|ftp):/i.test(link.href)) {
|
||||||
|
var engine = { title: link.title, href: link.href };
|
||||||
|
BrowserSearch.addEngine(engine, link.ownerDocument);
|
||||||
|
searchAdded = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const BrowserSearch = {
|
||||||
|
addEngine: function(engine, targetDoc) {
|
||||||
|
// Set the attribute of the (first) search-engine button.
|
||||||
|
var searchButton = document.getAnonymousElementByAttribute(this.getSearchBar(), "anonid",
|
||||||
|
"searchbar-engine-button");
|
||||||
|
if (searchButton) {
|
||||||
|
var browser = gBrowser.getBrowserForDocument(targetDoc);
|
||||||
|
// Append the URI and an appropriate title to the browser data.
|
||||||
|
var iconURL = null;
|
||||||
|
if (gBrowser.shouldLoadFavIcon(browser.currentURI))
|
||||||
|
iconURL = browser.currentURI.prePath + "/favicon.ico";
|
||||||
|
|
||||||
|
var hidden = false;
|
||||||
|
// If this engine (identified by title) is already in the list, add it
|
||||||
|
// to the list of hidden engines rather than to the main list.
|
||||||
|
// XXX This will need to be changed when engines are identified by URL;
|
||||||
|
// see bug 335102.
|
||||||
|
var searchService = Cc["@mozilla.org/browser/search-service;1"].
|
||||||
|
getService(Ci.nsIBrowserSearchService);
|
||||||
|
if (searchService.getEngineByName(engine.title))
|
||||||
|
hidden = true;
|
||||||
|
|
||||||
|
var engines = [];
|
||||||
|
if (hidden) {
|
||||||
|
if (browser.hiddenEngines)
|
||||||
|
engines = browser.hiddenEngines;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (browser.engines)
|
||||||
|
engines = browser.engines;
|
||||||
|
}
|
||||||
|
|
||||||
|
engines.push({ uri: engine.href,
|
||||||
|
title: engine.title,
|
||||||
|
icon: iconURL });
|
||||||
|
|
||||||
|
if (hidden)
|
||||||
|
browser.hiddenEngines = engines;
|
||||||
|
else {
|
||||||
|
browser.engines = engines;
|
||||||
|
if (browser == gBrowser || browser == gBrowser.mCurrentBrowser)
|
||||||
|
this.updateSearchButton();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -5073,16 +5135,6 @@ function convertFromUnicode(charset, str)
|
|||||||
* and shows UI when they are discovered.
|
* and shows UI when they are discovered.
|
||||||
*/
|
*/
|
||||||
var FeedHandler = {
|
var FeedHandler = {
|
||||||
/**
|
|
||||||
* Initialize the Feed Handler
|
|
||||||
*/
|
|
||||||
init: function() {
|
|
||||||
gBrowser.addEventListener("DOMLinkAdded",
|
|
||||||
function (event) { FeedHandler.onLinkAdded(event); },
|
|
||||||
true);
|
|
||||||
gBrowser.addEventListener("pagehide", FeedHandler.onPageHide, true);
|
|
||||||
},
|
|
||||||
|
|
||||||
onPageHide: function(event) {
|
onPageHide: function(event) {
|
||||||
var theBrowser = gBrowser.getBrowserForDocument(event.target);
|
var theBrowser = gBrowser.getBrowserForDocument(event.target);
|
||||||
if (theBrowser)
|
if (theBrowser)
|
||||||
@ -5237,25 +5289,9 @@ var FeedHandler = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
|
||||||
* A new <link> tag has been discovered - check to see if it advertises
|
|
||||||
* an RSS feed.
|
|
||||||
*/
|
|
||||||
onLinkAdded: function(event) {
|
|
||||||
// XXX this event listener can/should probably be combined with the onLinkAdded
|
|
||||||
// listener in tabbrowser.xml, which only listens for favicons and then passes
|
|
||||||
// them to onLinkIconAvailable in the ProgressListener. We could extend the
|
|
||||||
// progress listener to have a generic onLinkAvailable and have tabbrowser pass
|
|
||||||
// along all events. It should give us the browser for the tab, as well as
|
|
||||||
// the actual event.
|
|
||||||
|
|
||||||
var feed = recognizeFeedFromLink(event.target,
|
|
||||||
event.target.ownerDocument.nodePrincipal);
|
|
||||||
|
|
||||||
|
addFeed: function(feed, targetDoc) {
|
||||||
if (feed) {
|
if (feed) {
|
||||||
const targetDoc = event.target.ownerDocument;
|
|
||||||
|
|
||||||
// find which tab this is for, and set the attribute on the browser
|
// find which tab this is for, and set the attribute on the browser
|
||||||
var browserForLink = gBrowser.getBrowserForDocument(targetDoc);
|
var browserForLink = gBrowser.getBrowserForDocument(targetDoc);
|
||||||
if (!browserForLink) {
|
if (!browserForLink) {
|
||||||
|
|||||||
@ -50,14 +50,23 @@ function initFeedTab()
|
|||||||
var linkNodes = gDocument.getElementsByTagName("link");
|
var linkNodes = gDocument.getElementsByTagName("link");
|
||||||
var length = linkNodes.length;
|
var length = linkNodes.length;
|
||||||
for (var i = 0; i < length; i++) {
|
for (var i = 0; i < length; i++) {
|
||||||
var feed = recognizeFeedFromLink(linkNodes[i], gDocument.nodePrincipal);
|
var link = linkNodes[i];
|
||||||
if (feed) {
|
if (!link.href)
|
||||||
var type = feed.type;
|
continue;
|
||||||
if (type in feedTypes)
|
|
||||||
type = feedTypes[type];
|
var rel = link.rel && link.rel.toLowerCase();
|
||||||
else
|
var rels = {};
|
||||||
type = feedTypes["application/rss+xml"];
|
if (rel) {
|
||||||
addRow(feed.title, type, feed.href);
|
for each (let relVal in rel.split(/\s+/))
|
||||||
|
rels[relVal] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rels.feed || (link.type && rels.alternate && !rels.stylesheet)) {
|
||||||
|
var feed = { title: link.title, href: link.href, type: link.type || "" };
|
||||||
|
if (isValidFeed(feed, gDocument.nodePrincipal, rels.feed)) {
|
||||||
|
var type = feedTypes[feed.type] || feedTypes["application/rss+xml"];
|
||||||
|
addRow(feed.title, type, feed.href);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -853,73 +853,6 @@
|
|||||||
</body>
|
</body>
|
||||||
</method>
|
</method>
|
||||||
|
|
||||||
<method name="onLinkAdded">
|
|
||||||
<parameter name="event"/>
|
|
||||||
<body>
|
|
||||||
<![CDATA[
|
|
||||||
if (!this.mPrefs.getBoolPref("browser.chrome.site_icons"))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!event.originalTarget.rel.match((/(?:^|\s)icon(?:\s|$)/i)))
|
|
||||||
return;
|
|
||||||
|
|
||||||
// We have an icon.
|
|
||||||
var href = event.originalTarget.href;
|
|
||||||
if (!href)
|
|
||||||
return;
|
|
||||||
|
|
||||||
const nsIContentPolicy = Components.interfaces.nsIContentPolicy;
|
|
||||||
try {
|
|
||||||
var contentPolicy =
|
|
||||||
Components.classes['@mozilla.org/layout/content-policy;1']
|
|
||||||
.getService(nsIContentPolicy);
|
|
||||||
} catch(e) {
|
|
||||||
return; // Refuse to load if we can't do a security check.
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the IOService so we can make URIs
|
|
||||||
const ioService =
|
|
||||||
Components.classes["@mozilla.org/network/io-service;1"]
|
|
||||||
.getService(Components.interfaces.nsIIOService);
|
|
||||||
|
|
||||||
const targetDoc = event.target.ownerDocument;
|
|
||||||
// Make a URI out of our href.
|
|
||||||
var uri = ioService.newURI(href, targetDoc.characterSet, null);
|
|
||||||
try {
|
|
||||||
// Verify that the load of this icon is legal.
|
|
||||||
// error pages can load their favicon, to be on the safe side,
|
|
||||||
// only allow chrome:// favicons
|
|
||||||
const nsIScriptSecMan =
|
|
||||||
Components.interfaces.nsIScriptSecurityManager;
|
|
||||||
var secMan = Components.classes["@mozilla.org/scriptsecuritymanager;1"]
|
|
||||||
.getService(nsIScriptSecMan);
|
|
||||||
const aboutNeterr = "about:neterror?";
|
|
||||||
if (targetDoc.documentURI.substr(0, aboutNeterr.length) != aboutNeterr ||
|
|
||||||
!uri.schemeIs("chrome"))
|
|
||||||
secMan.checkLoadURIWithPrincipal(targetDoc.nodePrincipal, uri,
|
|
||||||
nsIScriptSecMan.DISALLOW_SCRIPT);
|
|
||||||
} catch(e) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Security says okay, now ask content policy
|
|
||||||
if (contentPolicy.shouldLoad(nsIContentPolicy.TYPE_IMAGE,
|
|
||||||
uri, targetDoc.documentURIObject,
|
|
||||||
event.target, event.target.type,
|
|
||||||
null) != nsIContentPolicy.ACCEPT)
|
|
||||||
return;
|
|
||||||
|
|
||||||
var browserIndex = this.getBrowserIndexForDocument(targetDoc);
|
|
||||||
// no browser? no favicon.
|
|
||||||
if (browserIndex == -1)
|
|
||||||
return;
|
|
||||||
|
|
||||||
var tab = this.mTabContainer.childNodes[browserIndex];
|
|
||||||
this.setIcon(tab, href);
|
|
||||||
]]>
|
|
||||||
</body>
|
|
||||||
</method>
|
|
||||||
|
|
||||||
<method name="onTitleChanged">
|
<method name="onTitleChanged">
|
||||||
<parameter name="evt"/>
|
<parameter name="evt"/>
|
||||||
<body>
|
<body>
|
||||||
@ -2400,8 +2333,6 @@
|
|||||||
</implementation>
|
</implementation>
|
||||||
|
|
||||||
<handlers>
|
<handlers>
|
||||||
<handler event="DOMLinkAdded" phase="capturing" action="this.onLinkAdded(event);"/>
|
|
||||||
|
|
||||||
<handler event="DOMWindowClose" phase="capturing">
|
<handler event="DOMWindowClose" phase="capturing">
|
||||||
<![CDATA[
|
<![CDATA[
|
||||||
if (!event.isTrusted)
|
if (!event.isTrusted)
|
||||||
|
|||||||
@ -50,6 +50,9 @@ _TEST_FILES = test_feed_discovery.html \
|
|||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
_BROWSER_FILES = browser_bug321000.js \
|
_BROWSER_FILES = browser_bug321000.js \
|
||||||
|
browser_autodiscovery.js \
|
||||||
|
autodiscovery.html \
|
||||||
|
moz.png \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
libs:: $(_TEST_FILES)
|
libs:: $(_TEST_FILES)
|
||||||
|
|||||||
8
mozilla/browser/base/content/test/autodiscovery.html
Normal file
8
mozilla/browser/base/content/test/autodiscovery.html
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<!DOCTYPE HTML>
|
||||||
|
<html>
|
||||||
|
<head id="linkparent">
|
||||||
|
<title>Autodiscovery Test</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
105
mozilla/browser/base/content/test/browser_autodiscovery.js
Normal file
105
mozilla/browser/base/content/test/browser_autodiscovery.js
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
function url(spec) {
|
||||||
|
var ios = Components.classes["@mozilla.org/network/io-service;1"]
|
||||||
|
.getService(Components.interfaces.nsIIOService);
|
||||||
|
return ios.newURI(spec, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
var gTestPage = null;
|
||||||
|
function test() {
|
||||||
|
waitForExplicitFinish();
|
||||||
|
var activeWin = Application.activeWindow;
|
||||||
|
gTestPage = activeWin.open(url("chrome://mochikit/content/browser/browser/base/content/test/autodiscovery.html"));
|
||||||
|
gTestPage.focus();
|
||||||
|
setTimeout(iconDiscovery, 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
function iconDiscovery() {
|
||||||
|
var tests = [
|
||||||
|
{ text: "rel icon discovered" },
|
||||||
|
{ rel: "abcdefg icon qwerty", text: "rel may contain additional rels separated by spaces" },
|
||||||
|
{ rel: "ICON", text: "rel is case insensitive" },
|
||||||
|
{ rel: "shortcut-icon", pass: false, text: "rel shortcut-icon not discovered" },
|
||||||
|
{ href: "moz.png", text: "relative href works" },
|
||||||
|
{ href: "notthere.png", text: "404'd icon is removed properly" },
|
||||||
|
{ href: "data:image/x-icon,%00", type: "image/x-icon", text: "data: URIs work" },
|
||||||
|
{ type: "image/png; charset=utf-8", text: "type may have optional parameters (RFC2046)" }
|
||||||
|
];
|
||||||
|
|
||||||
|
for (let i = 0; i < tests.length; i++) {
|
||||||
|
gProxyFavIcon.removeAttribute("src");
|
||||||
|
|
||||||
|
var test = tests[i];
|
||||||
|
var head = gTestPage.document.getElementById("linkparent");
|
||||||
|
var link = gTestPage.document.createElement("link");
|
||||||
|
|
||||||
|
var rel = test.rel || "icon";
|
||||||
|
var href = test.href || "chrome://mochikit/content/browser/browser/base/content/test/moz.png";
|
||||||
|
var type = test.type || "image/png";
|
||||||
|
if (test.pass == undefined)
|
||||||
|
test.pass = true;
|
||||||
|
|
||||||
|
link.rel = rel;
|
||||||
|
link.href = href;
|
||||||
|
link.type = type;
|
||||||
|
head.appendChild(link);
|
||||||
|
|
||||||
|
var hasSrc = gProxyFavIcon.hasAttribute("src");
|
||||||
|
if (test.pass)
|
||||||
|
ok(hasSrc, test.text);
|
||||||
|
else
|
||||||
|
ok(!hasSrc, test.text);
|
||||||
|
|
||||||
|
head.removeChild(link);
|
||||||
|
}
|
||||||
|
searchDiscovery();
|
||||||
|
}
|
||||||
|
|
||||||
|
function searchDiscovery() {
|
||||||
|
var tests = [
|
||||||
|
{ text: "rel search discovered" },
|
||||||
|
{ rel: "SEARCH", text: "rel is case insensitive" },
|
||||||
|
{ rel: "-search-", pass: false, text: "rel -search- not discovered" },
|
||||||
|
{ rel: "foo bar baz search quux", text: "rel may contain additional rels separated by spaces" },
|
||||||
|
{ href: "https://not.mozilla.com", text: "HTTPS ok" },
|
||||||
|
{ href: "ftp://not.mozilla.com", text: "FTP ok" },
|
||||||
|
{ href: "data:text/foo,foo", pass: false, text: "data URI not permitted" },
|
||||||
|
{ href: "javascript:alert(0)", pass: false, text: "JS URI not permitted" },
|
||||||
|
{ type: "APPLICATION/OPENSEARCHDESCRIPTION+XML", text: "type is case insensitve" },
|
||||||
|
{ type: " application/opensearchdescription+xml ", text: "type may contain extra whitespace" },
|
||||||
|
{ type: "application/opensearchdescription+xml; charset=utf-8", text: "type may have optional parameters (RFC2046)" },
|
||||||
|
{ type: "aapplication/opensearchdescription+xml", pass: false, text: "type should not be loosely matched" },
|
||||||
|
{ rel: "search search search", count: 1, text: "only one engine should be added" }
|
||||||
|
];
|
||||||
|
|
||||||
|
for (let i = 0; i < tests.length; i++) {
|
||||||
|
var test = tests[i];
|
||||||
|
var head = gTestPage.document.getElementById("linkparent");
|
||||||
|
var link = gTestPage.document.createElement("link");
|
||||||
|
|
||||||
|
var rel = test.rel || "search";
|
||||||
|
var href = test.href || "http://so.not.here.mozilla.com/search.xml";
|
||||||
|
var type = test.type || "application/opensearchdescription+xml";
|
||||||
|
var title = test.title || i;
|
||||||
|
if (test.pass == undefined)
|
||||||
|
test.pass = true;
|
||||||
|
|
||||||
|
link.rel = rel;
|
||||||
|
link.href = href;
|
||||||
|
link.type = type;
|
||||||
|
link.title = title;
|
||||||
|
head.appendChild(link);
|
||||||
|
|
||||||
|
var browser = gBrowser.getBrowserForDocument(gTestPage.document);
|
||||||
|
if (browser.engines) {
|
||||||
|
var hasEngine = (test.count) ? (browser.engines[0].title == title &&
|
||||||
|
browser.engines.length == test.count) :
|
||||||
|
(browser.engines[0].title == title);
|
||||||
|
ok(hasEngine, test.text);
|
||||||
|
browser.engines = null;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ok(!test.pass, test.text);
|
||||||
|
}
|
||||||
|
gTestPage.close();
|
||||||
|
finish();
|
||||||
|
}
|
||||||
BIN
mozilla/browser/base/content/test/moz.png
Executable file
BIN
mozilla/browser/base/content/test/moz.png
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 580 B |
@ -586,68 +586,48 @@ function openNewWindowWith(aURL, aDocument, aPostData, aAllowThirdPartyFixup,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* recognizeFeedFromLink: recognizes RSS/ATOM feeds from DOM link elements.
|
* isValidFeed: checks whether the given data represents a valid feed.
|
||||||
*
|
*
|
||||||
* @param aLink
|
* @param aData
|
||||||
* The DOM link element to check for representing a feed.
|
* An object representing a feed with title, href and type.
|
||||||
* @param aPrincipal
|
* @param aPrincipal
|
||||||
* The principal of the document, used for security check.
|
* The principal of the document, used for security check.
|
||||||
* @return object
|
* @param aIsFeed
|
||||||
* The feed object containing href, type, and title properties,
|
* Whether this is already a known feed or not, if true only a security
|
||||||
* if successful, otherwise null.
|
* check will be performed.
|
||||||
*/
|
*/
|
||||||
function recognizeFeedFromLink(aLink, aPrincipal)
|
function isValidFeed(aData, aPrincipal, aIsFeed)
|
||||||
{
|
{
|
||||||
if (!aLink || !aPrincipal)
|
if (!aData || !aPrincipal)
|
||||||
return null;
|
return false;
|
||||||
|
|
||||||
var erel = aLink.rel && aLink.rel.toLowerCase();
|
if (!aIsFeed) {
|
||||||
var etype = aLink.type && aLink.type.toLowerCase();
|
var type = aData.type && aData.type.toLowerCase();
|
||||||
var etitle = aLink.title;
|
type = type.replace(/^\s+|\s*(?:;.*)?$/g, "");
|
||||||
const rssTitleRegex = /(^|\s)rss($|\s)/i;
|
|
||||||
var rels = {};
|
|
||||||
|
|
||||||
if (erel) {
|
aIsFeed = (type == "application/rss+xml" ||
|
||||||
for each (var relValue in erel.split(/\s+/))
|
type == "application/atom+xml");
|
||||||
rels[relValue] = true;
|
|
||||||
}
|
|
||||||
var isFeed = rels.feed;
|
|
||||||
|
|
||||||
if (!isFeed && (!rels.alternate || rels.stylesheet || !etype))
|
if (!aIsFeed) {
|
||||||
return null;
|
|
||||||
|
|
||||||
if (!isFeed) {
|
|
||||||
// Use type value
|
|
||||||
etype = etype.replace(/^\s+/, "");
|
|
||||||
etype = etype.replace(/\s+$/, "");
|
|
||||||
etype = etype.replace(/\s*;.*/, "");
|
|
||||||
isFeed = (etype == "application/rss+xml" ||
|
|
||||||
etype == "application/atom+xml");
|
|
||||||
if (!isFeed) {
|
|
||||||
// really slimy: general XML types with magic letters in the title
|
// really slimy: general XML types with magic letters in the title
|
||||||
isFeed = ((etype == "text/xml" || etype == "application/xml" ||
|
const titleRegex = /(^|\s)rss($|\s)/i;
|
||||||
etype == "application/rdf+xml") && rssTitleRegex.test(etitle));
|
aIsFeed = ((type == "text/xml" || type == "application/rdf+xml" ||
|
||||||
|
type == "application/xml") && titleRegex.test(aData.title));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isFeed) {
|
if (aIsFeed) {
|
||||||
try {
|
try {
|
||||||
urlSecurityCheck(aLink.href,
|
urlSecurityCheck(aData.href, aPrincipal,
|
||||||
aPrincipal,
|
|
||||||
Components.interfaces.nsIScriptSecurityManager.DISALLOW_INHERIT_PRINCIPAL);
|
Components.interfaces.nsIScriptSecurityManager.DISALLOW_INHERIT_PRINCIPAL);
|
||||||
}
|
}
|
||||||
catch (ex) {
|
catch(ex) {
|
||||||
dump(ex.message);
|
aIsFeed = false;
|
||||||
return null; // doesn't pass security check
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// successful! return the feed
|
|
||||||
return {
|
|
||||||
href: aLink.href,
|
|
||||||
type: etype,
|
|
||||||
title: aLink.title
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
if (type)
|
||||||
|
aData.type = type;
|
||||||
|
|
||||||
|
return aIsFeed;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user