Fix all cookies being lost during remote translation (#5358)

This commit is contained in:
Abe Jellinek 2025-06-25 10:26:38 -04:00 committed by Dan Stillman
parent 556b571da2
commit 12f344e03d
3 changed files with 90 additions and 14 deletions

View file

@ -23,6 +23,8 @@
***** END LICENSE BLOCK *****
*/
Cu.import("resource://gre/modules/NetUtil.jsm");
/**
* Functions for performing HTTP requests, both via XMLHTTPRequest and using a hidden browser
* @namespace
@ -106,6 +108,15 @@ Zotero.HTTP = new function() {
var promise = Zotero.HTTP._attachHandlers(url, xmlhttp, options);
xmlhttp.open(method, url, true);
// Overwrite the system nsILoadInfo with one tied to our document
// so CookieSandbox can identify the source of the XHR
xmlhttp.channel.loadInfo = NetUtil.newChannel({
uri: url,
loadingNode: document,
securityFlags: Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_INHERITS_SEC_CONTEXT,
contentPolicyType: Ci.nsIContentPolicy.TYPE_XMLHTTPREQUEST,
}).loadInfo;
for (let header in options.headers) {
xmlhttp.setRequestHeader(header, options.headers[header]);

View file

@ -55,7 +55,6 @@ Zotero.CookieSandbox = function (browser, uri, cookieData, userAgent) {
this._observerService = Components.classes["@mozilla.org/observer-service;1"].
getService(Components.interfaces.nsIObserverService);
Zotero.CookieSandbox.Observer.register();
if (browser) {
this.attachToBrowser(browser);
}
@ -343,18 +342,30 @@ Zotero.CookieSandbox.Observer = new function() {
// Zotero.debug(`CookieSandbox: Found the browser via doc of load group for ${channelURI}`, 5);
trackedBy = this.trackedBrowsers.get(browser);
}
else if (notificationCallbacks instanceof XMLHttpRequest) {
// Zotero.debug(`CookieSandbox: Found the browser via XHR for ${channelURI}`, 5);
tested = true;
}
else {
// try getting as an nsIWBP
// System XHR created from TranslationChild only has browser identifiers in loadInfo
try {
notificationCallbacks.QueryInterface(Components.interfaces.nsIWebBrowserPersist);
// Zotero.debug(`CookieSandbox: Found the browser via nsIWBP for ${channelURI}`, 5);
tested = true;
browser = channel.loadInfo.targetBrowsingContext.embedderElement;
}
catch (e) {}
if (browser) {
tested = true;
// Zotero.debug(`CookieSandbox: Found the browser via load info BrowsingContext for ${channelURI}`, 5);
trackedBy = this.trackedBrowsers.get(browser);
}
else if (notificationCallbacks instanceof XMLHttpRequest) {
// Zotero.debug(`CookieSandbox: Found the browser via XHR for ${channelURI}`, 5);
tested = true;
}
else {
// try getting as an nsIWBP
try {
notificationCallbacks.QueryInterface(Components.interfaces.nsIWebBrowserPersist);
// Zotero.debug(`CookieSandbox: Found the browser via nsIWBP for ${channelURI}`, 5);
tested = true;
}
catch (e) {}
}
}
}
}

View file

@ -6,7 +6,10 @@ const { RemoteTranslate } = ChromeUtils.import("chrome://zotero/content/RemoteTr
describe("RemoteTranslate", function () {
let dummyTranslator;
let translatorProvider;
before(function () {
let httpd;
let port = 16213;
before(async function () {
dummyTranslator = buildDummyTranslator('web', `
function detectWeb() {
Zotero.debug("test string");
@ -36,6 +39,29 @@ describe("RemoteTranslate", function () {
return translators;
}
});
var { HttpServer } = ChromeUtils.import("chrome://remote/content/server/HTTPD.jsm");
httpd = new HttpServer();
httpd.start(port);
httpd.registerPathHandler(
'/readCookie',
{
handle: function (request, response) {
if (request.getHeader('Cookie') === 'sessionID=1') {
response.setStatusLine(null, 200, 'OK');
response.write('OK');
}
else {
response.setStatusLine(null, 403, 'Forbidden');
response.write('Header not set');
}
}
}
);
});
after(async function () {
await new Promise(resolve => httpd.stop(resolve));
});
describe("#setHandler()", function () {
@ -141,7 +167,7 @@ describe("RemoteTranslate", function () {
});
it("should support DOMParser", async function () {
let domParserDummy = buildDummyTranslator('web', `
let dummy = buildDummyTranslator('web', `
function detectWeb() {
return "book";
}
@ -157,7 +183,7 @@ describe("RemoteTranslate", function () {
let browser = new HiddenBrowser();
await browser.load(getTestDataUrl('test.html'));
await translate.setBrowser(browser);
translate.setTranslator(domParserDummy);
translate.setTranslator(dummy);
let items = await translate.translate({ libraryID: false });
assert.equal(items[0].title, 'content');
@ -167,7 +193,7 @@ describe("RemoteTranslate", function () {
});
it("should be able to access hidden prefs", async function () {
let domParserDummy = buildDummyTranslator('web', `
let dummy = buildDummyTranslator('web', `
function detectWeb() {
return "book";
}
@ -185,7 +211,7 @@ describe("RemoteTranslate", function () {
let browser = new HiddenBrowser();
await browser.load(getTestDataUrl('test.html'));
await translate.setBrowser(browser);
translate.setTranslator(domParserDummy);
translate.setTranslator(dummy);
let items = await translate.translate({ libraryID: false });
assert.equal(items[0].title, 'Test value');
@ -193,5 +219,33 @@ describe("RemoteTranslate", function () {
browser.destroy();
translate.dispose();
});
it("should send cookies", async function () {
let dummy = buildDummyTranslator('web', `
function detectWeb() {
return "book";
}
async function doWeb() {
let item = new Zotero.Item("book");
item.title = await requestText("http://localhost:${port}/readCookie", {
headers: { Cookie: "sessionID=1" },
});
item.complete();
}
`);
let translate = new RemoteTranslate();
let browser = new HiddenBrowser();
await browser.load(getTestDataUrl('test.html'));
await translate.setBrowser(browser);
translate.setTranslator(dummy);
let items = await translate.translate({ libraryID: false });
assert.equal(items[0].title, 'OK');
browser.destroy();
translate.dispose();
});
});
});