Bug 566339 - CalDAV errors lack enough information (r=philipp)
authorSimon Vaillancourt <simon.at.orcl@gmail.com>
Thu, 17 Jun 2010 11:18:37 -0400
changeset 5840 c845e4a3388b1fc49f857007b0b0117ee72236b7
parent 5839 99c90729cce73e05d6d150d6b9c1d6687b43d486
child 5841 ad50e0b068f85192ac7a3020691ab01de244fbaa
push idunknown
push userunknown
push dateunknown
reviewersphilipp
bugs566339
Bug 566339 - CalDAV errors lack enough information (r=philipp)
calendar/locales/en-US/chrome/calendar/calendar.properties
calendar/providers/caldav/calDavCalendar.js
--- a/calendar/locales/en-US/chrome/calendar/calendar.properties
+++ b/calendar/locales/en-US/chrome/calendar/calendar.properties
@@ -37,17 +37,17 @@
 # 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 *****
 
 # Misc. strings in JS
 
-# LOCALIZATION NOTE (PrintPreviewWindowTitle): 
+# LOCALIZATION NOTE (PrintPreviewWindowTitle):
 #    %1$S will be replaced with the title of a html frame
 PrintPreviewWindowTitle=Print Preview of %1$S
 Untitled=Untitled
 
 # Default name for new events
 newEvent=New Event
 
 # Titles for the event/task dialog
@@ -85,35 +85,35 @@ statusCompleted     =Completed
 highPriority=High
 mediumPriority=Medium
 lowPriority=Low
 
 importPrompt=Which calendar do you want to import these items into?
 exportPrompt=Which calendar do you want to export from?
 publishPrompt=Which calendar do you want to publish?
 
-# LOCALIZATION NOTE (importItemsFailed): 
+# LOCALIZATION NOTE (importItemsFailed):
 #    %1$S will be replaced with number of failed items
 #    %2$S will be replaced with last error code / error string
 importItemsFailed=%1$S items failed to import. The last error was: %2$S
 
 #spaces needed at the end of the following lines
 eventDescription=Description:
 
-unableToRead=Unable to read from file: 
-unableToWrite=Unable to write to file: 
+unableToRead=Unable to read from file:
+unableToWrite=Unable to write to file:
 defaultFileName=MozillaCalEvents
 HTMLTitle=Mozilla Calendar
 
-# LOCALIZATION NOTE (timezoneError): 
+# LOCALIZATION NOTE (timezoneError):
 # used for an error message like 'An unknown and undefined timezone was found while reading c:\Mycalendarfile.ics'
 #    %1$S will be replaced with the path to a file
 timezoneError=An unknown and undefined timezone was found while reading %1$S.
 
-# LOCALIZATION NOTE (duplicateError): 
+# LOCALIZATION NOTE (duplicateError):
 #    %1$S will be replaced with number of duplicate items
 #    %2$S will be replaced with a file path pointing to a calendar
 duplicateError=%1$S item(s) were ignored since they exist in both the destination calendar and %2$S.
 
 unableToCreateProvider=An error was encountered preparing the calendar located at %1$S for use. It will not be available.
 unknownTimezonesError=An error was encountered preparing the calendar located at %1$S for use. The calendar might refer to unknown timezones. Please install the latest calendar-timezones.xpi.
 missingCalendarTimezonesError=No timezones found! Please install calendar-timezones.xpi.
 
@@ -227,21 +227,31 @@ updateFromServer=Discard my changes and 
 proceedModify=Submit my changes anyway
 proceedDelete=Delete anyway
 dav_notDav=The resource at %1$S is either not a DAV collection or not available
 dav_davNotCaldav=The resource at %1$S is a DAV collection but not a CalDAV calendar
 itemPutError=There was an error storing the item on the server.
 itemDeleteError=There was an error deleting the item from the server.
 caldavRequestError=An error occurred when sending the invitation.
 caldavResponseError=An error occurred when sending the response.
