diff --git a/chrome/content/zotero/xpcom/http.js b/chrome/content/zotero/xpcom/http.js index 712394eb0f..0c1b2b9dd8 100644 --- a/chrome/content/zotero/xpcom/http.js +++ b/chrome/content/zotero/xpcom/http.js @@ -694,7 +694,9 @@ Zotero.HTTP = new function () { // Build headers let headers = new Zotero.HTTP.CasePreservingHeaders(options.headers || {}); if (ctx.username) { - let encoded = btoa(ctx.username + ':' + (ctx.password || '')); + // Encode as UTF-8 before base64, since btoa() only accepts code points below 256 + let bytes = new TextEncoder().encode(ctx.username + ':' + (ctx.password || '')); + let encoded = btoa(String.fromCharCode(...bytes)); headers.set('Authorization', `Basic ${encoded}`); } fetchOptions.headers = headers; diff --git a/test/tests/httpTest.js b/test/tests/httpTest.js index 892b9bd4e1..4986a93415 100644 --- a/test/tests/httpTest.js +++ b/test/tests/httpTest.js @@ -454,15 +454,16 @@ describe("Zotero.HTTP", function () { '/download/auth', { handle: function (request, response) { - let val; - try { - val = request.getHeader("Authorization"); - } - catch (e) { - val = ""; + if (!request.hasHeader("Authorization")) { + response.setStatusLine(null, 401, "Unauthorized"); + response.setHeader("WWW-Authenticate", 'Basic realm="Test"', false); + response.write("denied"); + return; } response.setStatusLine(null, 200, "OK"); - response.setHeader("X-Echo-Auth", val, false); + response.setHeader( + "X-Echo-Auth", request.getHeader("Authorization"), false + ); response.write("ok"); } } @@ -610,6 +611,20 @@ describe("Zotero.HTTP", function () { assert.equal(req.status, 200); assert.equal(req.headers.get("X-Echo-Auth"), expected); }); + + it("should encode non-ASCII credentials the same way as request()", async function () { + let url = `http://user:p%C3%A4ssw%E2%82%ACrd` + + `@127.0.0.1:${port}/download/auth`; + let dest = PathUtils.join(tmpDir, "auth-utf8.bin"); + let req = await Zotero.HTTP.download(Services.io.newURI(url), dest); + assert.equal(req.status, 200); + + let xmlhttp = await Zotero.HTTP.request("GET", url); + assert.equal( + req.headers.get("X-Echo-Auth"), + xmlhttp.getResponseHeader("X-Echo-Auth") + ); + }); });