Bug 1397061 - Adjust clock skew according to CDN cache age r=mgoodwin draft
authorMathieu Leplatre <mathieu@mozilla.com>
Wed, 30 May 2018 23:26:59 +0200
changeset 805187 1e19a75e1dd5aa7752d511fcf3256e460dbd9e55
parent 804582 715e3f81f67c5fb9f9810fd80690b429888ae86e
push id112589
push usermleplatre@mozilla.com
push dateThu, 07 Jun 2018 13:02:33 +0000
reviewersmgoodwin
bugs1397061
milestone62.0a1
Bug 1397061 - Adjust clock skew according to CDN cache age r=mgoodwin MozReview-Commit-ID: 9HPiNIp8bJM
services/settings/remote-settings.js
services/settings/test/unit/test_remote_settings_poll.js
--- a/services/settings/remote-settings.js
+++ b/services/settings/remote-settings.js
@@ -159,17 +159,20 @@ async function fetchLatestChanges(url, l
       // expected data (e.g. error response - Bug 1259145)
       throw new Error(`Server error response ${JSON.stringify(payload)}`);
     }
     changes = payload.data;
   }
   // The server should always return ETag. But we've had situations where the CDN
   // was interfering.
   const currentEtag = response.headers.has("ETag") ? response.headers.get("ETag") : undefined;
-  const serverTimeMillis = Date.parse(response.headers.get("Date"));
+  let serverTimeMillis = Date.parse(response.headers.get("Date"));
+  // Since the response is served via a CDN, the Date header value could have been cached.
+  const ageSeconds = response.headers.has("Age") ? parseInt(response.headers.get("Age"), 10) : 0;
+  serverTimeMillis += ageSeconds * 1000;
 
   // Check if the server asked the clients to back off.
   let backoffSeconds;
   if (response.headers.has("Backoff")) {
     const value = parseInt(response.headers.get("Backoff"), 10);
     if (!isNaN(value)) {
       backoffSeconds = value;
     }
--- a/services/settings/test/unit/test_remote_settings_poll.js
+++ b/services/settings/test/unit/test_remote_settings_poll.js
@@ -243,16 +243,39 @@ add_task(async function test_check_clock
 
   clockDifference = Services.prefs.getIntPref(PREF_CLOCK_SKEW_SECONDS);
   // we previously set the serverTime to Date.now() + 10000 ms past epoch
   Assert.ok(clockDifference <= 0 && clockDifference >= -10);
 });
 add_task(clear_state);
 
 
+add_task(async function test_check_clockskew_takes_age_into_account() {
+  const currentTime = Date.now();
+  const skewSeconds = 5;
+  const ageCDNSeconds = 3600;
+  const serverTime = currentTime - (skewSeconds * 1000) - (ageCDNSeconds * 1000);
+
+  function serverResponse(request, response) {
+    response.setHeader("Content-Type", "application/json; charset=UTF-8");
+    response.setHeader("Date", (new Date(serverTime)).toUTCString());
+    response.setHeader("Age", `${ageCDNSeconds}`);
+    response.write(JSON.stringify({data: []}));
+    response.setStatusLine(null, 200, "OK");
+  }
+  server.registerPathHandler(CHANGES_PATH, serverResponse);
+
+  await RemoteSettings.pollChanges();
+
+  const clockSkew = Services.prefs.getIntPref(PREF_CLOCK_SKEW_SECONDS);
+  Assert.ok(clockSkew >= skewSeconds, `clockSkew is ${clockSkew}`);
+});
+add_task(clear_state);
+
+
 add_task(async function test_backoff() {
   const startHistogram = getUptakeTelemetrySnapshot(TELEMETRY_HISTOGRAM_KEY);
 
   function simulateBackoffResponse(request, response) {
     response.setHeader("Content-Type", "application/json; charset=UTF-8");
     response.setHeader("Backoff", "10");
     response.write(JSON.stringify({data: []}));
     response.setStatusLine(null, 200, "OK");