commit bc800ddc301fc79eac3fb5b2224fb07314a0251f
parent d14c3fcc92e417579a16aee3447e37678b067c41
Author: Dan Stillman <dstillman@zotero.org>
Date: Mon, 18 Feb 2013 19:34:04 -0500
Fix WebDAV verification feedback
Diffstat:
3 files changed, 185 insertions(+), 176 deletions(-)
diff --git a/chrome/content/zotero/preferences/preferences.js b/chrome/content/zotero/preferences/preferences.js
@@ -371,38 +371,83 @@ function verifyStorageServer() {
abortButton.hidden = false;
progressMeter.hidden = false;
- var requestHolder = Zotero.Sync.Storage.WebDAV.checkServer(function (uri, status, callback) {
+ var request = null;
+ var onDone = false;
+
+ Zotero.Sync.Storage.WebDAV.checkServer()
+ .finally(function () {
verifyButton.hidden = false;
abortButton.hidden = true;
progressMeter.hidden = true;
-
+ })
+ .spread(function (uri, status) {
switch (status) {
case Zotero.Sync.Storage.ERROR_NO_URL:
- setTimeout(function () {
+ onDone = function () {
urlField.focus();
- }, 1);
+ };
break;
case Zotero.Sync.Storage.ERROR_NO_USERNAME:
- setTimeout(function () {
+ onDone = function () {
usernameField.focus();
- }, 1);
+ };
break;
case Zotero.Sync.Storage.ERROR_NO_PASSWORD:
+ case Zotero.Sync.Storage.ERROR_AUTH_FAILED:
+ onDone = function () {
+ passwordField.focus;
+ }
+ break;
+ }
+
+ return Zotero.Sync.Storage.WebDAV.checkServerCallback(uri, status, window);
+ })
+ .then(function (success) {
+ if (success) {
+ Zotero.debug("WebDAV verification succeeded");
+
+ var promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
+ .getService(Components.interfaces.nsIPromptService);
+ promptService.alert(
+ window,
+ Zotero.getString('sync.storage.serverConfigurationVerified'),
+ Zotero.getString('sync.storage.fileSyncSetUp')
+ );
+ Zotero.Prefs.set("sync.storage.verified", true);
+ }
+ else {
+ Zotero.debug("WebDAV verification failed");
+ if (onDone) {
setTimeout(function () {
- passwordField.focus();
+ onDone();
}, 1);
- break;
+ }
}
+ })
+ .progress(function (obj) {
+ request = obj.request;
+ })
+ .catch(function (e) {
+ Zotero.debug("WebDAV verification failed");
+ Zotero.debug(e, 1);
+ Components.utils.reportError(e);
+ Zotero.Utilities.Internal.errorPrompt(Zotero.getString('general.error'), e);
- Zotero.Sync.Storage.WebDAV.checkServerCallback(uri, status, window);
- });
+ if (onDone) {
+ setTimeout(function () {
+ onDone();
+ }, 1);
+ }
+ })
+ .done();
abortButton.onclick = function () {
- if (requestHolder.request) {
- requestHolder.request.onreadystatechange = undefined;
- requestHolder.request.abort();
+ if (request) {
+ Zotero.debug("Cancelling verification request");
+ request.onreadystatechange = undefined;
+ request.abort();
verifyButton.hidden = false;
abortButton.hidden = true;
progressMeter.hidden = true;
diff --git a/chrome/content/zotero/xpcom/storage.js b/chrome/content/zotero/xpcom/storage.js
@@ -114,10 +114,10 @@ Zotero.Sync.Storage = new function () {
Zotero.debug("WebDAV file sync is not active");
// Try to verify server now if it hasn't been
- return mode.checkServerPromise()
- .then(function () {
- libraryModes[0] = Zotero.Sync.Storage.WebDAV;
- });
+ return Zotero.Sync.Storage.checkServerPromise(Zotero.Sync.Storage.WebDAV)
+ .then(function () {
+ libraryModes[0] = Zotero.Sync.Storage.WebDAV;
+ });
}
libraryModes[0] = Zotero.Sync.Storage.WebDAV;
@@ -178,7 +178,6 @@ Zotero.Sync.Storage = new function () {
promises.forEach(function (p) {
p = p.valueOf();
var libraryID = p[0].valueOf();
- Zotero.debug(libraryID);
if (p[1].isFulfilled()) {
librarySyncTimes[libraryID] = p[1].valueOf();
}
@@ -953,18 +952,14 @@ Zotero.Sync.Storage = new function () {
this.checkServerPromise = function (mode) {
- var deferred = Q.defer();
- mode.checkServer(function (uri, status) {
+ return mode.checkServer()
+ .spread(function (uri, status) {
var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
.getService(Components.interfaces.nsIWindowMediator);
var lastWin = wm.getMostRecentWindow("navigator:browser");
var success = mode.checkServerCallback(uri, status, lastWin, true);
- if (success) {
- Zotero.debug(mode.name + " file sync is successfully set up");
- Q.resolve();
- }
- else {
+ if (!success) {
Zotero.debug(mode.name + " verification failed");
var e = new Zotero.Error(
@@ -980,11 +975,13 @@ Zotero.Sync.Storage = new function () {
}
}
);
-
- Q.reject(e);
+ throw e;
}
+ })
+ .then(function () {
+ Zotero.debug(mode.name + " file sync is successfully set up");
+ Zotero.Prefs.set("sync.storage.verified", true);
});
- return deferred.promise;
}
diff --git a/chrome/content/zotero/xpcom/storage/webdav.js b/chrome/content/zotero/xpcom/storage/webdav.js
@@ -55,7 +55,8 @@ Zotero.Sync.Storage.WebDAV = (function () {
)
.then(function (req) {
checkResponse(req);
-
+ })
+ .then(function (req) {
var funcName = "Zotero.Sync.Storage.WebDAV.getStorageModificationTime()";
// mod_speling can return 300s for 404s with base name matches
@@ -385,28 +386,22 @@ Zotero.Sync.Storage.WebDAV = (function () {
switch (req.status) {
case 201:
- callback(uri, Zotero.Sync.Storage.SUCCESS);
- break;
+ return [uri, Zotero.Sync.Storage.SUCCESS];
case 401:
- callback(uri, Zotero.Sync.Storage.ERROR_AUTH_FAILED);
- return;
+ return [uri, Zotero.Sync.Storage.ERROR_AUTH_FAILED];
case 403:
- callback(uri, Zotero.Sync.Storage.ERROR_FORBIDDEN);
- return;
+ return [uri, Zotero.Sync.Storage.ERROR_FORBIDDEN];
case 405:
- callback(uri, Zotero.Sync.Storage.ERROR_NOT_ALLOWED);
- return;
+ return [uri, Zotero.Sync.Storage.ERROR_NOT_ALLOWED];
case 500:
- callback(uri, Zotero.Sync.Storage.ERROR_SERVER_ERROR);
- return;
+ return [uri, Zotero.Sync.Storage.ERROR_SERVER_ERROR];
default:
- callback(uri, Zotero.Sync.Storage.ERROR_UNKNOWN);
- return;
+ return [uri, Zotero.Sync.Storage.ERROR_UNKNOWN];
}
});
}
@@ -585,7 +580,7 @@ Zotero.Sync.Storage.WebDAV = (function () {
/**
- * Checks for an invalid SSL certificate and displays a nice error
+ * Checks for an invalid SSL certificate and throws a nice error
*/
function checkResponse(req) {
var channel = req.channel;
@@ -981,41 +976,41 @@ Zotero.Sync.Storage.WebDAV = (function () {
return Q.fcall(function () {
return self._cacheCredentials();
})
- .then(function () {
- var lastSyncURI = this.rootURI;
- lastSyncURI.spec += "lastsync";
- return Zotero.HTTP.promise("GET", lastSyncURI,
- { debug: true, successCodes: [200, 404] });
- })
- .then(function (req) {
- if (req.status == 404) {
- Zotero.debug("No last WebDAV sync time");
- return null;
- }
-
- var lastModified = req.getResponseHeader("Last-Modified");
- var date = new Date(lastModified);
- Zotero.debug("Last successful WebDAV sync was " + date);
- return Zotero.Date.toUnixTimestamp(date);
- })
- .fail(function (e) {
- if (e instanceof Zotero.HTTP.UnexpectedStatusException) {
- if (e.status == 403) {
- Zotero.debug("Clearing WebDAV authentication credentials", 2);
- _cachedCredentials = false;
+ .then(function () {
+ var lastSyncURI = this.rootURI;
+ lastSyncURI.spec += "lastsync";
+ return Zotero.HTTP.promise("GET", lastSyncURI,
+ { debug: true, successCodes: [200, 404] });
+ })
+ .then(function (req) {
+ if (req.status == 404) {
+ Zotero.debug("No last WebDAV sync time");
+ return null;
}
+
+ var lastModified = req.getResponseHeader("Last-Modified");
+ var date = new Date(lastModified);
+ Zotero.debug("Last successful WebDAV sync was " + date);
+ return Zotero.Date.toUnixTimestamp(date);
+ })
+ .fail(function (e) {
+ if (e instanceof Zotero.HTTP.UnexpectedStatusException) {
+ if (e.status == 403) {
+ Zotero.debug("Clearing WebDAV authentication credentials", 2);
+ _cachedCredentials = false;
+ }
+ else {
+ throw("Unexpected status code " + e.status + " getting "
+ + "WebDAV last sync time");
+ }
+
+ return Q.reject(e);
+ }
+ // TODO: handle browser offline exception
else {
- throw("Unexpected status code " + e.status + " getting "
- + "WebDAV last sync time");
+ throw (e);
}
-
- return Q.reject(e);
- }
- // TODO: handle browser offline exception
- else {
- throw (e);
- }
- });
+ });
};
@@ -1068,31 +1063,29 @@ Zotero.Sync.Storage.WebDAV = (function () {
}
return Zotero.HTTP.promise("OPTIONS", this.rootURI)
- .then(function (req) {
- // TODO: promisify
- checkResponse(req);
-
- Zotero.debug("Credentials are cached");
- _cachedCredentials = true;
- })
- .fail(function (e) {
- if (e instanceof Zotero.HTTP.UnexpectedStatusException) {
- var msg = "Unexpected status code " + e.status + " "
- + "for OPTIONS request caching WebDAV credentials";
- Zotero.debug(msg, 1);
- Components.utils.reportError(msg);
- throw new Error(_defaultErrorRestart);
- }
- throw e;
- });
+ .then(function (req) {
+ return checkResponse(req);
+ })
+ .then(function () {
+ Zotero.debug("Credentials are cached");
+ _cachedCredentials = true;
+ })
+ .fail(function (e) {
+ if (e instanceof Zotero.HTTP.UnexpectedStatusException) {
+ var msg = "Unexpected status code " + e.status + " "
+ + "for OPTIONS request caching WebDAV credentials";
+ Zotero.debug(msg, 1);
+ Components.utils.reportError(msg);
+ throw new Error(_defaultErrorRestart);
+ }
+ throw e;
+ });
};
- /**
- * @param {Function} callback Function to pass URI and result value to
- * @param {Object} errorCallbacks
- */
- obj._checkServer = function (callback) {
+ obj._checkServer = function () {
+ var deferred = Q.defer();
+
try {
// Clear URIs
this.init();
@@ -1103,27 +1096,23 @@ Zotero.Sync.Storage.WebDAV = (function () {
catch (e) {
switch (e.name) {
case 'Z_ERROR_NO_URL':
- callback(null, Zotero.Sync.Storage.ERROR_NO_URL);
- return;
+ deferred.resolve([null, Zotero.Sync.Storage.ERROR_NO_URL]);
case 'Z_ERROR_NO_USERNAME':
- callback(null, Zotero.Sync.Storage.ERROR_NO_USERNAME);
- return;
+ deferred.resolve([null, Zotero.Sync.Storage.ERROR_NO_USERNAME]);
case 'Z_ERROR_NO_PASSWORD':
- callback(null, Zotero.Sync.Storage.ERROR_NO_PASSWORD);
- return;
+ deferred.resolve([null, Zotero.Sync.Storage.ERROR_NO_PASSWORD]);
default:
Zotero.debug(e);
Components.utils.reportError(e);
- callback(null, Zotero.Sync.Storage.ERROR_UNKNOWN);
- return;
+ deferred.resolve([null, Zotero.Sync.Storage.ERROR_UNKNOWN]);
}
+
+ return deferred.promise;
}
- var requestHolder = { request: null };
-
var xmlstr = "<propfind xmlns='DAV:'><prop>"
// IIS 5.1 requires at least one property in PROPFIND
+ "<getcontentlength/>"
@@ -1133,10 +1122,14 @@ Zotero.Sync.Storage.WebDAV = (function () {
var request = Zotero.HTTP.doOptions(uri, function (req) {
// Timeout
if (req.status == 0) {
- checkResponse(req);
+ try {
+ checkResponse(req);
+ }
+ catch (e) {
+ deferred.reject(e);
+ }
- callback(uri, Zotero.Sync.Storage.ERROR_UNREACHABLE);
- return;
+ return deferred.resolve([uri, Zotero.Sync.Storage.ERROR_UNREACHABLE]);
}
Zotero.debug(req.getAllResponseHeaders());
@@ -1145,26 +1138,21 @@ Zotero.Sync.Storage.WebDAV = (function () {
switch (req.status) {
case 400:
- callback(uri, Zotero.Sync.Storage.ERROR_BAD_REQUEST);
- return;
+ return deferred.resolve([uri, Zotero.Sync.Storage.ERROR_BAD_REQUEST]);
case 401:
- callback(uri, Zotero.Sync.Storage.ERROR_AUTH_FAILED);
- return;
+ return deferred.resolve([uri, Zotero.Sync.Storage.ERROR_AUTH_FAILED]);
case 403:
- callback(uri, Zotero.Sync.Storage.ERROR_FORBIDDEN);
- return;
+ return deferred.resolve([uri, Zotero.Sync.Storage.ERROR_FORBIDDEN]);
case 500:
- callback(uri, Zotero.Sync.Storage.ERROR_SERVER_ERROR);
- return;
+ return deferred.resolve([uri, Zotero.Sync.Storage.ERROR_SERVER_ERROR]);
}
var dav = req.getResponseHeader("DAV");
if (dav == null) {
- callback(uri, Zotero.Sync.Storage.ERROR_NOT_DAV);
- return;
+ return deferred.resolve([uri, Zotero.Sync.Storage.ERROR_NOT_DAV]);
}
// Get the Authorization header used in case we need to do a request
@@ -1209,32 +1197,26 @@ Zotero.Sync.Storage.WebDAV = (function () {
switch (req.status) {
case 200: // IIS 5.1 and Sakai return 200
case 204:
- callback(uri, Zotero.Sync.Storage.SUCCESS);
- return;
+ return deferred.resolve([uri, Zotero.Sync.Storage.SUCCESS]);
case 401:
- callback(uri, Zotero.Sync.Storage.ERROR_AUTH_FAILED);
- return;
+ return deferred.resolve([uri, Zotero.Sync.Storage.ERROR_AUTH_FAILED]);
case 403:
- callback(uri, Zotero.Sync.Storage.ERROR_FORBIDDEN);
- return;
+ return deferred.resolve([uri, Zotero.Sync.Storage.ERROR_FORBIDDEN]);
default:
- callback(uri, Zotero.Sync.Storage.ERROR_UNKNOWN);
- return;
+ return deferred.resolve([uri, Zotero.Sync.Storage.ERROR_UNKNOWN]);
}
}
);
return;
case 401:
- callback(uri, Zotero.Sync.Storage.ERROR_AUTH_FAILED);
- return;
+ return deferred.resolve([uri, Zotero.Sync.Storage.ERROR_AUTH_FAILED]);
case 403:
- callback(uri, Zotero.Sync.Storage.ERROR_FORBIDDEN);
- return;
+ return deferred.resolve([uri, Zotero.Sync.Storage.ERROR_FORBIDDEN]);
// This can happen with cloud storage services
// backed by S3 or other eventually consistent
@@ -1244,51 +1226,41 @@ Zotero.Sync.Storage.WebDAV = (function () {
// not to serve extensionless files or .prop files
// http://support.microsoft.com/kb/326965
case 404:
- callback(uri, Zotero.Sync.Storage.ERROR_FILE_MISSING_AFTER_UPLOAD);
- return;
+ return deferred.resolve([uri, Zotero.Sync.Storage.ERROR_FILE_MISSING_AFTER_UPLOAD]);
case 500:
- callback(uri, Zotero.Sync.Storage.ERROR_SERVER_ERROR);
- return;
+ return deferred.resolve([uri, Zotero.Sync.Storage.ERROR_SERVER_ERROR]);
default:
- callback(uri, Zotero.Sync.Storage.ERROR_UNKNOWN);
- return;
+ return deferred.resolve([uri, Zotero.Sync.Storage.ERROR_UNKNOWN]);
}
}
);
return;
case 401:
- callback(uri, Zotero.Sync.Storage.ERROR_AUTH_FAILED);
- return;
+ return deferred.resolve([uri, Zotero.Sync.Storage.ERROR_AUTH_FAILED]);
case 403:
- callback(uri, Zotero.Sync.Storage.ERROR_FORBIDDEN);
- return;
+ return deferred.resolve([uri, Zotero.Sync.Storage.ERROR_FORBIDDEN]);
case 500:
- callback(uri, Zotero.Sync.Storage.ERROR_SERVER_ERROR);
- return;
+ return deferred.resolve([uri, Zotero.Sync.Storage.ERROR_SERVER_ERROR]);
default:
- callback(uri, Zotero.Sync.Storage.ERROR_UNKNOWN);
- return;
+ return deferred.resolve([uri, Zotero.Sync.Storage.ERROR_UNKNOWN]);
}
});
return;
case 400:
- callback(uri, Zotero.Sync.Storage.ERROR_BAD_REQUEST);
- return;
+ return deferred.resolve([uri, Zotero.Sync.Storage.ERROR_BAD_REQUEST]);
case 401:
- callback(uri, Zotero.Sync.Storage.ERROR_AUTH_FAILED);
- return;
+ return deferred.resolve([uri, Zotero.Sync.Storage.ERROR_AUTH_FAILED]);
case 403:
- callback(uri, Zotero.Sync.Storage.ERROR_FORBIDDEN);
- return;
+ return deferred.resolve([uri, Zotero.Sync.Storage.ERROR_FORBIDDEN]);
case 404:
// Include Authorization header from /zotero request,
@@ -1309,49 +1281,52 @@ Zotero.Sync.Storage.WebDAV = (function () {
switch (req.status) {
// Parent directory existed
case 207:
- callback(uri, Zotero.Sync.Storage.ERROR_ZOTERO_DIR_NOT_FOUND);
- return;
+ return deferred.resolve([uri, Zotero.Sync.Storage.ERROR_ZOTERO_DIR_NOT_FOUND]);
case 400:
- callback(uri, Zotero.Sync.Storage.ERROR_BAD_REQUEST);
- return;
+ return deferred.resolve([uri, Zotero.Sync.Storage.ERROR_BAD_REQUEST]);
case 401:
- callback(uri, Zotero.Sync.Storage.ERROR_AUTH_FAILED);
- return;
+ return deferred.resolve([uri, Zotero.Sync.Storage.ERROR_AUTH_FAILED]);
// Parent directory wasn't found either
case 404:
- callback(uri, Zotero.Sync.Storage.ERROR_PARENT_DIR_NOT_FOUND);
- return;
+ return deferred.resolve([uri, Zotero.Sync.Storage.ERROR_PARENT_DIR_NOT_FOUND]);
default:
- callback(uri, Zotero.Sync.Storage.ERROR_UNKNOWN);
- return;
+ return deferred.resolve([uri, Zotero.Sync.Storage.ERROR_UNKNOWN]);
}
}, newHeaders);
return;
case 500:
- callback(uri, Zotero.Sync.Storage.ERROR_SERVER_ERROR);
- return;
+ return deferred.resolve([uri, Zotero.Sync.Storage.ERROR_SERVER_ERROR]);
default:
- callback(uri, Zotero.Sync.Storage.ERROR_UNKNOWN);
- return;
+ return deferred.resolve([uri, Zotero.Sync.Storage.ERROR_UNKNOWN]);
}
}, headers);
});
if (!request) {
- callback(uri, Zotero.Sync.Storage.ERROR_OFFLINE);
+ return deferred.resolve([uri, Zotero.Sync.Storage.ERROR_OFFLINE]);
}
- requestHolder.request = request;
- return requestHolder;
+ // Pass request to progress handler
+ var obj = {};
+ obj.request = request;
+ deferred.notify(obj)
+
+
+ return deferred.promise;
};
+ /**
+ * Handles the result of WebDAV verification, displaying an alert if necessary.
+ *
+ * @return bool True if the verification succeeded, false otherwise
+ */
obj._checkServerCallback = function (uri, status, window, skipSuccessMessage) {
var promptService =
Components.classes["@mozilla.org/embedcomp/prompt-service;1"].
@@ -1362,14 +1337,6 @@ Zotero.Sync.Storage.WebDAV = (function () {
switch (status) {
case Zotero.Sync.Storage.SUCCESS:
- if (!skipSuccessMessage) {
- promptService.alert(
- window,
- Zotero.getString('sync.storage.serverConfigurationVerified'),
- Zotero.getString('sync.storage.fileSyncSetUp')
- );
- }
- Zotero.Prefs.set("sync.storage.verified", true);
return true;
case Zotero.Sync.Storage.ERROR_NO_URL: