Fix WebDAV verification feedback

This commit is contained in:
Dan Stillman 2013-02-18 19:34:04 -05:00
parent d14c3fcc92
commit bc800ddc30
3 changed files with 187 additions and 178 deletions

View File

@ -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:
setTimeout(function () {
passwordField.focus();
}, 1);
case Zotero.Sync.Storage.ERROR_AUTH_FAILED:
onDone = function () {
passwordField.focus;
}
break;
}
Zotero.Sync.Storage.WebDAV.checkServerCallback(uri, status, window);
});
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 () {
onDone();
}, 1);
}
}
})
.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);
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;

View File

@ -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;
}

View File

@ -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;
}
else {
throw("Unexpected status code " + e.status + " getting "
+ "WebDAV last sync time");
.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;
}
return Q.reject(e);
}
// TODO: handle browser offline exception
else {
throw (e);
}
});
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 (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: