Bug 974990 - hawk request to access lang prefs as infrequently as possible. r=rnewman
☠☠ backed out by 2e340e446426 ☠ ☠
authorJed Parsons <jedp@mozilla.com>
Thu, 20 Feb 2014 18:04:44 -0800
changeset 170416 96fd88a4d31118eadde9029231ba71fe0348a155
parent 170415 2d851a8e2c677693e6bbf91c729ca2f20d92d77d
child 170417 b96e4b7e4be6bf2b4a63e5a73f3aa6581d7af953
push id26288
push userryanvm@gmail.com
push dateTue, 25 Feb 2014 20:20:43 +0000
treeherdermozilla-central@22650589a724 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersrnewman
bugs974990
milestone30.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 974990 - hawk request to access lang prefs as infrequently as possible. r=rnewman
services/common/Makefile.in
services/common/hawk.js
services/common/hawkclient.js
services/common/hawkrequest.js
services/common/rest.js
services/common/tests/unit/test_hawk.js
services/common/tests/unit/test_hawkclient.js
services/common/tests/unit/test_hawkrequest.js
services/common/tests/unit/test_restrequest.js
services/common/tests/unit/xpcshell.ini
services/fxaccounts/FxAccountsClient.jsm
services/fxaccounts/tests/mochitest/test_invalidEmailCase.html
services/sync/tests/unit/test_browserid_identity.js
--- a/services/common/Makefile.in
+++ b/services/common/Makefile.in
@@ -1,14 +1,15 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
 modules := \
-  hawk.js \
+  hawkclient.js \
+  hawkrequest.js \
   storageservice.js \
   stringbundle.js \
   tokenserverclient.js \
   utils.js \
   $(NULL)
 
 pp_modules := \
   async.js \
rename from services/common/hawk.js
rename to services/common/hawkclient.js
--- a/services/common/hawk.js
+++ b/services/common/hawkclient.js
@@ -26,17 +26,17 @@
 
 this.EXPORTED_SYMBOLS = ["HawkClient"];
 
 const {interfaces: Ci, utils: Cu} = Components;
 
 Cu.import("resource://gre/modules/FxAccountsCommon.js");
 Cu.import("resource://services-common/utils.js");
 Cu.import("resource://services-crypto/utils.js");
