Bug 692700 part 1 - Set X-If-Unmodified-Since when uploading meta/global. r?markh draft
authorEdouard Oger <eoger@fastmail.com>
Tue, 14 Mar 2017 14:42:24 -0400
changeset 503103 a144c495396e5b1708bc60fc78e9b230a4b5a1d2
parent 502997 e03e0c60462c775c7558a1dc9d5cf2076c3cd1f9
child 503104 1bb61b05114f4654ab8ef919c00d3a7966c8b3d1
push id50500
push userbmo:eoger@fastmail.com
push dateWed, 22 Mar 2017 21:06:57 +0000
reviewersmarkh
bugs692700
milestone55.0a1
Bug 692700 part 1 - Set X-If-Unmodified-Since when uploading meta/global. r?markh MozReview-Commit-ID: IoiThiDlvCj
services/sync/modules/service.js
--- a/services/sync/modules/service.js
+++ b/services/sync/modules/service.js
@@ -897,26 +897,19 @@ Sync11Service.prototype = {
       if (this.recordManager.response.status == 401) {
         this._log.debug("Fetching meta/global record on the server returned 401.");
         this.errorHandler.checkServerError(this.recordManager.response);
         return false;
       }
 
       if (this.recordManager.response.status == 404) {
         this._log.debug("No meta/global record on the server. Creating one.");
-        newMeta = new WBORecord("meta", "global");
-        newMeta.payload.syncID = this.syncID;
-        newMeta.payload.storageVersion = STORAGE_VERSION;
-        newMeta.payload.declined = this.engineManager.getDeclined();
-
-        newMeta.isNew = true;
-
-        this.recordManager.set(this.metaURL, newMeta);
-        let uploadRes = newMeta.upload(this.resource(this.metaURL));
-        if (!uploadRes.success) {
+        try {
+          this._uploadNewMetaGlobal();
+        } catch (uploadRes) {
           this._log.warn("Unable to upload new meta/global. Failing remote setup.");
           this.errorHandler.checkServerError(uploadRes);
           return false;
         }
       } else if (!newMeta) {
         this._log.warn("Unable to get meta/global. Failing remote setup.");
         this.errorHandler.checkServerError(this.recordManager.response);
         return false;
@@ -1111,53 +1104,63 @@ Sync11Service.prototype = {
         }
 
         this.uploadMetaGlobal(meta);
       }
     }))();
   },
 
   /**
-   * Upload meta/global, throwing the response on failure.
+   * Upload a fresh meta/global record
+   * @throws the response object if the upload request was not a success
+   */
+  _uploadNewMetaGlobal() {
+    let meta = new WBORecord("meta", "global");
+    meta.payload.syncID = this.syncID;
+    meta.payload.storageVersion = STORAGE_VERSION;
+    meta.payload.declined = this.engineManager.getDeclined();
+    meta.modified = 0;
+    meta.isNew = true;
+
+    this.uploadMetaGlobal(meta);
+  },
+
+  /**
+   * Upload meta/global, throwing the response on failure
+   * @param {WBORecord} meta meta/global record
+   * @throws the response object if the request was not a success
    */
   uploadMetaGlobal(meta) {
-    this._log.debug("Uploading meta/global: " + JSON.stringify(meta));
-
-    // It would be good to set the X-If-Unmodified-Since header to `timestamp`
-    // for this PUT to ensure at least some level of transactionality.
-    // Unfortunately, the servers don't support it after a wipe right now
-    // (bug 693893), so we're going to defer this until bug 692700.
+    this._log.debug("Uploading meta/global", meta);
     let res = this.resource(this.metaURL);
+    res.setHeader("X-If-Unmodified-Since", meta.modified);
     let response = res.put(meta);
     if (!response.success) {
       throw response;
     }
+    // From https://docs.services.mozilla.com/storage/apis-1.5.html:
+    // "Successful responses will return the new last-modified time for the collection."
+    meta.modified = response.obj;
     this.recordManager.set(this.metaURL, meta);
   },
 
   _freshStart: function _freshStart() {
     this._log.info("Fresh start. Resetting client.");
     this.resetClient();
     this.collectionKeys.clear();
 
     // Wipe the server.
     this.wipeServer();
 
     // Upload a new meta/global record.
-    let meta = new WBORecord("meta", "global");
-    meta.payload.syncID = this.syncID;
-    meta.payload.storageVersion = STORAGE_VERSION;
-    meta.payload.declined = this.engineManager.getDeclined();
-    meta.isNew = true;
-
-    // uploadMetaGlobal throws on failure -- including race conditions.
+    // _uploadNewMetaGlobal throws on failure -- including race conditions.
     // If we got into a race condition, we'll abort the sync this way, too.
     // That's fine. We'll just wait till the next sync. The client that we're
     // racing is probably busy uploading stuff right now anyway.
-    this.uploadMetaGlobal(meta);
+    this._uploadNewMetaGlobal();
 
     // Wipe everything we know about except meta because we just uploaded it
     // TODO: there's a bug here. We should be calling resetClient, no?
 
     // Generate, upload, and download new keys. Do this last so we don't wipe
     // them...
     this.generateNewSymmetricKeys();
   },