Bug 1107588 - Use an xhr to download reader mode content instead of creating new browser elements. r=mfinkle

--HG--
extra : rebase_source : fe24bfefa2efc5500ca74a9be5f79a958bab32ee
This commit is contained in:
Margaret Leibovic 2014-12-30 14:56:09 -05:00
parent 920d7d1b2a
commit e98ae2130e
3 changed files with 51 additions and 59 deletions

View File

@ -69,7 +69,7 @@ add_task(function* test_remove_article() {
add_task(function* test_parse_articles() {
for (let testcase of TEST_PAGES) {
let article = yield Reader._downloadAndParseDocument(testcase.url);
let article = yield ReaderMode.downloadAndParseDocument(testcase.url);
checkArticle(article, testcase);
}
});

View File

@ -170,62 +170,7 @@ let Reader = {
// Article hasn't been found in the cache, we need to
// download the page and parse the article out of it.
return yield this._downloadAndParseDocument(url);
}),
_downloadDocument: function (url) {
return new Promise((resolve, reject) => {
// We want to parse those arbitrary pages safely, outside the privileged
// context of chrome. We create a hidden browser element to fetch the
// loaded page's document object then discard the browser element.
let browser = document.createElement("browser");
browser.setAttribute("type", "content");
browser.setAttribute("collapsed", "true");
browser.setAttribute("disablehistory", "true");
document.documentElement.appendChild(browser);
browser.stop();
browser.webNavigation.allowAuth = false;
browser.webNavigation.allowImages = false;
browser.webNavigation.allowJavascript = false;
browser.webNavigation.allowMetaRedirects = true;
browser.webNavigation.allowPlugins = false;
browser.addEventListener("DOMContentLoaded", event => {
let doc = event.originalTarget;
// ignore on frames and other documents
if (doc != browser.contentDocument) {
return;
}
if (doc.location.href == "about:blank") {
reject("about:blank loaded; aborting");
// Request has finished with error, remove browser element
browser.parentNode.removeChild(browser);
return;
}
resolve({ browser, doc });
});
browser.loadURIWithFlags(url, Ci.nsIWebNavigation.LOAD_FLAGS_NONE,
null, null, null);
});
},
_downloadAndParseDocument: Task.async(function* (url) {
let { browser, doc } = yield this._downloadDocument(url);
try {
let uri = Services.io.newURI(url, null, null);
let article = yield ReaderMode.readerParse(uri, doc);
return article;
} finally {
browser.parentNode.removeChild(browser);
}
return yield ReaderMode.downloadAndParseDocument(url);
}),
/**

View File

@ -61,9 +61,56 @@ let ReaderMode = {
}
let doc = browser.contentWindow.document;
return yield this.readerParse(uri, doc);
return yield this._readerParse(uri, doc);
}),
/**
* Downloads and parses a document from a URL.
*
* @param url URL to download and parse.
* @return {Promise}
* @resolves JS object representing the article, or null if no article is found.
*/
downloadAndParseDocument: Task.async(function* (url) {
let uri = Services.io.newURI(url, null, null);
let doc = yield this._downloadDocument(url);
return yield this._readerParse(uri, doc);
}),
_downloadDocument: function (url) {
return new Promise((resolve, reject) => {
let xhr = new XMLHttpRequest();
xhr.open("GET", url, true);
xhr.onerror = evt => reject(evt.error);
xhr.responseType = "document";
xhr.onload = evt => {
if (xhr.status !== 200) {
reject("Reader mode XHR failed with status: " + xhr.status);
return;
}
let doc = xhr.responseXML;
// Manually follow a meta refresh tag if one exists.
let meta = doc.querySelector("meta[http-equiv=refresh]");
if (meta) {
let content = meta.getAttribute("content");
if (content) {
let urlIndex = content.indexOf("URL=");
if (urlIndex > -1) {
let url = content.substring(urlIndex + 4);
this._downloadDocument(url).then((doc) => resolve(doc));
return;
}
}
}
resolve(doc);
}
xhr.send();
});
},
/**
* Retrieves an article from the cache given an article URI.
*
@ -138,7 +185,7 @@ let ReaderMode = {
* @return {Promise}
* @resolves JS object representing the article, or null if no article is found.
*/
readerParse: function (uri, doc) {
_readerParse: function (uri, doc) {
return new Promise((resolve, reject) => {
let numTags = doc.getElementsByTagName("*").length;
if (numTags > this.MAX_ELEMS_TO_PARSE) {