-Cu.import("resource://services-common/rest.js");
+Cu.import("resource://services-common/hawkrequest.js");
 Cu.import("resource://gre/modules/Promise.jsm");
 
 /*
  * A general purpose client for making HAWK authenticated requests to a single
  * host.  Keeps track of the clock offset between the client and the host for
  * computation of the timestamp in the HAWK Authorization header.
  *
  * Clients should create one HawkClient object per each server they wish to
new file mode 100644
--- /dev/null
+++ b/services/common/hawkrequest.js
@@ -0,0 +1,145 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
+
+this.EXPORTED_SYMBOLS = [
+  "HAWKAuthenticatedRESTRequest",
+];
+
+Cu.import("resource://gre/modules/Preferences.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/Log.jsm");
+Cu.import("resource://services-common/rest.js");
+
+XPCOMUtils.defineLazyModuleGetter(this, "CryptoUtils",
+                                  "resource://services-crypto/utils.js");
+
+const Prefs = new Preferences("services.common.rest.");
+
+/**
+ * Single-use HAWK-authenticated HTTP requests to RESTish resources.
+ *
+ * @param uri
+ *        (String) URI for the RESTRequest constructor
+ *
+ * @param credentials
+ *        (Object) Optional credentials for computing HAWK authentication
+ *        header.
+ *
+ * @param payloadObj
+ *        (Object) Optional object to be converted to JSON payload
+ *
+ * @param extra
+ *        (Object) Optional extra params for HAWK header computation.
+ *        Valid properties are:
+ *
+ *          now:                 <current time in milliseconds>,
+ *          localtimeOffsetMsec: <local clock offset vs server>
+ *
+ * extra.localtimeOffsetMsec is the value in milliseconds that must be added to
+ * the local clock to make it agree with the server's clock.  For instance, if
+ * the local clock is two minutes ahead of the server, the time offset in
+ * milliseconds will be -120000.
+ */
+
+this.HAWKAuthenticatedRESTRequest =
+ function HawkAuthenticatedRESTRequest(uri, credentials, extra={}) {
+  RESTRequest.call(this, uri);
+
+  this.credentials = credentials;
+  this.now = extra.now || Date.now();
+  this.localtimeOffsetMsec = extra.localtimeOffsetMsec || 0;
+  this._log.trace("local time, offset: " + this.now + ", " + (this.localtimeOffsetMsec));
+
+  // Expose for testing
+  this._intl = getIntl();
+};
+HAWKAuthenticatedRESTRequest.prototype = {
+  __proto__: RESTRequest.prototype,
+
+  dispatch: function dispatch(method, data, onComplete, onProgress) {
+    let contentType = "text/plain";
+    if (method == "POST" || method == "PUT") {
+      contentType = "application/json";
+    }
+    if (this.credentials) {
+      let options = {
+        now: this.now,
+        localtimeOffsetMsec: this.localtimeOffsetMsec,
+        credentials: this.credentials,
+        payload: data && JSON.stringify(data) || "",
+        contentType: contentType,
+      };
+      let header = CryptoUtils.computeHAWK(this.uri, method, options);
+      this.setHeader("Authorization", header.field);
+      this._log.trace("hawk auth header: " + header.field);
+    }
+
+    this.setHeader("Content-Type", contentType);
+
+    this.setHeader("Accept-Language", this._intl.accept_languages);
+
+    return RESTRequest.prototype.dispatch.call(
+      this, method, data, onComplete, onProgress
+    );
+  }
+};
+
+// With hawk request, we send the user's accepted-languages with each request.
+// To keep the number of times we read this pref at a minimum, maintain the
+// preference in a stateful object that notices and updates itself when the
+// pref is changed.
+this.Intl = function Intl() {
+  // We won't actually query the pref until the first time we need it
+  this._accepted = "";
+  this._everRead = false;
+  this._log = Log.repository.getLogger("Services.common.RESTRequest");
+  this._log.level = Log.Level[Prefs.get("log.logger.rest.request")];
+  this.init();
+};
+
+this.Intl.prototype = {
+  init: function() {
+    Services.prefs.addObserver("intl.accept_languages", this, false);
+  },
+
+  uninit: function() {
+    Services.prefs.removeObserver("intl.accept_languages", this);
+  },
+
+  observe: function(subject, topic, data) {
+    this.readPref();
+  },
+
+  readPref: function() {
+    this._everRead = true;
+    try {
+      this._accepted = Services.prefs.getComplexValue(
+        "intl.accept_languages", Ci.nsIPrefLocalizedString).data;
+    } catch (err) {
+      this._log.error("Error reading intl.accept_languages pref: " + CommonUtils.exceptionStr(err));
+    }
+  },
+
+  get accept_languages() {
+    if (!this._everRead) {
+      this.readPref();
+    }
+    return this._accepted;
+  },
+};
+
+// Singleton getter for Intl, creating an instance only when we first need it.
+let intl = null;
+function getIntl() {
+  if (!intl) {
+    intl = new Intl();
+  }
+  return intl;
+}
+
--- a/services/common/rest.js
+++ b/services/common/rest.js
@@ -5,17 +5,16 @@
 #ifndef MERGED_COMPARTMENT
 
 const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
 
 this.EXPORTED_SYMBOLS = [
   "RESTRequest",
   "RESTResponse",
   "TokenAuthenticatedRESTRequest",
-  "HAWKAuthenticatedRESTRequest",
 ];
 
 #endif
 
 Cu.import("resource://gre/modules/Preferences.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Log.jsm");
@@ -720,80 +719,8 @@ TokenAuthenticatedRESTRequest.prototype 
     this.setHeader("Authorization", sig.getHeader());
 
     return RESTRequest.prototype.dispatch.call(
       this, method, data, onComplete, onProgress
     );
   },
 };
 