+caldavRequestStatusCode=Status Code: %1$S
+caldavRequestStatusCodeStringGeneric=The request cannot be processed.
+caldavRequestStatusCodeString400=The request contains bad syntax and cannot be processed.
+caldavRequestStatusCodeString403=The user lacks the required permission to perform the request.
+caldavRequestStatusCodeString404=Resource not found.
+caldavRequestStatusCodeString409=Resource conflict.
+caldavRequestStatusCodeString412=Precondition failed.
+caldavRequestStatusCodeString500=Internal server error.
+caldavRequestStatusCodeString502=Bad gateway (Proxy configuration?).
+caldavRequestStatusCodeString503=Internal server error (Temporary server outage?).
 
 # LOCALIZATION NOTE (likelyTimezone):
 #   Translators, please put the most likely timezone(s) where the people using
 #   your locale will be.  Use the Olson ZoneInfo timezone name *in English*,
-#   ie "Europe/Paris", (continent or ocean)/(largest city in timezone). 
+#   ie "Europe/Paris", (continent or ocean)/(largest city in timezone).
 #   Order does not matter, except if two historically different zones now match,
 #   such as America/New_York and America/Toronto, will only find first listed.
 #   (Particularly needed to guess the most relevant timezones if there are
 #    similar timezones at the same June/December GMT offsets with alphabetically
 #    earlier ZoneInfo timezone names.  Sample explanations for English below.)
 # for english-US:
 #   America/Los_Angeles likelier than America/Dawson
 #   America/New_York    likelier than America/Detroit (NY for US-EasternTime)
@@ -258,27 +268,27 @@ caldavResponseError=An error occurred wh
 #   Africa/Johannesburg likelier than Africa/Blantyre (for SouthAfricanStdTime)
 #   Africa/Nairobi likelier than Africa/Addis_Ababa (for EastAfricanTime)
 #   Australia/Brisbane likelier than Antarctica/DumontDUrville
 #   Australia/Sydney likelier than Australia/Currie or Australia/Hobart
 #   Pacific/Auckland likelier than Antarctica/McMurdo
 likelyTimezone=America/New_York, America/Chicago, America/Denver, America/Phoenix, America/Los_Angeles, America/Anchorage, America/Adak, Pacific/Honolulu, America/Puerto_Rico, America/Halifax, America/Mexico_City, America/Argentina/Buenos_Aires, America/Sao_Paulo, Europe/London, Europe/Paris, Asia/Singapore, Asia/Tokyo, Africa/Lagos, Africa/Johannesburg, Africa/Nairobi, Australia/Brisbane, Australia/Sydney, Pacific/Auckland
 
 # Guessed Timezone errors and warnings.
-# Testing note:  
+# Testing note:
 # * remove preference for calendar.timezone.default in userprofile/prefs.js
 # * repeat
 #   - set OS timezone to a city (windows: click right on clock in taskbar)
 #   - restart: sunbird -jsconsole
 #   - observe guess in error console and verify whether guessed timezone city
 #     makes sense for OS city.
 #
-# 'Warning: Operating system timezone "E. South America Standard Time" 
+# 'Warning: Operating system timezone "E. South America Standard Time"
 #  no longer matches ZoneInfo timezone "America/Sao_Paulo".'
-# Testing notes: 
+# Testing notes:
 # - Brasil DST change dates are set every year by decree, so likely out of sync.
 # - Only appears on OSes from which timezone can be obtained
 #   (windows; or TZ env var, /etc/localtime target path, or line in
 #    /etc/timezone or /etc/sysconfig/clock contains ZoneInfo timezone id).
 # - Windows: turning off "Automatically adjust clock for daylight saving time"
 #   can also trigger this warning.
 WarningOSTZNoMatch=Warning: Operating system timezone "%1$S"\nno longer matches the internal ZoneInfo timezone "%2$S".
 
@@ -300,29 +310,29 @@ warningUsingFloatingTZNoMatch=Warning: U
 
 # "Warning:  Using guessed timezone
 #    America/New York (UTC-0500/-0400).
 #    [rfc2445 summer daylight saving shift rules for timezone]
 #  This ZoneInfo timezone almost matches/seems to match..."
 #  This ZoneInfo timezone was chosen based on ... "
 WarningUsingGuessedTZ=Warning:  Using guessed timezone\n  %1$S (UTC%2$S).\n%3$S\n%4$S
 
