Improve error messages on certificate and connection errors
- Show a clearer message on a certificate error that includes the underlying error, which should make debugging much simpler. (No more checking in a browser and hoping it's the same connection.) - Mention proxy server in message on startup proxy-check failure - Include link to connection-error KB page on sync connection failure Closes #1191 Closes #1513
This commit is contained in:
parent
ea8b15a44a
commit
ff8df06c75
7 changed files with 91 additions and 96 deletions
|
@ -319,17 +319,19 @@ Zotero.HTTP = new function() {
|
|||
}
|
||||
Zotero.debug(msg, 1);
|
||||
|
||||
try {
|
||||
_checkSecurity(xmlhttp, channel);
|
||||
}
|
||||
catch (e) {
|
||||
deferred.reject(e);
|
||||
return;
|
||||
if (xmlhttp.status == 0) {
|
||||
try {
|
||||
this.checkSecurity(channel);
|
||||
}
|
||||
catch (e) {
|
||||
deferred.reject(e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
deferred.reject(new Zotero.HTTP.UnexpectedStatusException(xmlhttp, msg));
|
||||
}
|
||||
};
|
||||
}.bind(this);
|
||||
|
||||
if (options.cookieSandbox) {
|
||||
options.cookieSandbox.attachToInterfaceRequestor(xmlhttp);
|
||||
|
@ -663,9 +665,17 @@ Zotero.HTTP = new function() {
|
|||
})
|
||||
.catch(function (e) {
|
||||
// Show error icon at startup
|
||||
if (e instanceof Zotero.HTTP.SecurityException) {
|
||||
Zotero.proxyFailure = e;
|
||||
if (!e.dialogHeader) {
|
||||
e.dialogHeader = Zotero.getString('networkError.errorViaProxy');
|
||||
}
|
||||
e.message += "\n\n" + Zotero.getString('startupError.internetFunctionalityMayNotWork');
|
||||
if (!e.dialogButtonText) {
|
||||
e.dialogButtonText = Zotero.getString('general.moreInformation');
|
||||
e.dialogButtonCallback = () => {
|
||||
Zotero.launchURL('https://www.zotero.org/support/kb/connection_error');
|
||||
};
|
||||
}
|
||||
Zotero.proxyFailure = e;
|
||||
Zotero.logError(e);
|
||||
let msg = "Error connecting to proxy -- proxied requests may not work";
|
||||
Zotero.logError(msg);
|
||||
|
@ -992,8 +1002,8 @@ Zotero.HTTP = new function() {
|
|||
}
|
||||
}
|
||||
|
||||
function _checkSecurity(xmlhttp, channel) {
|
||||
if (xmlhttp.status != 0 || !channel) {
|
||||
this.checkSecurity = function (channel) {
|
||||
if (!channel) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1005,37 +1015,27 @@ Zotero.HTTP = new function() {
|
|||
secInfo.QueryInterface(Ci.nsITransportSecurityInfo);
|
||||
if ((secInfo.securityState & Ci.nsIWebProgressListener.STATE_IS_INSECURE)
|
||||
== Ci.nsIWebProgressListener.STATE_IS_INSECURE) {
|
||||
let url = channel.name;
|
||||
let ios = Components.classes["@mozilla.org/network/io-service;1"]
|
||||
.getService(Components.interfaces.nsIIOService);
|
||||
try {
|
||||
var uri = ios.newURI(url, null, null);
|
||||
var host = uri.host;
|
||||
}
|
||||
catch (e) {
|
||||
Zotero.debug(e);
|
||||
}
|
||||
let kbURL = 'https://www.zotero.org/support/kb/ssl_certificate_error';
|
||||
msg = Zotero.getString(
|
||||
'sync.storage.error.webdav.sslCertificateError',
|
||||
'https://' + host
|
||||
);
|
||||
// Show actual error from the networking stack, with the hyperlink around the
|
||||
// error code removed
|
||||
msg = Zotero.Utilities.unescapeHTML(secInfo.errorMessage);
|
||||
dialogButtonText = Zotero.getString('general.moreInformation');
|
||||
dialogButtonCallback = function () {
|
||||
let wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
|
||||
.getService(Components.interfaces.nsIWindowMediator);
|
||||
let win = wm.getMostRecentWindow("navigator:browser");
|
||||
win.ZoteroPane.loadURI(kbURL, { metaKey: true, shiftKey: true });
|
||||
Zotero.launchURL('https://www.zotero.org/support/kb/ssl_certificate_error');
|
||||
};
|
||||
}
|
||||
else if ((secInfo.securityState & Ci.nsIWebProgressListener.STATE_IS_BROKEN)
|
||||
== Ci.nsIWebProgressListener.STATE_IS_BROKEN) {
|
||||
msg = Zotero.getString('sync.error.sslConnectionError');
|
||||
msg = Zotero.getString('networkError.connectionNotSecure')
|
||||
+ Zotero.Utilities.unescapeHTML(secInfo.errorMessage);
|
||||
}
|
||||
if (msg) {
|
||||
throw new Zotero.HTTP.SecurityException(
|
||||
msg,
|
||||
{
|
||||
dialogHeader: Zotero.getString(
|
||||
'networkError.connectionNotSecure',
|
||||
Zotero.clientName
|
||||
),
|
||||
dialogButtonText,
|
||||
dialogButtonCallback
|
||||
}
|
||||
|
|
|
@ -158,6 +158,17 @@ Zotero.Sync.Storage.Mode.ZFS.prototype = {
|
|||
return;
|
||||
}
|
||||
|
||||
// Check for SSL certificate error
|
||||
if (status == 0) {
|
||||
try {
|
||||
Zotero.HTTP.checkSecurity(req);
|
||||
}
|
||||
catch (e) {
|
||||
deferred.reject(e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// If S3 connection is interrupted, delay and retry, or bail if too many
|
||||
// consecutive failures
|
||||
if (status == 0 || status == 500 || status == 503) {
|
||||
|
|
|
@ -788,12 +788,9 @@ Zotero.Sync.APIClient.prototype = {
|
|||
|
||||
|
||||
/**
|
||||
* Check connection for certificate errors, interruptions, and empty responses and
|
||||
* throw an appropriate error
|
||||
* Check connection for interruptions and empty responses and throw an appropriate error
|
||||
*/
|
||||
_checkConnection: function (xmlhttp, channel) {
|
||||
const Ci = Components.interfaces;
|
||||
|
||||
if (!xmlhttp.responseText && (xmlhttp.status == 0 || xmlhttp.status == 200)) {
|
||||
let msg = null;
|
||||
let dialogButtonText = null;
|
||||
|
@ -801,8 +798,11 @@ Zotero.Sync.APIClient.prototype = {
|
|||
|
||||
if (xmlhttp.status === 0) {
|
||||
msg = Zotero.getString('sync.error.checkConnection');
|
||||
dialogButtonText = Zotero.getString('general.moreInformation');
|
||||
let url = 'https://www.zotero.org/support/kb/connection_error';
|
||||
dialogButtonCallback = () => Zotero.launchURL(url);
|
||||
}
|
||||
if (!msg) {
|
||||
else if (!msg) {
|
||||
msg = Zotero.getString('sync.error.emptyResponseServer')
|
||||
+ Zotero.getString('general.tryAgainLater');
|
||||
}
|
||||
|
|
|
@ -1404,26 +1404,31 @@ Zotero.Sync.Runner_Module = function (options = {}) {
|
|||
}
|
||||
label.setAttribute('value', libraryName);
|
||||
}
|
||||
var content = doc.createElement('hbox');
|
||||
var content = doc.createElement('vbox');
|
||||
var buttons = doc.createElement('hbox');
|
||||
buttons.pack = 'end';
|
||||
box.appendChild(label);
|
||||
box.appendChild(content);
|
||||
box.appendChild(buttons);
|
||||
|
||||
if (e.dialogHeader) {
|
||||
let header = doc.createElement('description');
|
||||
header.className = 'error-header';
|
||||
header.textContent = e.dialogHeader;
|
||||
content.appendChild(header);
|
||||
}
|
||||
|
||||
// Show our own error mesages directly
|
||||
var msg;
|
||||
if (e instanceof Zotero.Error) {
|
||||
var msg = e.message;
|
||||
msg = e.message;
|
||||
}
|
||||
// For unexpected ones, just show a generic message
|
||||
else if (e instanceof Zotero.HTTP.UnexpectedStatusException && e.xmlhttp.responseText) {
|
||||
msg = Zotero.Utilities.ellipsize(e.xmlhttp.responseText, 1000, true);
|
||||
}
|
||||
else {
|
||||
if (e instanceof Zotero.HTTP.UnexpectedStatusException) {
|
||||
msg = Zotero.Utilities.ellipsize(e.xmlhttp.responseText, 1000, true);
|
||||
}
|
||||
else {
|
||||
// TODO: Localize
|
||||
var msg = "An error occurred during syncing:\n\n" + e.message;
|
||||
}
|
||||
msg = e.message;
|
||||
}
|
||||
|
||||
var desc = doc.createElement('description');
|
||||
|
|
|
@ -483,10 +483,7 @@ var ZoteroPane = new function()
|
|||
|
||||
if (Zotero.proxyFailure) {
|
||||
try {
|
||||
Zotero.proxyFailure.message += "\n\n"
|
||||
+ Zotero.getString('startupError.internetFunctionalityMayNotWork');
|
||||
Zotero.Sync.Runner.updateIcons(Zotero.proxyFailure);
|
||||
Zotero.proxyFailure = null;
|
||||
}
|
||||
catch (e) {
|
||||
Zotero.logError(e);
|
||||
|
@ -4611,64 +4608,33 @@ var ZoteroPane = new function()
|
|||
|
||||
this.syncAlert = function (e) {
|
||||
e = Zotero.Sync.Runner.parseError(e);
|
||||
var ps = Services.prompt;
|
||||
var buttonText = e.dialogButtonText;
|
||||
var buttonCallback = e.dialogButtonCallback;
|
||||
|
||||
var ps = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
|
||||
.getService(Components.interfaces.nsIPromptService);
|
||||
var buttonFlags = ps.BUTTON_POS_0 * ps.BUTTON_TITLE_OK
|
||||
+ ps.BUTTON_POS_1 * ps.BUTTON_TITLE_IS_STRING;
|
||||
|
||||
// Warning
|
||||
if (e.errorType == 'warning') {
|
||||
var title = Zotero.getString('general.warning');
|
||||
if (e.errorType == 'warning' || e.errorType == 'error') {
|
||||
let title = Zotero.getString('general.' + e.errorType);
|
||||
// TODO: Display header in bold
|
||||
let msg = (e.dialogHeader ? e.dialogHeader + '\n\n' : '') + e.message;
|
||||
|
||||
// If secondary button not specified, just use an alert
|
||||
if (e.buttonText) {
|
||||
var buttonText = e.buttonText;
|
||||
}
|
||||
else {
|
||||
if (e.errorType == 'warning' || buttonText === null) {
|
||||
ps.alert(null, title, e.message);
|
||||
return;
|
||||
}
|
||||
|
||||
var index = ps.confirmEx(
|
||||
null,
|
||||
title,
|
||||
e.message,
|
||||
buttonFlags,
|
||||
"",
|
||||
buttonText,
|
||||
"", null, {}
|
||||
);
|
||||
|
||||
if (index == 1) {
|
||||
setTimeout(function () { buttonCallback(); }, 1);
|
||||
}
|
||||
}
|
||||
// Error
|
||||
else if (e.errorType == 'error') {
|
||||
var title = Zotero.getString('general.error');
|
||||
|
||||
// If secondary button is explicitly null, just use an alert
|
||||
if (buttonText === null) {
|
||||
ps.alert(null, title, e.message);
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof buttonText == 'undefined') {
|
||||
var buttonText = Zotero.getString('errorReport.reportError');
|
||||
var buttonCallback = function () {
|
||||
if (!buttonText) {
|
||||
buttonText = Zotero.getString('errorReport.reportError');
|
||||
buttonCallback = function () {
|
||||
ZoteroPane.reportErrors();
|
||||
};
|
||||
}
|
||||
else {
|
||||
var buttonText = e.buttonText;
|
||||
var buttonCallback = e.buttonCallback;
|
||||
}
|
||||
|
||||
var index = ps.confirmEx(
|
||||
let buttonFlags = ps.BUTTON_POS_0 * ps.BUTTON_TITLE_OK
|
||||
+ ps.BUTTON_POS_1 * ps.BUTTON_TITLE_IS_STRING;
|
||||
let index = ps.confirmEx(
|
||||
null,
|
||||
title,
|
||||
e.message,
|
||||
msg,
|
||||
buttonFlags,
|
||||
"",
|
||||
buttonText,
|
||||
|
@ -4676,12 +4642,13 @@ var ZoteroPane = new function()
|
|||
);
|
||||
|
||||
if (index == 1) {
|
||||
setTimeout(function () { buttonCallback(); }, 1);
|
||||
setTimeout(buttonCallback, 1);
|
||||
}
|
||||
}
|
||||
// Upgrade
|
||||
// Upgrade message
|
||||
else if (e.errorType == 'upgrade') {
|
||||
ps.alert(null, "", e.message);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -75,6 +75,9 @@ general.operationInProgress = A Zotero operation is currently in progress.
|
|||
general.operationInProgress.waitUntilFinished = Please wait until it has finished.
|
||||
general.operationInProgress.waitUntilFinishedAndTryAgain = Please wait until it has finished and try again.
|
||||
|
||||
networkError.connectionNotSecure = %S could not make a secure connection.
|
||||
networkError.errorViaProxy = Error connecting via proxy server
|
||||
|
||||
about.createdBy = Zotero is a project of the [Roy Rosenzweig Center for History and New Media] and is developed by a [global community].
|
||||
about.getInvolved = Want to help? [Get involved] today!
|
||||
|
||||
|
|
|
@ -645,6 +645,15 @@
|
|||
margin-right: 0;
|
||||
}
|
||||
|
||||
#zotero-sync-error-panel .error-header {
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 1em;
|
||||
-moz-user-select: text;
|
||||
user-select: text;
|
||||
cursor: text
|
||||
}
|
||||
|
||||
.zotero-sync-error-panel-library-name {
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
|
|
Loading…
Reference in a new issue