Bug 1076650: retry registration on a 401 response. r=mikedeboer a=lsblakk
authorPaul Kerr [:pkerr] <pkerr@mozilla.com>
Tue, 23 Dec 2014 12:39:52 +0000
changeset 234507 1fd71b58a91b6f0ea1cda5c678d2e064ccc2c1d8
parent 234506 73276b690a0e3738e3d93697f96e1dfb5396181a
child 234508 d21cf86760b06279765f924cc908b3683af66b82
push id7407
push userrjesup@wgate.com
push dateFri, 26 Dec 2014 16:27:15 +0000
treeherdermozilla-aurora@d21cf86760b0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmikedeboer, lsblakk
bugs1076650
milestone36.0a2
Bug 1076650: retry registration on a 401 response. r=mikedeboer a=lsblakk
browser/components/loop/MozLoopService.jsm
--- a/browser/components/loop/MozLoopService.jsm
+++ b/browser/components/loop/MozLoopService.jsm
@@ -427,35 +427,35 @@ let MozLoopServiceInternal = {
    * for this request, if this is required, use hawkRequest.
    *
    * @param {LOOP_SESSION_TYPE} sessionType The type of session to use for the request.
    *                                        This is one of the LOOP_SESSION_TYPE members.
    * @param {String} path The path to make the request to.
    * @param {String} method The request method, e.g. 'POST', 'GET'.
    * @param {Object} payloadObj An object which is converted to JSON and
    *                            transmitted with the request.
+   * @param {Boolean} [retryOn401=true] Whether to retry if authentication fails.
    * @returns {Promise}
    *        Returns a promise that resolves to the response of the API call,
    *        or is rejected with an error.  If the server response can be parsed
    *        as JSON and contains an 'error' property, the promise will be
    *        rejected with this JSON-parsed response.
    */
-  hawkRequestInternal: function(sessionType, path, method, payloadObj) {
+  hawkRequestInternal: function(sessionType, path, method, payloadObj, retryOn401 = true) {
     if (!gHawkClient) {
       gHawkClient = new HawkClient(this.loopServerUri);
     }
 
-    let sessionToken;
+    let sessionToken, credentials;
     try {
       sessionToken = Services.prefs.getCharPref(this.getSessionTokenPrefName(sessionType));
     } catch (x) {
       // It is ok for this not to exist, we'll default to sending no-creds
     }
 
-    let credentials;
     if (sessionToken) {
       // true = use a hex key, as required by the server (see bug 1032738).
       credentials = deriveHawkCredentials(sessionToken, "sessionToken",
                                           2 * 32, true);
     }
 
     if (payloadObj) {
       // Note: we must copy the object rather than mutate it, to avoid
@@ -466,37 +466,50 @@ let MozLoopServiceInternal = {
           newPayloadObj[property] = CommonUtils.encodeUTF8(payloadObj[property]);
         } else {
           newPayloadObj[property] = payloadObj[property];
         }
       };
       payloadObj = newPayloadObj;
     }
 
-    return gHawkClient.request(path, method, credentials, payloadObj).then((result) => {
-      this.clearError("network");
-      return result;
-    }, (error) => {
-      if (error.code == 401) {
-        this.clearSessionToken(sessionType);
+    let handle401Error = (error) => {
+      if (sessionType === LOOP_SESSION_TYPE.FXA) {
+        MozLoopService.logOutFromFxA().then(() => {
+          // Set a user-visible error after logOutFromFxA clears existing ones.
+          this.setError("login", error);
+        });
+      } else if (this.urlExpiryTimeIsInFuture()) {
+        // If there are no Guest URLs in the future, don't use setError to notify the user since
+        // there isn't a need for a Guest registration at this time.
+        this.setError("registration", error);
+      }
+    };
 
-        if (sessionType == LOOP_SESSION_TYPE.FXA) {
-          MozLoopService.logOutFromFxA().then(() => {
-            // Set a user-visible error after logOutFromFxA clears existing ones.
-            this.setError("login", error);
-          });
-        } else {
-          if (!this.urlExpiryTimeIsInFuture()) {
-            // If there are no Guest URLs in the future, don't use setError to notify the user since
-            // there isn't a need for a Guest registration at this time.
-            throw error;
-          }
-
-          this.setError("registration", error);
+    return gHawkClient.request(path, method, credentials, payloadObj).then(
+      (result) => {
+        this.clearError("network");
+        return result;
+      },
+      (error) => {
+      if (error.code && error.code == 401) {
+        this.clearSessionToken(sessionType);
+        if (retryOn401 && sessionType === LOOP_SESSION_TYPE.GUEST) {
+          log.info("401 and INVALID_AUTH_TOKEN - retry registration");
+          return this.registerWithLoopServer(sessionType, false).then(
+            () => {
+              return this.hawkRequestInternal(sessionType, path, method, payloadObj, false);
+            },
+            () => {
+              handle401Error(error); //Process the original error that triggered the retry.
+              throw error;
+            }
+          );
         }
+        handle401Error(error);
       }
       throw error;
     });
   },
 
   /**
    * Performs a hawk based request to the loop server, registering if necessary.
    *
@@ -620,17 +633,17 @@ let MozLoopServiceInternal = {
     // that will register only the calls notification.
     let msg = {
         simplePushURL: callsPushURL,
         simplePushURLs: {
           calls: callsPushURL,
           rooms: roomsPushURL,
         },
     };
-    return this.hawkRequestInternal(sessionType, "/registration", "POST", msg)
+    return this.hawkRequestInternal(sessionType, "/registration", "POST", msg, false)
       .then((response) => {
         // If this failed we got an invalid token.
         if (!this.storeSessionToken(sessionType, response.headers)) {
           return Promise.reject(new Error("session-token-wrong-size"));
         }
 
         log.debug("Successfully registered with server for sessionType", sessionType);
         this.clearError("registration");