-# Testing note: "Almost match" timezones include Cairo on W2k. 
+# Testing note: "Almost match" timezones include Cairo on W2k.
 TZAlmostMatchesOSDifferAtMostAWeek=This ZoneInfo timezone almost matches the operating system timezone.\nFor this rule, the next transitions between daylight and standard time\ndiffer at most a week from the operating system timezone transitions.\nThere may be discrepancies in the data, such as differing start date,\nor differing rule, or approximation for non-Gregorian-calendar rule.
 
 TZSeemsToMatchOS=This ZoneInfo timezone seems to match the operating system timezone this year.
 
 # LOCALIZATION NOTE (TZFromOS):
 # used for a display of a chosen timezone
 #    %1$S will be replaced with the name of a timezone
 TZFromOS=This ZoneInfo timezone was chosen based on the operating system timezone\nidentifier "%1$S".
 
 # Localization note (TZFromLocale): Substitute name of your locale language.
 TZFromLocale=This ZoneInfo timezone was chosen based on matching the operating system\ntimezone with likely timezones for internet users using US English.
-  
+
 TZFromKnownTimezones=This ZoneInfo timezone was chosen based on matching the operating system\ntimezone with known timezones in alphabetical order of timezone id.
 
 # Print Layout
 formatListName = List
 weekPrinterName = Weekly Planner
 monthPrinterName = Monthly Grid
 tasksWithNoDueDate = Tasks with no due date
 
--- a/calendar/providers/caldav/calDavCalendar.js
+++ b/calendar/providers/caldav/calDavCalendar.js
@@ -510,16 +510,17 @@ calDavCalendar.prototype = {
 
         let parentItem = aItem.parentItem;
         var locationPath = this.getItemLocationPath(parentItem);
         var itemUri = this.makeUri(locationPath);
         cal.LOG("CalDAV: itemUri.spec = " + itemUri.spec);
 
         var addListener = {};
         var thisCalendar = this;
+        let serializedItem = this.getSerializedItem(aItem);
         addListener.onStreamComplete =
             function onPutComplete(aLoader, aContext, aStatus, aResultLength,
                                    aResult) {
             let request = aLoader.request.QueryInterface(Components.interfaces.nsIHttpChannel);
             let status;
             try {
                 status = request.responseStatus;
             } catch (ex) {
@@ -539,27 +540,36 @@ calDavCalendar.prototype = {
                 // for instance) so we'd best re-fetch in order to know
                 // the current state of the item
                 // Observers will be notified in getUpdatedItem()
                 thisCalendar.getUpdatedItem(parentItem, aListener);
             } else {
                 if (status > 999) {
                     status = "0x" + status.toString(16);
                 }
-                cal.LOG("CalDAV: Unexpected status adding item to " +
-                        thisCalendar.name + ": " + status);
+                let responseBody="";
+                try {
+                    responseBody = cal.convertByteArray(aResult, aResultLength);
+                } catch(e) {}
 
-                thisCalendar.reportDavError(Components.interfaces.calIErrors.DAV_PUT_ERROR);
+                cal.ERROR("CalDAV: Unexpected status adding item to " +
+                          thisCalendar.name + ": " + status + "\n" +
+                          responseBody + "\n" +
+                          serializedItem);
+
+                thisCalendar.reportDavError(Components.interfaces.calIErrors.DAV_PUT_ERROR,
+                                            status,
+                                            responseBody);
             }
         };
 
         parentItem.calendar = this.superCalendar;
 
         let httpchannel = cal.prepHttpChannel(itemUri,
-                                              this.getSerializedItem(aItem),
+                                              serializedItem,
                                               "text/calendar; charset=utf-8",
                                               this);
 
 
         if (!aIgnoreEtag) {
             httpchannel.setRequestHeader("If-None-Match", "*", false);
         }
 
@@ -642,19 +652,31 @@ calDavCalendar.prototype = {
                 }
             } else if (status == 412) {
                 thisCalendar.promptOverwrite(CALDAV_MODIFY_ITEM, aNewItem,
                                              aListener, aOldItem);
             } else {
                 if (status > 999) {
                     status = "0x " + status.toString(16);
                 }
-                cal.LOG("CalDAV: Unexpected status on modifying item on " +
-                        thisCalendar.name + ": " + status);
-                thisCalendar.reportDavError(Components.interfaces.calIErrors.DAV_PUT_ERROR);
+
+                let responseBody="";
+                try {
+                    responseBody = cal.convertByteArray(aResult, aResultLength);
+                } catch(e) {}
+
+
+                cal.ERROR("CalDAV: Unexpected status modifying item to " +
+                        thisCalendar.name + ": " + status + "\n" +
+                        responseBody + "\n" +
+                        modifiedItemICS);
+
+                thisCalendar.reportDavError(Components.interfaces.calIErrors.DAV_PUT_ERROR,
+                                            status,
+                                            responseBody);
             }
         };
 
         let httpchannel = cal.prepHttpChannel(eventUri,
                                               modifiedItemICS,
                                               "text/calendar; charset=utf-8",
                                               this);
 