-/**
- * Single-use HAWK-authenticated HTTP requests to RESTish resources.
- *
- * @param uri
- *        (String) URI for the RESTRequest constructor
- *
- * @param credentials
- *        (Object) Optional credentials for computing HAWK authentication
- *        header.
- *
- * @param payloadObj
- *        (Object) Optional object to be converted to JSON payload
- *
- * @param extra
- *        (Object) Optional extra params for HAWK header computation.
- *        Valid properties are:
- *
- *          now:                 <current time in milliseconds>,
- *          localtimeOffsetMsec: <local clock offset vs server>
- *
- * extra.localtimeOffsetMsec is the value in milliseconds that must be added to
- * the local clock to make it agree with the server's clock.  For instance, if
- * the local clock is two minutes ahead of the server, the time offset in
- * milliseconds will be -120000.
- */
-this.HAWKAuthenticatedRESTRequest =
- function HawkAuthenticatedRESTRequest(uri, credentials, extra={}) {
-  RESTRequest.call(this, uri);
-
-  this.credentials = credentials;
-  this.now = extra.now || Date.now();
-  this.localtimeOffsetMsec = extra.localtimeOffsetMsec || 0;
-  this._log.trace("local time, offset: " + this.now + ", " + (this.localtimeOffsetMsec));
-};
-HAWKAuthenticatedRESTRequest.prototype = {
-  __proto__: RESTRequest.prototype,
-
-  dispatch: function dispatch(method, data, onComplete, onProgress) {
-    let contentType = "text/plain";
-    if (method == "POST" || method == "PUT") {
-      contentType = "application/json";
-    }
-    if (this.credentials) {
-      let options = {
-        now: this.now,
-        localtimeOffsetMsec: this.localtimeOffsetMsec,
-        credentials: this.credentials,
-        payload: data && JSON.stringify(data) || "",
-        contentType: contentType,
-      };
-      let header = CryptoUtils.computeHAWK(this.uri, method, options);
-      this.setHeader("Authorization", header.field);
-      this._log.trace("hawk auth header: " + header.field);
-    }
-
-    this.setHeader("Content-Type", contentType);
-
-    try {
-      let acceptLanguage = Services.prefs.getComplexValue(
-          "intl.accept_languages", Ci.nsIPrefLocalizedString).data;
-      if (acceptLanguage) {
-        this.setHeader("Accept-Language", acceptLanguage);
-      }
-    } catch (err) {
-      this._log.error("Error reading intl.accept_languages pref: " + CommonUtils.exceptionStr(err));
-    }
-
-    return RESTRequest.prototype.dispatch.call(
-      this, method, data, onComplete, onProgress
-    );
-  }
-};
rename from services/common/tests/unit/test_hawk.js
rename to services/common/tests/unit/test_hawkclient.js
--- a/services/common/tests/unit/test_hawk.js
+++ b/services/common/tests/unit/test_hawkclient.js
@@ -1,15 +1,15 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 Cu.import("resource://gre/modules/Promise.jsm");
-Cu.import("resource://services-common/hawk.js");
+Cu.import("resource://services-common/hawkclient.js");
 
 const SECOND_MS = 1000;
 const MINUTE_MS = SECOND_MS * 60;
 const HOUR_MS = MINUTE_MS * 60;
 
 const TEST_CREDS = {
   id: "eyJleHBpcmVzIjogMTM2NTAxMDg5OC4x",
   key: "qTZf4ZFpAMpMoeSsX3zVRjiqmNs=",
new file mode 100644
--- /dev/null
+++ b/services/common/tests/unit/test_hawkrequest.js
@@ -0,0 +1,211 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+Cu.import("resource://gre/modules/Log.jsm");
+Cu.import("resource://services-common/utils.js");
+Cu.import("resource://services-common/hawkrequest.js");
+
+function do_register_cleanup() {
+  Services.prefs.resetUserPrefs();
+
+  // remove the pref change listener
+  let hawk = new HAWKAuthenticatedRESTRequest("https://example.com");
+  hawk._intl.uninit();
+}
+
+function run_test() {
+  Log.repository.getLogger("Services.Common.RESTRequest").level =
+    Log.Level.Trace;
+  initTestLogging("Trace");
+
+  run_next_test();
+}
+
+
+add_test(function test_intl_accept_language() {
+  let testCount = 0;
+  let languages = [
+    "zu-NP;vo",     // Nepalese dialect of Zulu, defaulting to Volap√ľk
+    "fa-CG;ik",     // Congolese dialect of Farsei, defaulting to Inupiaq
+  ];
+
+  function setLanguage(lang) {
+    let acceptLanguage = Cc["@mozilla.org/supports-string;1"]
+                           .createInstance(Ci.nsISupportsString);
+    acceptLanguage.data = lang;
+    Services.prefs.setComplexValue(
+      "intl.accept_languages", Ci.nsISupportsString, acceptLanguage);
+  }
+
+  let hawk = new HAWKAuthenticatedRESTRequest("https://example.com");
+
+  Services.prefs.addObserver("intl.accept_languages", nextTest, false);
+  setLanguage(languages[testCount]);
+
+  function nextTest() {
+    CommonUtils.nextTick(function() {
+      if (testCount < 2) {
+        do_check_eq(hawk._intl.accept_languages, languages[testCount]);
+
+        testCount += 1;
+        setLanguage(languages[testCount]);
+        nextTest();
+        return;
+      }
+      Services.prefs.removeObserver("intl.accept_languages", nextTest);
+      run_next_test();
+      return;
+    });
+  }
+});
+
+add_test(function test_hawk_authenticated_request() {
+  let onProgressCalled = false;
+  let postData = {your: "data"};
+
+  // An arbitrary date - Feb 2, 1971.  It ends in a bunch of zeroes to make our
+  // computation with the hawk timestamp easier, since hawk throws away the
+  // millisecond values.
+  let then = 34329600000;
+
+  let clockSkew = 120000;
+  let timeOffset = -1 * clockSkew;
+  let localTime = then + clockSkew;
+
+  // Set the accept-languages pref to the Nepalese dialect of Zulu.
+  let acceptLanguage = Cc['@mozilla.org/supports-string;1'].createInstance(Ci.nsISupportsString);
+  acceptLanguage.data = 'zu-NP'; // omit trailing ';', which our HTTP libs snip
+  Services.prefs.setComplexValue('intl.accept_languages', Ci.nsISupportsString, acceptLanguage);
+
+  let credentials = {
+    id: "eyJleHBpcmVzIjogMTM2NTAxMDg5OC4x",
+    key: "qTZf4ZFpAMpMoeSsX3zVRjiqmNs=",
+    algorithm: "sha256"
+  };
+
+  let server = httpd_setup({
+    "/elysium": function(request, response) {
+      do_check_true(request.hasHeader("Authorization"));
+
+      // check that the header timestamp is our arbitrary system date, not
+      // today's date.  Note that hawk header timestamps are in seconds, not
+      // milliseconds.
+      let authorization = request.getHeader("Authorization");
+      let tsMS = parseInt(/ts="(\d+)"/.exec(authorization)[1], 10) * 1000;
+      do_check_eq(tsMS, then);
+
+      // This testing can be a little wonky. In an environment where
+      //   pref("intl.accept_languages") === 'en-US, en'
+      // the header is sent as:
+      //   'en-US,en;q=0.5'
+      // hence our fake value for acceptLanguage.
+      let lang = request.getHeader("Accept-Language");
+      do_check_eq(lang, acceptLanguage);
+
+      let message = "yay";
+      response.setStatusLine(request.httpVersion, 200, "OK");
+      response.bodyOutputStream.write(message, message.length);
+    }
+  });
+
+  function onProgress() {
+    onProgressCalled = true;
+  }
+
+  function onComplete(error) {
+    do_check_eq(200, this.response.status);
+    do_check_eq(this.response.body, "yay");
+    do_check_true(onProgressCalled);
+
+    Services.prefs.resetUserPrefs();
+    let pref = Services.prefs.getComplexValue(
+      "intl.accept_languages", Ci.nsIPrefLocalizedString);
+    do_check_neq(acceptLanguage.data, pref.data);
+
+    server.stop(run_next_test);
+  }
+
+  let url = server.baseURI + "/elysium";
+  let extra = {
+    now: localTime,
+    localtimeOffsetMsec: timeOffset
+  };
+
+  let request = new HAWKAuthenticatedRESTRequest(url, credentials, extra);
+
+  // Allow hawk._intl to respond to the language pref change
+  CommonUtils.nextTick(function() {
+    request.post(postData, onComplete, onProgress);
+  });
+});
+
+add_test(function test_hawk_language_pref_changed() {
+  let attempt = 0;
+  let languages = [
+    "zu-NP",        // Nepalese dialect of Zulu
+    "fa-CG",        // Congolese dialect of Farsi
+  ];
+
+  let credentials = {
+    id: "eyJleHBpcmVzIjogMTM2NTAxMDg5OC4x",
+    key: "qTZf4ZFpAMpMoeSsX3zVRjiqmNs=",
+    algorithm: "sha256",
+  };
+
+  function setLanguage(lang) {
+    let acceptLanguage = Cc["@mozilla.org/supports-string;1"].createInstance(Ci.nsISupportsString);
+    acceptLanguage.data = lang;
+    Services.prefs.setComplexValue("intl.accept_languages", Ci.nsISupportsString, acceptLanguage);
+  }
+
+  let server = httpd_setup({
+    "/foo": function(request, response) {
+      let lang = request.getHeader("Accept-Language");
+      do_check_eq(lang, languages[attempt]);
+
+      attempt += 1;
+
+      if (attempt > 2) {
+        response.setStatusLine(request.httpVersion, 429, "What are you doing");
+        return;
+      }
+
+      response.setStatusLine(request.httpVersion, 200, "OK");
+      return;
+    },
+  });
+
+  let url = server.baseURI + "/foo";
+  let postData = {};
+  let request;
+
+  setLanguage(languages[attempt], firstTest);
+  CommonUtils.nextTick(firstTest);
+
+  function firstTest() {
+    // Call once with initial language pref
+    request = new HAWKAuthenticatedRESTRequest(url, credentials);
+    request.post({}, function(error) {
+      do_check_null(error);
+      do_check_eq(200, this.response.status);
+      setLanguage(languages[attempt]);
+      CommonUtils.nextTick(secondTest);
+    });
+  }
+
+  function secondTest() {
+    // Change of language pref should be picked up
+    request = new HAWKAuthenticatedRESTRequest(url, credentials);
+    request.post({}, function(error) {
+      do_check_null(error);
+      do_check_eq(200, this.response.status);
+
+      Services.prefs.resetUserPrefs();
+
+      server.stop(run_next_test);
+    });
+  }
+});
+
--- a/services/common/tests/unit/test_restrequest.js
+++ b/services/common/tests/unit/test_restrequest.js
@@ -1,18 +1,18 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
+"use strict";
+
 Cu.import("resource://gre/modules/NetUtil.jsm");
 Cu.import("resource://gre/modules/Log.jsm");
 Cu.import("resource://services-common/rest.js");
 Cu.import("resource://services-common/utils.js");
 
-//DEBUG = true;
-
 function run_test() {
   Log.repository.getLogger("Services.Common.RESTRequest").level =
     Log.Level.Trace;
   initTestLogging("Trace");
 
   run_next_test();
 }
 
@@ -833,84 +833,8 @@ add_test(function test_not_sending_cooki
   res.get(function (error) {
     do_check_null(error);
     do_check_true(this.response.success);
     do_check_eq("COOKIE!", this.response.body);
     server.stop(run_next_test);
   });
 });
 
