Bug 1012532 - Replace translation engine usage of RESTRequest with Http.jsm. r=felipe
authorIaroslav Sheptykin <yarik.sheptykin@googlemail.com>
Tue, 24 Mar 2015 15:32:16 -0300
changeset 264354 603d839658dc555daca9f4e02a6fff6257eb473a
parent 264353 e36d122aeef8be95def8a17de6738686b9dfd159
child 264355 690cfd1cf8421dc4f395599c1834273e22527b46
push id4718
push userraliiev@mozilla.com
push dateMon, 11 May 2015 18:39:53 +0000
treeherdermozilla-beta@c20c4ef55f08 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfelipe
bugs1012532
milestone39.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 1012532 - Replace translation engine usage of RESTRequest with Http.jsm. r=felipe
browser/components/translation/BingTranslator.jsm
browser/components/translation/test/bing.sjs
--- a/browser/components/translation/BingTranslator.jsm
+++ b/browser/components/translation/BingTranslator.jsm
@@ -8,17 +8,17 @@ const {classes: Cc, interfaces: Ci, util
 
 this.EXPORTED_SYMBOLS = [ "BingTranslator" ];
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/Log.jsm");
 Cu.import("resource://gre/modules/Promise.jsm");
 Cu.import("resource://gre/modules/Task.jsm");
 Cu.import("resource://services-common/utils.js");
-Cu.import("resource://services-common/rest.js");
+Cu.import("resource://gre/modules/Http.jsm");
 
 // The maximum amount of net data allowed per request on Bing's API.
 const MAX_REQUEST_DATA = 5000; // Documentation says 10000 but anywhere
                                // close to that is refused by the service.
 
 // The maximum number of chunks allowed to be translated in a single
 // request.
 const MAX_REQUEST_CHUNKS = 1000; // Documentation says 2000.
@@ -124,23 +124,23 @@ this.BingTranslator.prototype = {
   /**
    * Function called when a request sent to the server has failed.
    * This function handles deciding if the error is transient or means the
    * service is unavailable (zero balance on the key or request credentials are
    * not in an active state) and calling the function to resolve the promise
    * returned by the public `translate()` method when there's no pending.
    * request left.
    *
-   * @param   aError   [optional] The RESTRequest that failed.
+   * @param   aError   [optional] The XHR object of the request that failed.
    */
   _chunkFailed: function(aError) {
-    if (aError instanceof RESTRequest &&
-        [400, 401].indexOf(aError.response.status) != -1) {
-      let body = aError.response.body;
-      if (body.contains("TranslateApiException") &&
+    if (aError instanceof Ci.nsIXMLHttpRequest &&
+        [400, 401].indexOf(aError.status) != -1) {
+      let body = aError.responseText;
+      if (body && body.contains("TranslateApiException") &&
           (body.contains("balance") || body.contains("active state")))
         this._serviceUnavailable = true;
     }
 
     this._checkIfFinished();
   },
 
   /**
@@ -173,23 +173,19 @@ this.BingTranslator.prototype = {
    * particular interest, the only part of the response that matters
    * are the <TranslatedText> nodes, which contains the resulting
    * items that were sent to be translated.
    *
    * @param   request      The request sent to the server.
    * @returns boolean      True if parsing of this chunk was successful.
    */
   _parseChunkResult: function(bingRequest) {
-    let domParser = Cc["@mozilla.org/xmlextras/domparser;1"]
-                      .createInstance(Ci.nsIDOMParser);
-
     let results;
     try {
-      let doc = domParser.parseFromString(bingRequest.networkRequest
-                                                     .response.body, "text/xml");
+      let doc = bingRequest.networkRequest.responseXML;
       results = doc.querySelectorAll("TranslatedText");
     } catch (e) {
       return false;
     }
 
     let len = results.length;
     if (len != bingRequest.translationData.length) {
       // This should never happen, but if the service returns a different number
@@ -286,25 +282,28 @@ function BingRequest(translationData, so
 }
 
 BingRequest.prototype = {
   /**
    * Initiates the request
    */
   fireRequest: function() {
     return Task.spawn(function *(){
+      // Prepare authentication.
       let token = yield BingTokenManager.getToken();
       let auth = "Bearer " + token;
+
+      // Prepare URL.
       let url = getUrlParam("https://api.microsofttranslator.com/v2/Http.svc/TranslateArray",
-                            "browser.translation.bing.translateArrayURL",
-                            false);
-      let request = new RESTRequest(url);
-      request.setHeader("Content-type", "text/xml");
-      request.setHeader("Authorization", auth);
+                            "browser.translation.bing.translateArrayURL");
 
+      // Prepare request headers.
+      let headers = [["Content-type", "text/xml"], ["Authorization", auth]];
+
+      // Prepare the request body.
       let requestString =
         '<TranslateArrayRequest>' +
           '<AppId/>' +
           '<From>' + this.sourceLanguage + '</From>' +
           '<Options>' +
             '<ContentType xmlns="http://schemas.datacontract.org/2004/07/Microsoft.MT.Web.Service.V2">text/html</ContentType>' +
             '<ReservedFlags xmlns="http://schemas.datacontract.org/2004/07/Microsoft.MT.Web.Service.V2" />' +
           '</Options>' +
@@ -314,26 +313,34 @@ BingRequest.prototype = {
         requestString += '<s:string>' + text + '</s:string>';
         this.characterCount += text.length;
       }
 
       requestString += '</Texts>' +
           '<To>' + this.targetLanguage + '</To>' +
         '</TranslateArrayRequest>';
 
-      let utf8 = CommonUtils.encodeUTF8(requestString);
-
+      // Set up request options.
       let deferred = Promise.defer();
-      request.post(utf8, function(err) {
-        if (request.error || !request.response.success)
-          deferred.reject(request);
+      let options = {
+        onLoad: (function(responseText, xhr) {
+          deferred.resolve(this);
+        }).bind(this),
+        onError: function(e, responseText, xhr) {
+          deferred.reject(xhr);
+        },
+        postData: requestString,
+        headers: headers
+      };
 
-        deferred.resolve(this);
-      }.bind(this));
+      // Fire the request.
+      let request = httpRequest(url, options);
 
+      // Override the response MIME type.
+      request.overrideMimeType("text/xml");
       this.networkRequest = request;
       return deferred.promise;
     }.bind(this));
   }
 };
 
 /**
  * Authentication Token manager for the API
@@ -368,55 +375,56 @@ let BingTokenManager = {
   /**
    * Generates a new token from the server.
    *
    * @returns {Promise}  A promise that resolves with the token
    *                     string once it is obtained.
    */
   _getNewToken: function() {
     let url = getUrlParam("https://datamarket.accesscontrol.windows.net/v2/OAuth2-13",
-                          "browser.translation.bing.authURL",
-                          false);
-    let request = new RESTRequest(url);
-    request.setHeader("Content-type", "application/x-www-form-urlencoded");
+                          "browser.translation.bing.authURL");
     let params = [
-      "grant_type=client_credentials",
-      "scope=" + encodeURIComponent("http://api.microsofttranslator.com"),
-      "client_id=" +
-      getUrlParam("%BING_API_CLIENTID%", "browser.translation.bing.clientIdOverride"),
-      "client_secret=" +
-      getUrlParam("%BING_API_KEY%", "browser.translation.bing.apiKeyOverride")
+      ["grant_type", "client_credentials"],
+      ["scope", "http://api.microsofttranslator.com"],
+      ["client_id",
+      getUrlParam("%BING_API_CLIENTID%", "browser.translation.bing.clientIdOverride")],
+      ["client_secret",
+      getUrlParam("%BING_API_KEY%", "browser.translation.bing.apiKeyOverride")]
     ];
 
     let deferred = Promise.defer();
-    this._pendingRequest = deferred.promise;
-    request.post(params.join("&"), function(err) {
-      BingTokenManager._pendingRequest = null;
+    let options = {
+      onLoad: function(responseText, xhr) {
+        BingTokenManager._pendingRequest = null;
+        try {
+          let json = JSON.parse(responseText);
 
-      if (err) {
-        deferred.reject(err);
-      }
-
-      try {
-        let json = JSON.parse(this.response.body);
+          if (json.error) {
+            deferred.reject(json.error);
+            return;
+          }
 
-        if (json.error) {
-          deferred.reject(json.error);
-          return;
+          let token = json.access_token;
+          let expires_in = json.expires_in;
+          BingTokenManager._currentToken = token;
+          BingTokenManager._currentExpiryTime = new Date(Date.now() + expires_in * 1000);
+          deferred.resolve(token);
+        } catch (e) {
+          deferred.reject(e);
         }
+      },
+      onError: function(e, responseText, xhr) {
+        BingTokenManager._pendingRequest = null;
+        deferred.reject(e);
+      },
+      postData: params
+    };
 
-        let token = json.access_token;
-        let expires_in = json.expires_in;
-        BingTokenManager._currentToken = token;
-        BingTokenManager._currentExpiryTime = new Date(Date.now() + expires_in * 1000);
-        deferred.resolve(token);
-      } catch (e) {
-        deferred.reject(e);
-      }
-    });
+    this._pendingRequest = deferred.promise;
+    let request = httpRequest(url, options);
 
     return deferred.promise;
   }
 };
 
 /**
  * Escape a string to be valid XML content.
  */
@@ -428,15 +436,14 @@ function escapeXML(aStr) {
              .replace(/</g, "&lt;")
              .replace(/>/g, "&gt;");
 }
 
 /**
  * Fetch an auth token (clientID or client secret), which may be overridden by
  * a pref if it's set.
  */
-function getUrlParam(paramValue, prefName, encode = true) {
+function getUrlParam(paramValue, prefName) {
   if (Services.prefs.getPrefType(prefName))
     paramValue = Services.prefs.getCharPref(prefName);
   paramValue = Services.urlFormatter.formatURL(paramValue);
-
-  return encode ? encodeURIComponent(paramValue) : paramValue;
+  return paramValue;
 }
--- a/browser/components/translation/test/bing.sjs
+++ b/browser/components/translation/test/bing.sjs
@@ -146,17 +146,17 @@ function reallyHandleRequest(req, res) {
 
   let body = getRequestBody(req);
   log("body: " + body);
 
   // First, we'll see if we're dealing with an XML body:
   let contentType = req.hasHeader("Content-Type") ? req.getHeader("Content-Type") : null;
   log("contentType: " + contentType);
 
-  if (contentType == "text/xml") {
+  if (contentType.startsWith("text/xml")) {
     try {
       // For all these requests the client needs to supply the correct
       // authentication headers.
       checkAuth(req);
 
       let xml = parseXml(body);
       let method = xml.documentElement.localName;
       log("invoking method: " + method);