Wire up new feed processor to Zotero's feed reader

This connects the new feed processor to Zotero's existing feed reader. The new
feed processor assumes a content window environment, so a sandbox in a parent
window is used to load it.
This commit is contained in:
J. Ryan Stinnett 2021-05-22 18:44:42 +01:00
parent 2bd4904ead
commit eaa01901ef
3 changed files with 72 additions and 21 deletions

View file

@ -130,11 +130,49 @@ Zotero.FeedReader = function (url) {
lastItem.resolve(null);
}.bind(this));
// Set up asynchronous feed processor
let feedProcessor = Components.classes["@mozilla.org/feed-processor;1"]
.createInstance(Components.interfaces.nsIFeedProcessor);
// The feed processor and related modules assume a content window environment, so we'll simulate
// one via a sandbox in a parent window. You might think we could jump straight to
// `hiddenDOMWindow` as a parent window, since it does indeed exist on all platforms...
// However, when loading scripts into the `hiddenDOMWindow` on Windows and Linux, they get
// stuck in some lazily parsed state which bizarrely drops function prototypes. To avoid this,
// we prefer other parent windows first, which work fine on all platforms.
let parentWindow = Services.wm.getMostRecentWindow("navigator:browser");
if (!parentWindow) {
parentWindow = Services.ww.activeWindow;
}
// Use the hidden DOM window on macOS with the main window closed
if (!parentWindow) {
parentWindow = Services.appShell.hiddenDOMWindow;
}
if (!parentWindow) {
this.terminate("Parent window not available for feed reader");
return;
}
let feedUrl = Services.io.newURI(url, null, null);
const sandbox = new Cu.Sandbox(parentWindow, {
sandboxPrototype: parentWindow,
sandboxName: "Feed Processor",
});
sandbox.Zotero = {
debug: Components.utils.exportFunction(Zotero.debug, sandbox),
};
Services.scriptloader.loadSubScript("resource://zotero/feeds/FeedProcessor.js", sandbox);
Services.scriptloader.loadSubScript("resource://zotero/feeds/SAXXMLReader.js", sandbox);
// Set up asynchronous feed processor
const { FeedProcessor } = sandbox;
const feedProcessor = new FeedProcessor();
if (!feedProcessor.parseAsync) {
this.terminate("Feed processor failed to load in parent window");
return;
}
// Borrow web utils to fetch feed content
const { fetch, URL } = parentWindow;
// Pass along the URL
const feedUrl = new URL(url);
feedProcessor.parseAsync(null, feedUrl);
/*
@ -148,19 +186,21 @@ Zotero.FeedReader = function (url) {
this.terminate("No Feed");
return;
}
let newFeed = result.doc.QueryInterface(Components.interfaces.nsIFeed);
feedFetched.resolve(newFeed);
feedFetched.resolve(result.doc);
}
};
Zotero.debug("FeedReader: Fetching feed from " + feedUrl.spec);
Zotero.debug("FeedReader: Fetching feed from " + feedUrl);
this._channel = Services.io.newChannelFromURI2(feedUrl, null,
Services.scriptSecurityManager.getSystemPrincipal(), null,
Ci.nsILoadInfo.SEC_NORMAL, Ci.nsIContentPolicy.TYPE_OTHER);
this._channel.loadFlags |= Components.interfaces.nsIRequest.LOAD_BYPASS_CACHE;
this._channel.asyncOpen(feedProcessor, null); // Sends an HTTP request
// Fetch and start processing
fetch(feedUrl, {
cache: "no-store",
}).then((response) => {
return feedProcessor.onResponseAvailable(response);
}).catch((e) => {
Zotero.debug(e);
this.terminate("Processing failed");
});
};
/*
@ -195,11 +235,6 @@ Zotero.FeedReader.prototype.terminate = function (status) {
er.handledRejection = true;
lastItem.reject(er);
}
// Close feed connection
if (this._channel.isPending()) {
this._channel.cancel(Components.results.NS_BINDING_ABORTED);
}
};
Zotero.defineProperty(Zotero.FeedReader.prototype, 'feedProperties', {

View file

@ -35,8 +35,18 @@ describe("Zotero.FeedReader", function () {
var atomFeedURL = getTestDataUrl("feed.atom");
var mediaFeedURL = getTestDataUrl("feedMedia.xml");
after(function* () {
yield clearFeeds();
var win;
before(async function() {
// Browser window is needed as parent window to load the feed reader scripts.
win = await loadBrowserWindow();
});
after(async function() {
if (win) {
win.close();
}
await clearFeeds();
});
describe('FeedReader()', function () {

View file

@ -311,8 +311,11 @@ describe("Zotero.Feed", function() {
var feed, scheduleNextFeedCheck;
var feedUrl = getTestDataUrl("feed.rss");
var modifiedFeedUrl = getTestDataUrl("feedModified.rss");
var win;
before(function() {
before(async function() {
// Browser window is needed as parent window to load the feed reader scripts.
win = await loadBrowserWindow();
scheduleNextFeedCheck = sinon.stub(Zotero.Feeds, 'scheduleNextFeedCheck').resolves();
});
@ -328,6 +331,9 @@ describe("Zotero.Feed", function() {
});
after(function() {
if (win) {
win.close();
}
scheduleNextFeedCheck.restore();
});