-add_test(function test_hawk_authenticated_request() {
-  do_test_pending();
-
-  let onProgressCalled = false;
-  let postData = {your: "data"};
-
-  // An arbitrary date - Feb 2, 1971.  It ends in a bunch of zeroes to make our
-  // computation with the hawk timestamp easier, since hawk throws away the
-  // millisecond values.
-  let then = 34329600000;
-
-  let clockSkew = 120000;
-  let timeOffset = -1 * clockSkew;
-  let localTime = then + clockSkew;
-
-  // Set the accept-languages pref to the Nepalese dialect of Zulu.
-  let acceptLanguage = Cc['@mozilla.org/supports-string;1'].createInstance(Ci.nsISupportsString);
-  acceptLanguage.data = 'zu-NP'; // omit trailing ';', which our HTTP libs snip
-  Services.prefs.setComplexValue('intl.accept_languages', Ci.nsISupportsString, acceptLanguage);
-
-  let credentials = {
-    id: "eyJleHBpcmVzIjogMTM2NTAxMDg5OC4x",
-    key: "qTZf4ZFpAMpMoeSsX3zVRjiqmNs=",
-    algorithm: "sha256"
-  };
-
-  let server = httpd_setup({
-    "/elysium": function(request, response) {
-      do_check_true(request.hasHeader("Authorization"));
-
-      // check that the header timestamp is our arbitrary system date, not
-      // today's date.  Note that hawk header timestamps are in seconds, not
-      // milliseconds.
-      let authorization = request.getHeader("Authorization");
-      let tsMS = parseInt(/ts="(\d+)"/.exec(authorization)[1], 10) * 1000;
-      do_check_eq(tsMS, then);
-
-      // This testing can be a little wonky. In an environment where
-      //   pref("intl.accept_languages") === 'en-US, en'
-      // the header is sent as:
-      //   'en-US,en;q=0.5'
-      // hence our fake value for acceptLanguage.
-      let lang = request.getHeader('Accept-Language');
-      do_check_eq(lang, acceptLanguage);
-
-      let message = "yay";
-      response.setStatusLine(request.httpVersion, 200, "OK");
-      response.bodyOutputStream.write(message, message.length);
-    }
-  });
-
-  function onProgress() {
-    onProgressCalled = true;
-  }
-
-  function onComplete(error) {
-    do_check_eq(200, this.response.status);
-    do_check_eq(this.response.body, "yay");
-    do_check_true(onProgressCalled);
-    do_test_finished();
-    server.stop(run_next_test);
-  }
-
-  let url = server.baseURI + "/elysium";
-  let extra = {
-    now: localTime,
-    localtimeOffsetMsec: timeOffset
-  };
-  let request = new HAWKAuthenticatedRESTRequest(url, credentials, extra);
-  request.post(postData, onComplete, onProgress);
-
-  Services.prefs.resetUserPrefs();
-  let pref = Services.prefs.getComplexValue('intl.accept_languages',
-                                            Ci.nsIPrefLocalizedString);
-  do_check_neq(acceptLanguage.data, pref.data);
-});
--- a/services/common/tests/unit/xpcshell.ini
+++ b/services/common/tests/unit/xpcshell.ini
@@ -20,17 +20,18 @@ firefox-appdir = browser
 [test_utils_stackTrace.js]
 [test_utils_utf8.js]
 [test_utils_uuid.js]
 
 [test_async_chain.js]
 [test_async_querySpinningly.js]
 [test_bagheera_server.js]
 [test_bagheera_client.js]
