diff --git a/chrome/content/zotero/xpcom/attachments.js b/chrome/content/zotero/xpcom/attachments.js index 4aa95a64d4..0ebfbc7fa1 100644 --- a/chrome/content/zotero/xpcom/attachments.js +++ b/chrome/content/zotero/xpcom/attachments.js @@ -1175,7 +1175,6 @@ Zotero.Attachments = new function () { this.downloadFile = async function (url, path, options = {}) { Zotero.debug(`Downloading file from ${url}`); - let enforcingFileType = false; try { let headers = {}; if (options.referrer) { @@ -1189,9 +1188,8 @@ Zotero.Attachments = new function () { cookieSandbox: options.cookieSandbox } ); - + // Check that the downloaded file is the expected type if (options.enforceFileType) { - enforcingFileType = true; await _enforceFileType(path); } } @@ -1202,9 +1200,13 @@ Zotero.Attachments = new function () { catch (e) { Zotero.logError(e); } - // Custom handling for PDFs that are bot-guarded - // via a JS-redirect - if (enforcingFileType && e instanceof this.InvalidPDFException) { + // Custom handling for files that are bot-guarded via a JS redirect and/or that require + // a CAPTCHA + if (options.enforceFileType + // Thrown by _enforceFileType() + && (e instanceof this.InvalidPDFException + // Thrown by HTTP.download() + || (e instanceof Zotero.HTTP.UnexpectedStatusException && e.status == 403))) { if (Zotero.BrowserDownload.shouldAttemptDownloadViaBrowser(url)) { return Zotero.BrowserDownload.downloadPDF(url, path, options); } diff --git a/test/tests/attachmentsTest.js b/test/tests/attachmentsTest.js index 5aebff446a..7d3cc4d563 100644 --- a/test/tests/attachmentsTest.js +++ b/test/tests/attachmentsTest.js @@ -609,6 +609,58 @@ describe("Zotero.Attachments", function() { }); }); + describe("#downloadFile()", function () { + var httpd; + var testServerPort; + + before(async () => { + ({ httpd, port: testServerPort } = await startHTTPServer()); + }); + + + after(async () => { + await new Promise((resolve) => { + httpd.stop(() => resolve()); + }); + }); + + it("should use BrowserDownload for 403 when enforcing file type", async function () { + let prefix = Zotero.Utilities.randomString(); + let testServerPath = 'http://127.0.0.1:' + testServerPort + '/' + prefix; + let pdfURL = testServerPath + '/test.pdf'; + httpd.registerPathHandler( + "/" + prefix + '/test.pdf', + { + handle: function (request, response) { + response.setStatusLine(null, 403, "Forbidden"); + response.write("Forbidden"); + } + } + ); + + let path = OS.Path.join(Zotero.getTempDirectory().path, 'test.pdf'); + let shouldAttemptStub = sinon.stub(Zotero.BrowserDownload, "shouldAttemptDownloadViaBrowser"); + let downloadPDFStub = sinon.stub(Zotero.BrowserDownload, "downloadPDF"); + shouldAttemptStub.returns(true); + downloadPDFStub.callsFake(async (_url, path) => { + await OS.File.copy(OS.Path.join(getTestDataDirectory().path, 'test.pdf'), path); + }); + var item; + try { + item = await Zotero.Attachments.downloadFile(pdfURL, path, { enforceFileType: true }); + + assert.isTrue(shouldAttemptStub.calledOnce); + assert.isTrue(downloadPDFStub.calledOnce); + } + finally { + // Clean up + if (item) await Zotero.Items.erase(item.id); + downloadPDFStub.restore(); + shouldAttemptStub.restore(); + } + }); + }); + describe("Find Full Text", function () { var doiPrefix = 'https://doi.org/'; var doi1 = '10.1111/abcd';