diff --git a/chrome/content/zotero/xpcom/http.js b/chrome/content/zotero/xpcom/http.js index 09119b2ac3..8e564e3e28 100644 --- a/chrome/content/zotero/xpcom/http.js +++ b/chrome/content/zotero/xpcom/http.js @@ -15,8 +15,8 @@ Zotero.HTTP = new function () { * Parse a URI (nsIURI or string), extract any embedded credentials, and * return the URL as a credential-free string * - * Mozilla percent-encodes periods in the username component of nsIURIs (%2E), which is - * technically valid but breaks Basic auth against most servers, so we undo that here. + * nsIURI returns the username and password percent-encoded, so we decode them so + * callers can use them directly (e.g., when building a Basic auth header). * * @param {nsIURI|String} uri * @return {{ url: String, username: String|null, password: String|null }} @@ -30,11 +30,9 @@ Zotero.HTTP = new function () { return { url: uri, username: null, password: null }; } } - let username = uri.username || null; - let password = null; + let username = uri.username ? decodeURIComponent(uri.username) : null; + let password = uri.password ? decodeURIComponent(uri.password) : null; if (username) { - username = username.replace(/%2E/, '.'); - password = uri.password || null; uri = uri.mutate().setUserPass('').finalize(); } return { url: uri.spec, username, password }; diff --git a/test/tests/httpTest.js b/test/tests/httpTest.js index 610ee9166d..15cfbb9f4a 100644 --- a/test/tests/httpTest.js +++ b/test/tests/httpTest.js @@ -421,6 +421,23 @@ describe("Zotero.HTTP", function () { } } ); + httpd.registerPathHandler( + '/download/auth', + { + handle: function (request, response) { + let val; + try { + val = request.getHeader("Authorization"); + } + catch (e) { + val = ""; + } + response.setStatusLine(null, 200, "OK"); + response.setHeader("X-Echo-Auth", val, false); + response.write("ok"); + } + } + ); }); beforeEach(async function () { @@ -551,6 +568,19 @@ describe("Zotero.HTTP", function () { let stat = await IOUtils.stat(dest); assert.equal(stat.size, 3 * 1024); }); + + it("should decode percent-encoded credentials from URL for Basic auth", async function () { + let username = "user@example.com"; + let password = "secret"; + let expected = "Basic " + btoa(username + ":" + password); + let url = `http://${encodeURIComponent(username)}:${password}` + + `@127.0.0.1:${port}/download/auth`; + let dest = PathUtils.join(tmpDir, "auth.bin"); + let nsUri = Services.io.newURI(url); + let req = await Zotero.HTTP.download(nsUri, dest); + assert.equal(req.status, 200); + assert.equal(req.headers.get("X-Echo-Auth"), expected); + }); });