Bug 795851 - Redirects cause dialog asking user if he wants to post his data again. r=mmecca
authorPhilipp Kewisch <mozilla@kewis.ch>
Thu, 20 Nov 2014 13:50:32 +0100
changeset 21475 be0bbb3b6d7c60d44474c806468c7eb6918f5bb1
parent 21474 8ec77939dbd50dc58a808d4397a2c2eed82811dc
child 21476 ca37edf292bed6ddd463bd79e3b7297eb606f39f
push id1305
push usermbanner@mozilla.com
push dateMon, 23 Feb 2015 19:48:12 +0000
treeherdercomm-beta@3ae4f13858fd [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmmecca
bugs795851
Bug 795851 - Redirects cause dialog asking user if he wants to post his data again. r=mmecca
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
@@ -197,16 +197,20 @@ caldavRequestStatusCodeStringGeneric=The
 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?).
+caldavRedirectTitle=Update location for calendar %1$S?
+caldavRedirectText=The requests for %1$S are being redirected to a new location. Would you like to change the location to the following value?
+caldavRedirectDisableCalendar=Disable Calendar
+
 
 # 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).
 #   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
--- a/calendar/providers/caldav/calDavCalendar.js
+++ b/calendar/providers/caldav/calDavCalendar.js
@@ -125,16 +125,18 @@ calDavCalendar.prototype = {
     get supportedItemTypes() {
         return this.mSupportedItemTypes;
     },
 
     get isCached() {
         return (this != this.superCalendar);
     },
 
+    mLastRedirectStatus: null,
+
     ensureTargetCalendar: function caldav_ensureTargetCalendar() {
         if (!this.isCached && !this.mOfflineStorage) {
             // If this is a cached calendar, the actual cache is taken care of
             // by the calCachedCalendar facade. In any other case, we use a
             // memory calendar to cache things.
             this.mOfflineStorage = Components
                                    .classes["@mozilla.org/calendar/calendar;1?type=memory"]
                                    .createInstance(Components.interfaces.calISyncWriteCalendar);
@@ -363,16 +365,18 @@ calDavCalendar.prototype = {
             if (aUseStreamLoader) {
                 let loader = cal.createStreamLoader();
                 listener.onStreamComplete = oauthCheck.bind(null, listener.onStreamComplete.bind(listener));
                 loader.init(listener);
                 listener = loader;
             } else {
                 listener.onStartRequest = oauthCheck.bind(null, listener.onStartRequest.bind(listener));
             }
+
+            self.mLastRedirectStatus = null;
             channel.asyncOpen(listener, channel);
         }
 
         const OAUTH_GRACE_TIME = 30 * 1000;
 
         let usesGoogleOAuth = (aUri && aUri.host == "apidata.googleusercontent.com" && this.oauth);
         let origArgs = arguments;
         let self = this;
@@ -1695,16 +1699,50 @@ calDavCalendar.prototype = {
             } catch (ex) {
                 cal.LOG("CalDAV: Error without status on initial PROPFIND for calendar " +
                         thisCalendar.name);
                 thisCalendar.completeCheckServerInfo(aChangeLogListener,
                                                      Components.interfaces.calIErrors.DAV_NOT_DAV);
                 return;
             }
 
+            let isText = true;
+
+            if ((isText || request.URI.spec != request.originalURI.spec) &&
+                thisCalendar.mLastRedirectStatus == 301) {
+                // The initial PROPFIND essentially goes against the calendar
+                // collection url. If a 301 Moved Permanently redirect occurred
+                // here, we want to modify the url we use in the future.
+                let nIPS = Components.interfaces.nsIPromptService;
+
+                let promptTitle = cal.calGetString("calendar", "caldavRedirectTitle", [thisCalendar.name]);
+                let promptText = cal.calGetString("calendar", "caldavRedirectText", [thisCalendar.name]) +
+                                 "\n\n" + request.URI.spec;
+                let button1Title = cal.calGetString("calendar", "caldavRedirectDisableCalendar");
+                let flags = (nIPS.BUTTON_TITLE_YES * nIPS.BUTTON_POS_0) +
+                            (nIPS.BUTTON_TITLE_IS_STRING * nIPS.BUTTON_POS_1);
+
+                let res = Services.prompt.confirmEx(cal.getCalendarWindow(),
+                                                    promptTitle, promptText,
+                                                    flags, null, button1Title,
+                                                    null, null, {});
+
+                if (res == 0) { // YES
+                    let newUri = request.URI;
+                    cal.LOG("CalDAV: Migrating url due to redirect: " +
+                            thisCalendar.mUri.spec + " -> " + newUri.spec);
+                    thisCalendar.mUri = newUri;
+                    thisCalendar.setProperty("uri", newUri.spec);
+                } else if (res == 1) { // DISABLE CALENDAR
+                    thisCalendar.setProperty("disabled", "true");
+                    thisCalendar.completeCheckServerInfo(aChangeLogListener, Components.results.NS_ERROR_ABORT);
+                    return;
+                }
+            }
+
             let responseStatusCategory = Math.floor(request.responseStatus / 100);
 
             // 4xx codes, which is either an authentication failure or
             // something like method not allowed. This is a failure worth
             // disabling the calendar.
             if (responseStatusCategory == 4) {
                 thisCalendar.setProperty("disabled", "true");
                 thisCalendar.setProperty("auto-enabled", "true");
@@ -2841,16 +2879,22 @@ calDavCalendar.prototype = {
                             uploadContent,
                             this,
                             aNewChannel);
 
         // Make sure we can get/set headers on both channels.
         aNewChannel.QueryInterface(Components.interfaces.nsIHttpChannel);
         aOldChannel.QueryInterface(Components.interfaces.nsIHttpChannel);
 
+        try {
+            this.mLastRedirectStatus = aOldChannel.responseStatus;
+        } catch (e) {
+            this.mLastRedirectStatus = null;
+        }
+
         function copyHeader(aHdr) {
             try {
                 let hdrValue = aOldChannel.getRequestHeader(aHdr);
                 if (hdrValue) {
                     aNewChannel.setRequestHeader(aHdr, hdrValue, false);
                 }
             } catch (e) {
                 if (e.code != Components.results.NS_ERROR_NOT_AVAILIBLE) {