Send cookies and Referer from HTTP.download()

Since the switch to fetch() in 0fe31b0f04 (Zotero 10.0.0), download
requests didn't use cookies, and the Referer header was silently dropped
as a forbidden header. Sites that check either -- e.g., IEEE Xplore,
which returns a 502 -- failed during Find Full Text.

https://forums.zotero.org/discussion/133703/

(cherry picked from commit 364181f4e7)
This commit is contained in:
Dan Stillman 2026-10-05 14:14:37 -04:00
parent f6b6643604
commit f590efa63e
2 changed files with 47 additions and 0 deletions

View file

@ -707,7 +707,16 @@ Zotero.HTTP = new function () {
let encoded = btoa(String.fromCharCode(...bytes));
headers.set('Authorization', `Basic ${encoded}`);
}
// fetch() drops Referer as a forbidden header, so pass it as the request referrer
let referrer = headers.get('Referer');
if (referrer) {
headers.delete('Referer');
fetchOptions.referrer = referrer;
fetchOptions.referrerPolicy = 'unsafe-url';
}
fetchOptions.headers = headers;
// Send cookies, except for requests with embedded credentials, matching request()
fetchOptions.credentials = ctx.username ? 'omit' : 'include';
// Start the request with a connect timeout
let connectTimerID;

View file

@ -450,6 +450,20 @@ describe("Zotero.HTTP", function () {
}
}
);
httpd.registerPathHandler(
'/download/referer',
{
handle: function (request, response) {
response.setStatusLine(null, 200, "OK");
response.setHeader(
"X-Echo",
request.hasHeader("Referer") ? request.getHeader("Referer") : "",
false
);
response.write("ok");
}
}
);
httpd.registerPathHandler(
'/download/auth',
{
@ -515,6 +529,30 @@ describe("Zotero.HTTP", function () {
assert.equal(req.headers.get("X-Echo"), "test-value");
});
it("should send a Referer header", async function () {
let dest = PathUtils.join(tmpDir, "referer.bin");
let referrer = baseURL + "article";
let req = await Zotero.HTTP.download(
baseURL + "download/referer",
dest,
{
headers: { Referer: referrer }
}
);
assert.equal(req.headers.get("X-Echo"), referrer);
});
it("should send cookies", async function () {
Services.cookies.removeAll();
let url = baseURL + "cookie-check";
// Set the cookie
await Zotero.HTTP.request('GET', url, { successCodes: false });
let dest = PathUtils.join(tmpDir, "cookie.bin");
let req = await Zotero.HTTP.download(url, dest, { successCodes: false });
assert.equal(req.status, 200);
});
it("should throw UnexpectedStatusException for non-success status", async function () {
let dest = PathUtils.join(tmpDir, "404.bin");
let e = await getPromiseError(