@@ -744,24 +766,29 @@ calDavCalendar.prototype = {
 
                 let httpchannel2 = cal.prepHttpChannel(eventUri,
                                                        null,
                                                        null,
                                                        thisCalendar);
                 httpchannel2.requestMethod = "HEAD";
                 cal.sendHttpRequest(cal.createStreamLoader(), httpchannel2, delListener2);
             } else {
-                let str;
+                let responseBody="";
                 try {
-                    str = cal.convertByteArray(aResult, aResultLength);
+                    responseBody = cal.convertByteArray(aResult, aResultLength);
                 } catch(e) {}
-                cal.LOG("CalDAV: Unexpected status " + status +
-                        " deleting item from " + thisCalendar.name +
-                        ". Content:\n" + str);
-                thisCalendar.reportDavError(Components.interfaces.calIErrors.DAV_REMOVE_ERROR);
+
+                cal.ERROR("CalDAV: Unexpected status deleting item from " +
+                          thisCalendar.name + ": " + status + "\n" +
+                          responseBody + "\n" +
+                          "uri: " + eventUri.spec);
+
+                thisCalendar.reportDavError(Components.interfaces.calIErrors.DAV_REMOVE_ERROR,
+                                            status,
+                                            responseBody);
             }
         };
         var delListener2 = {};
         delListener2.onStreamComplete =
         function caldav_dDI_del2_onStreamComplete(aLoader, aContext, aStatus, aResultLength, aResult) {
             let request = aLoader.request.QueryInterface(Components.interfaces.nsIHttpChannel);
             let status = request.responseStatus;
             if (status == 404) {
@@ -1854,17 +1881,17 @@ calDavCalendar.prototype = {
             }
         }
     },
 
     /**
      * Called to report a certain DAV error. Strings and modification type are
      * handled here.
      */
-    reportDavError: function caldav_reportDavError(aErrNo) {
+    reportDavError: function caldav_reportDavError(aErrNo, status, extraInfo) {
         var mapError = {};
         mapError[Components.interfaces.calIErrors.DAV_NOT_DAV] = "dav_notDav";
         mapError[Components.interfaces.calIErrors.DAV_DAV_NOT_CALDAV] = "dav_davNotCaldav";
         mapError[Components.interfaces.calIErrors.DAV_PUT_ERROR] = "itemPutError";
         mapError[Components.interfaces.calIErrors.DAV_REMOVE_ERROR] = "itemDeleteError";
         mapError[Components.interfaces.calIErrors.DAV_REPORT_ERROR] = "disabledMode";
 
         var mapModification = {};
@@ -1885,17 +1912,36 @@ calDavCalendar.prototype = {
 
         this.mReadOnly = true;
         this.mDisabled = true;
         this.notifyError(aErrNo,
                          calGetString("calendar", message , [this.mUri.spec]));
         this.notifyError(modificationError
                          ? Components.interfaces.calIErrors.MODIFICATION_FAILED
                          : Components.interfaces.calIErrors.READ_FAILED,
-                         "");
+                         this.buildDetailedMessage(status, extraInfo));
+    },
+
+    buildDetailedMessage : function caldav_buildDetailedMessage(status, extraInfo) {
+        if (!status || !extraInfo) {
+            return "";
+        }
+
+        var props = calGetStringBundle("chrome://calendar/locale/calendar.properties");
+        let statusString;
+        try {
+            statusString = props.GetStringFromName("caldavRequestStatusCodeString" + status);
+        } catch (e) {
+            // Fallback on generic string if no string is defined for the status code
+            statusString = props.GetStringFromName("caldavRequestStatusCodeStringGeneric");
+        }
+        return props.formatStringFromName("caldavRequestStatusCode", [ status ], 1) + ", " +
+               statusString + "\n\n" +
+               extraInfo;
+
     },
 
     //
     // calIFreeBusyProvider interface
     //
 
     getFreeBusyIntervals: function caldav_getFreeBusyIntervals(
         aCalId, aRangeStart, aRangeEnd, aBusyTypes, aListener) {