From e09295ee7691083cf1848a6bf402182e3a2e3b36 Mon Sep 17 00:00:00 2001 From: Dan Stillman Date: Wed, 1 May 2013 06:29:31 -0400 Subject: [PATCH] Fix compatibility with authenticated proxies It's not clear when this became an issue, but our usual background HTTP requests (set that way to avoid triggering auth prompts when saving from websites) weren't triggering proxy authentication dialogs, which was breaking most network activity in Standalone. To fix this, we now make a foreground request at startup to a file on S3 and resolve the Zotero.proxyAuthComplete promise when we're done. Any network requests that want to wait for proxy authentication can wait for that promise. This behavior can be disabled via the triggerProxyAuthentication hidden pref. --- chrome/content/zotero/xpcom/http.js | 47 +++++++++++++++++++++++++++ chrome/content/zotero/xpcom/schema.js | 11 +++++-- chrome/content/zotero/xpcom/zotero.js | 3 ++ chrome/content/zotero/zoteroPane.js | 7 ++-- defaults/preferences/zotero.js | 1 + 5 files changed, 65 insertions(+), 4 deletions(-) diff --git a/chrome/content/zotero/xpcom/http.js b/chrome/content/zotero/xpcom/http.js index d1721fb6f..fd52a66ec 100644 --- a/chrome/content/zotero/xpcom/http.js +++ b/chrome/content/zotero/xpcom/http.js @@ -440,6 +440,53 @@ Zotero.HTTP = new function() { return xmlhttp; } + + /** + * Make a foreground HTTP request in order to trigger a proxy authentication + * dialog in Standalone + * + * Other Zotero.HTTP requests are background requests by default, and + * background requests don't trigger a proxy auth prompt, so we make a + * foreground request on startup and resolve the promise + * Zotero.proxyAuthComplete when we're done. Any network requests that want + * to wait for proxy authentication can wait for that promise. + */ + this.triggerProxyAuth = function () { + if (!Zotero.isStandalone + || !Zotero.Prefs.get("triggerProxyAuthentication") + || Zotero.HTTP.browserIsOffline()) { + Zotero.proxyAuthComplete = Q(); + return false; + } + + var deferred = Q.defer(); + Zotero.proxyAuthComplete = deferred.promise; + + var uri = ZOTERO_CONFIG.PROXY_AUTH_URL; + + Zotero.debug("HTTP GET " + uri); + + var xmlhttp = Components.classes["@mozilla.org/xmlextras/xmlhttprequest;1"] + .createInstance(); + xmlhttp.open("GET", uri, true); + + xmlhttp.channel.loadFlags |= Components.interfaces.nsIRequest.LOAD_BYPASS_CACHE; + + var useMethodjit = Components.utils.methodjit; + /** @ignore */ + xmlhttp.onreadystatechange = function() { + Components.utils.methodjit = useMethodjit; + _stateChange(xmlhttp, function (xmlhttp) { + Zotero.debug("Proxy auth request completed with status " + + xmlhttp.status + ": " + xmlhttp.responseText); + deferred.resolve(); + }); + }; + xmlhttp.send(null); + return xmlhttp; + } + + // // WebDAV methods // diff --git a/chrome/content/zotero/xpcom/schema.js b/chrome/content/zotero/xpcom/schema.js index 1a8c75260..ac764eb18 100644 --- a/chrome/content/zotero/xpcom/schema.js +++ b/chrome/content/zotero/xpcom/schema.js @@ -474,11 +474,18 @@ Zotero.Schema = new function(){ var deferred = Q.defer(); if (updated) { if (Zotero.Prefs.get('automaticScraperUpdates')) { - Zotero.Schema.updateFromRepository(2, function () deferred.resolve()); + Zotero.proxyAuthComplete + .then(function () { + Zotero.Schema.updateFromRepository(2, function () deferred.resolve()); + }) } } else { - Zotero.Schema.updateFromRepository(false, function () deferred.resolve()); + Zotero.proxyAuthComplete + .then(function () { + Zotero.Schema.updateFromRepository(false, function () deferred.resolve()); + }) + .done(); } return deferred.promise; } diff --git a/chrome/content/zotero/xpcom/zotero.js b/chrome/content/zotero/xpcom/zotero.js index 4bcdb9cc9..017f43f4e 100644 --- a/chrome/content/zotero/xpcom/zotero.js +++ b/chrome/content/zotero/xpcom/zotero.js @@ -31,6 +31,7 @@ const ZOTERO_CONFIG = { REPOSITORY_RETRY_INTERVAL: 3600, // 1 hour BASE_URI: 'http://zotero.org/', WWW_BASE_URL: 'http://www.zotero.org/', + PROXY_AUTH_URL: 'http://zotero.org.s3.amazonaws.com/proxy-auth', SYNC_URL: 'https://sync.zotero.org/', API_URL: 'https://api.zotero.org/', API_VERSION: 2, @@ -544,6 +545,8 @@ Components.utils.import("resource://gre/modules/Services.jsm"); if(!_initDB()) return false; + Zotero.HTTP.triggerProxyAuth(); + // Add notifier queue callbacks to the DB layer Zotero.DB.addCallback('begin', Zotero.Notifier.begin); Zotero.DB.addCallback('commit', Zotero.Notifier.commit); diff --git a/chrome/content/zotero/zoteroPane.js b/chrome/content/zotero/zoteroPane.js index d8268d8fc..558fc4f0a 100644 --- a/chrome/content/zotero/zoteroPane.js +++ b/chrome/content/zotero/zoteroPane.js @@ -415,7 +415,9 @@ var ZoteroPane = new function() // Auto-sync on pane open if (Zotero.Prefs.get('sync.autoSync')) { - setTimeout(function () { + Zotero.proxyAuthComplete + .delay(1000) + .then(function () { if (!Zotero.Sync.Server.enabled) { Zotero.debug('Sync not enabled -- skipping auto-sync', 4); return; @@ -432,7 +434,8 @@ var ZoteroPane = new function() } Zotero.Sync.Runner.sync(true); - }, 1000); + }) + .done(); } // Set sync icon to spinning or not diff --git a/defaults/preferences/zotero.js b/defaults/preferences/zotero.js index 357689639..0e4672b19 100644 --- a/defaults/preferences/zotero.js +++ b/defaults/preferences/zotero.js @@ -21,6 +21,7 @@ pref("extensions.zotero.debug.level",5); pref("extensions.zotero.debug.time", false); pref("extensions.zotero.automaticScraperUpdates",true); pref("extensions.zotero.zoteroDotOrgVersionHeader", true); +pref("extensions.zotero.triggerProxyAuthentication", true); pref("extensions.zotero.cacheTranslatorData",true); pref("extensions.zotero.showIn", 1); pref("extensions.zotero.statusBarIcon", 2);