-[test_hawk.js]
+[test_hawkclient.js]
+[test_hawkrequest.js]
 [test_observers.js]
 [test_restrequest.js]
 [test_tokenauthenticatedrequest.js]
 
 # Storage service APIs
 [test_storageservice_bso.js]
 [test_storageservice_client.js]
 
--- a/services/fxaccounts/FxAccountsClient.jsm
+++ b/services/fxaccounts/FxAccountsClient.jsm
@@ -5,17 +5,17 @@
 this.EXPORTED_SYMBOLS = ["FxAccountsClient"];
 
 const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
 
 Cu.import("resource://gre/modules/Log.jsm");
 Cu.import("resource://gre/modules/Promise.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://services-common/utils.js");
-Cu.import("resource://services-common/hawk.js");
+Cu.import("resource://services-common/hawkclient.js");
 Cu.import("resource://services-crypto/utils.js");
 Cu.import("resource://gre/modules/FxAccountsCommon.js");
 Cu.import("resource://gre/modules/Credentials.jsm");
 
 let _host = "https://api.accounts.firefox.com/v1"
 try {
   _host = Services.prefs.getCharPref("identity.fxaccounts.auth.uri");
 } catch(keepDefault) {}
--- a/services/fxaccounts/tests/mochitest/test_invalidEmailCase.html
+++ b/services/fxaccounts/tests/mochitest/test_invalidEmailCase.html
@@ -24,17 +24,17 @@ https://bugzilla.mozilla.org/show_bug.cg
 <script class="testbody" type="text/javascript;version=1.8">
 
 SimpleTest.waitForExplicitFinish();
 
 Components.utils.import("resource://gre/modules/Promise.jsm");
 Components.utils.import("resource://gre/modules/Services.jsm");
 Components.utils.import("resource://gre/modules/FxAccounts.jsm");
 Components.utils.import("resource://gre/modules/FxAccountsClient.jsm");
