/* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Mozilla Roaming code. * * The Initial Developer of the Original Code is * Ben Bucksch of * Beonex * Portions created by the Initial Developer are Copyright (C) 2002-2004 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Netscape Editor team, esp. Charles Manske * ManyOne * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ EXPORTED_SYMBOLS.push( "kErrorUserCancelled", "NetUtil", "ServerError", "MozillaException" ); /** * Library with a set of functions which is needed by networking code. */ const kHomeBase = 0x80760000; const kErrorUserCancelled = kHomeBase + 1; const kNetErrorStringbundleURI = "chrome://tthome/locale/logic/netutil.properties"; /** * @class */ const NetUtil = { _kNetErrorStringbundle: null, _getNetErrorStringbundle: function () { if (!this._kNetErrorStringbundle) this._kNetErrorStringbundle = getStringBundle(kNetErrorStringbundleURI); return this._kNetErrorStringbundle; }, /** * Translates an XPCOM exception into a String similar to the C++ constant. * * @param ex (nsIException) any object is accepted, but names are only returned for XPCOM errors (nsIException) * @return String returns a human-readable name for the result code */ _nameForException: function (ex) { if (!(ex instanceof CI.nsIException)) return null; if (ex.name) return ex.name.replace(/^NS_(ERROR_)?/, ""); // Error code not found. Let's see if NSS knows about it. var nssError = null; nssError = this.nssMessageForStatusCode(ex.result); if (nssError) return nssError; // Unknown/new error code? var module = ((ex.result & ~0x80000000) >> 16) - 0x45; var errorNum = (ex.result & 0xFFFF); return "Unknown error code: module " + module + ", error number " + errorNum; }, /** * Translates an nsresult into a *non-translated* String for display to the user. * * @param status (nsresult) an nsresult * @return String returns a non-translated human-readable representation for the result code * if it is an NSS error, or null if result code is not known by NSS */ nssMessageForStatusCode: function (status) { var message = null; try { message = Cc["@mozilla.org/psm;1"].getService(CI.nsINSSErrorsService) .getErrorMessage(status); } catch (e) { /* NSS is at a loss, ignore */ } return message; }, /** * Translates an XPCOM exception into a String for display to the user. * * @param ex (nsIException) any object is accepted, but names are only returned for XPCOM errors (nsIException) * @return String returns a translated human-readable represenation of the * result code, or null if result code is unknown */ errorMessageForException: function (ex) { var statusName = this._nameForException(ex); if (!statusName) return null; try { return this._getNetErrorStringbundle().GetStringFromName(statusName); } catch (e) { debug("Please translate " + statusName + ". Just add it to netutil.properties now."); return statusName; } }, /** * Translates an XPCOM status (nsresult) into a ServerError * * @param {nsresult} status nsresult code * @param {String} uri URI called * @param {Object} additionalInfo additional info to be stored in the exception * @return {ServerError} returns a ServerError */ exceptionForStatusCode: function (status, uri, additionalInfo) { var exception = Cc["@mozilla.org/js/xpc/Exception;1"].createInstance(CI.nsIXPCException); exception.initialize(null, status, null, null, null, null); var message = NetUtil.errorMessageForException(exception); if (!message) message = this._getNetErrorStringbundle().formatStringFromName("unknownError", [status], 1); return new ServerError(message, status, uri, undefined, additionalInfo); }, /** * Checks if the given channel was able to complete * the request successfully. * * @param {nsIChannel} aChannel the channel to check * @param {nsresult} aStatus status code of the request * @param {Object} additionalInfo additional info to be stored in the exception * @return {ServerError} returns null if the request was successful, and a ServerError containing the cause * of the error if the request was not successful */ isRequestSuccess: function (aChannel, aStatus, additionalInfo) { // check if an error occurred // Do not consider NS_IMAGELIB_ERROR_LOAD_ABORTED or NS_ERROR_PARSED_DATA_CACHED as errors, these // are thrown by XUL cache (TODO: remove NS_IMAGELIB_ERROR_LOAD_ABORTED once bug 475344 is fixed for us). if (Components.isSuccessCode(aStatus) || aStatus == 0x80540008 || aStatus == 0x805D0021) { // errors on protocol (HTTP) level give NS_OK on channel and // the error in a protocol-specific way if (aChannel instanceof CI.nsIHttpChannel) { aChannel.QueryInterface(CI.nsIHttpChannel); /* nsIHttpChannel::responseStatus and nsIHttpChannel::responseStatusText * throw an NS_ERROR_NOT_AVAILABLE if the channel did not even * manage to connect to the remote server. */ try { // HTTP 2xx is success if (200 <= aChannel.responseStatus && aChannel.responseStatus < 300) { return null; } else { var responseStatusCode = aChannel.responseStatus; var responseStatusText = aChannel.responseStatusText; // @TODO: we need a facility to translate HTTP error status codes return new ServerError(responseStatusText, -responseStatusCode, aChannel.URI.spec, undefined, additionalInfo); } } catch (e) { let exception = NetUtil.exceptionForStatusCode(Components.results.NS_ERROR_OFFLINE, aChannel.URI.spec, additionalInfo); exception.inner = e; return exception; } } else { debug("Protocol not supported. Can't check whether download worked."); return null; } } else { // an error occurred during downloading the object, try to find out the reason return NetUtil.exceptionForStatusCode(aStatus, aChannel.URI.spec, additionalInfo); } } }; /** * ServerError constructor. * * Note that either an |errorStr| must be passed in or an |id|, but never both. * * @param {String} errorStr A localised error message (must be null if id is set). * @param {Number} errorCode An error code. * @param {String} url The URL that was involved when the error occurred. * @param {Number} severity The severity of this exception, or null if default severity should be used. * @param {String} additionalInfo Additional information, can be null. * @param {String} id The exception id (must be null if errorStr is set). * @constructor */ function ServerError(errorStr, errorCode, url, severity, additionalInfo, id) { var extendedID = (id ? id + "/#" + errorCode + "/" : errorCode + "/#") + url; Exception.call(this, null, extendedID); this.name = "Error from server"; this.code = errorCode; this.url = url; if (errorStr) this.message = errorStr; // overrides message or |null| set by id in Exception ctor this.additionalInfo = additionalInfo; if (severity != null) this.severity = severity; this.errorStr = errorStr; } ServerError.prototype = { code : null, // number (integer), HOME2 error code or HTTP code (latter are 'minus'ed) url : null, // string additionalInfo : null, // object to be dumped into the debug info func : null, // string, same as rpcCall.func debugInfoFromServer : null, // string, extra info from server get message() { if (this.code >= 100 && this.code < 200) // server says protocol violation return NetUtil._getNetErrorStringbundle().GetStringFromName("ServerProtocolError"); if ((this.code >= 200 && this.code < 400) || // server internal error, HOME protocol level (this.code <= -500 && this.code > -600)) // server internal error, HTTP level return NetUtil._getNetErrorStringbundle().GetStringFromName("InternalServerError"); if (this.code >= 780 && this.code < 790) // HORQ-530: do not wrap message return this._message; return NetUtil._getNetErrorStringbundle().formatStringFromName("ServerErrorPrefix", [ this._message ], 1); }, set message(message) { return this._message = message; }, /** * The ServerError class infers the debug information from the error string sent by the server. Therefore, setting it is not suspported. */ set debugInfo(debugInfo) { throw new Bug("Setting debugInfo not supported on ServerError"); }, get debugInfo() { var result = this.errorStr; if (this.code <= -100 && this.code > -1000) // we put a - in front of HTTP codes result += "\nError code: HTTP " + (-this.code); else { var exception = Cc["@mozilla.org/js/xpc/Exception;1"].createInstance(CI.nsIXPCException); exception.initialize(null, this.code, null, null, null, null); if (exception.name) result += "\nError code: " + this.code + " (" + exception.name + ")"; else // no such XPCOM exception exists { // maybe NSS knows let message = NetUtil.nssMessageForStatusCode(this.code); if (message) result += "\nError code: " + this.code + " (" + message + ")"; else result += "\nError code: " + this.code; } } if (this.debugInfoFromServer) result += "\nDebug info from server: " + this.debugInfoFromServer; result += "\nURL: " + this.url; if (this.additionalInfo) result += "\nAdditional information: " + dumpObject(this.additionalInfo, "info", 3); return result; } }; extend(ServerError, Exception); /** * @constructor */ function MozillaException(e) { assert(e instanceof CI.nsIException, "MozillaException wraps only XPCOM exceptions"); Exception.call(this, null, e.result.toString(16)); this.name = "Exception from an XPCOM module"; this._inner = e; this.debugInfo = e.message; } MozillaException.prototype = { get message() { var msg = NetUtil.errorMessageForException(this._inner); if (msg) return msg; return this._message; }, set message(message) { return this._message = message; } }; extend(MozillaException, Exception); /** * Checks whether this is an exception coming from Mozilla, * esp. nsIFile and network errors, and put a user-readable text on it. * * @param e An XPCOM exception object that potentially comes from Mozilla * @return MozillaException, if a Mozilla exception * e (input param) otherwise */ function wrapMozillaException(e) { if (!(e instanceof CI.nsIException) || // XPCOM exception (e.result >= CI.ttIErrorCode.k_BASE && e.result < CI.ttIErrorCode.k_BASE + 0x1000)) // Do *not* change DLL exceptions, DLL will translate return e; // don't touch return new MozillaException(e); }