-Components.utils.import("resource://services-common/hawk.js");
+Components.utils.import("resource://services-common/hawkclient.js");
 
 const TEST_SERVER =
   "http://mochi.test:8888/chrome/services/fxaccounts/tests/mochitest/file_invalidEmailCase.sjs?path=";
 
 let MockStorage = function() {
   this.data = null;
 };
 MockStorage.prototype = Object.freeze({
--- a/services/sync/tests/unit/test_browserid_identity.js
+++ b/services/sync/tests/unit/test_browserid_identity.js
@@ -3,17 +3,17 @@
 
 Cu.import("resource://gre/modules/FxAccounts.jsm");
 Cu.import("resource://services-sync/browserid_identity.js");
 Cu.import("resource://services-sync/rest.js");
 Cu.import("resource://services-sync/util.js");
 Cu.import("resource://services-common/utils.js");
 Cu.import("resource://services-crypto/utils.js");
 Cu.import("resource://testing-common/services/sync/utils.js");
-Cu.import("resource://services-common/hawk.js");
+Cu.import("resource://services-common/hawkclient.js");
 Cu.import("resource://gre/modules/FxAccounts.jsm");
 Cu.import("resource://gre/modules/FxAccountsClient.jsm");
 Cu.import("resource://gre/modules/FxAccountsCommon.js");
 
 const SECOND_MS = 1000;
 const MINUTE_MS = SECOND_MS * 60;
 const HOUR_MS = MINUTE_MS * 60;