Bug 869291 - 0001. Refactor existing WAP PUSH handlers. r=vicamo
authorChuck Lee <chulee@mozilla.com>
Mon, 22 Jul 2013 17:52:45 +0800
changeset 152266 7a4e174d7dbc7e3d7e5d4e320337f0aad2fe7f50
parent 152265 41845f57045f8f9773e208257ba57b43906b319f
child 152267 f31f09459b3f31e1d7293d44e1df8e5f6d7ad859
push id2859
push userakeybl@mozilla.com
push dateMon, 16 Sep 2013 19:14:59 +0000
treeherdermozilla-beta@87d3c51cd2bf [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersvicamo
bugs869291
milestone25.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 869291 - 0001. Refactor existing WAP PUSH handlers. r=vicamo
dom/wappush/src/gonk/SiPduHelper.jsm
dom/wappush/src/gonk/SlPduHelper.jsm
dom/wappush/src/gonk/WbxmlPduHelper.jsm
--- a/dom/wappush/src/gonk/SiPduHelper.jsm
+++ b/dom/wappush/src/gonk/SiPduHelper.jsm
@@ -60,92 +60,91 @@ this.OpaqueAsDate = {
   },
 };
 
 this.PduHelper = {
 
   /**
    * @param data
    *        A wrapped object containing raw PDU data.
-   * @param contentType [optional]
+   * @param contentType
    *        Content type of incoming SI message, should be "text/vnd.wap.si" or
    *        "application/vnd.wap.sic".
-   *        Default value is "application/vnd.wap.sic".
    *
-   * @return A SI message object or null in case of errors found.
+   * @return A message object containing attribute content and contentType.
+   *         |content| will contain string of decoded SI message if successfully
+   *         decoded, or raw data if failed.
+   *         |contentType| will be string representing corresponding type of
+   *         content.
    */
   parse: function parse_si(data, contentType) {
-    let msg = {};
+    // We only need content and contentType
+    let msg = {
+      contentType: contentType
+    };
 
     /**
      * Message is compressed by WBXML, decode into string.
      *
      * @see WAP-192-WBXML-20010725-A
      */
-    if (!contentType || contentType === "application/vnd.wap.sic") {
+    if (contentType === "application/vnd.wap.sic") {
       let globalTokenOverride = {};
       globalTokenOverride[0xC3] = {
         number: 0xC3,
         coder: OpaqueAsDate
       };
 
       let appToken = {
         publicId: PUBLIC_IDENTIFIER_SI,
-        tagToken: SI_TAG_FIELDS,
-        attrToken: SI_ATTRIBUTE_FIELDS,
+        tagTokenList: SI_TAG_FIELDS,
+        attrTokenList: SI_ATTRIBUTE_FIELDS,
+        valueTokenList: SI_VALUE_FIELDS,
         globalTokenOverride: globalTokenOverride
       }
 
-      WBXML.PduHelper.parse(data, appToken, msg);
-
-      msg.contentType = "text/vnd.wap.si";
+      try {
+        let parseResult = WBXML.PduHelper.parse(data, appToken);
+        msg.content = parseResult.content;
+        msg.contentType = "text/vnd.wap.si";
+      } catch (e) {
+        // Provide raw data if we failed to parse.
+        msg.content = data.array;
+      }
       return msg;
     }
 
     /**
      * Message is plain text, transform raw to string.
      */
-    if (contentType === "text/vnd.wap.si") {
+    try {
       let stringData = WSP.Octet.decodeMultiple(data, data.array.length);
-      msg.publicId = PUBLIC_IDENTIFIER_SI;
       msg.content = WSP.PduHelper.decodeStringContent(stringData, "UTF-8");
-      msg.contentType = "text/vnd.wap.si";
-      return msg;
+    } catch (e) {
+      // Provide raw data if we failed to parse.
+      msg.content = data.array;
     }
-
-    return null;
-  },
+    return msg;
 
-  /**
-   * @param multiStream
-   *        An exsiting nsIMultiplexInputStream.
-   * @param msg
-   *        A SI message object.
-   *
-   * @return An instance of nsIMultiplexInputStream or null in case of errors.
-   */
-  compose: function compose_si(multiStream, msg) {
-    // Composing SI message is not supported
-    return null;
-  },
+  }
 };
 
 /**
  * Tag tokens
  *
  * @see WAP-167-SERVICEIND-20010731-A, clause 8.3.1
  */
 const SI_TAG_FIELDS = (function () {
   let names = {};
   function add(name, number) {
     let entry = {
       name: name,
       number: number,
     };
-    names[name] = names[number] = entry;
+    names[number] = entry;
   }
 
   add("si",           0x05);
   add("indication",   0x06);
   add("info",         0x07);
   add("item",         0x08);
 
   return names;
@@ -159,37 +158,51 @@ const SI_TAG_FIELDS = (function () {
 const SI_ATTRIBUTE_FIELDS = (function () {
   let names = {};
   function add(name, value, number) {
     let entry = {
       name: name,
       value: value,
       number: number,
     };
-    names[name] = names[number] = entry;
+    names[number] = entry;
   }
 
   add("action",       "signal-none",    0x05);
   add("action",       "signal-low",     0x06);
   add("action",       "signal-medium",  0x07);
   add("action",       "signal-high",    0x08);
   add("action",       "delete",         0x09);
   add("created",      "",               0x0A);
   add("href",         "",               0x0B);
   add("href",         "http://",        0x0C);
   add("href",         "http://www.",    0x0D);
   add("href",         "https://",       0x0E);
   add("href",         "https://www.",   0x0F);
   add("si-expires",   "",               0x10);
   add("si-id",        "",               0x11);
   add("class",        "",               0x12);
-  add("",             ".com/",          0x85);
-  add("",             ".edu/",          0x86);
-  add("",             ".net/",          0x87);
-  add("",             ".org/",          0x88);
+
+  return names;
+})();
+
+const SI_VALUE_FIELDS = (function () {
+  let names = {};
+  function add(value, number) {
+    let entry = {
+      value: value,
+      number: number,
+    };
+    names[number] = entry;
+  }
+
+  add(".com/",          0x85);
+  add(".edu/",          0x86);
+  add(".net/",          0x87);
+  add(".org/",          0x88);
 
   return names;
 })();
 
 this.EXPORTED_SYMBOLS = [
   // Parser
   "PduHelper",
 ];
--- a/dom/wappush/src/gonk/SlPduHelper.jsm
+++ b/dom/wappush/src/gonk/SlPduHelper.jsm
@@ -21,86 +21,86 @@ let DEBUG = WBXML.DEBUG_ALL | false;
  */
 const PUBLIC_IDENTIFIER_SL    = "-//WAPFORUM//DTD SL 1.0//EN";
 
 this.PduHelper = {
 
   /**
    * @param data
    *        A wrapped object containing raw PDU data.
-   * @param contentType [optional]
+   * @param contentType
    *        Content type of incoming SL message, should be "text/vnd.wap.sl" or
    *        "application/vnd.wap.slc".
-   *        Default value is "application/vnd.wap.slc".
    *
-   * @return A SL message object or null in case of errors found.
+   * @return A message object containing attribute content and contentType.
+   *         |content| will contain string of decoded SL message if successfully
+   *         decoded, or raw data if failed.
+   *         |contentType| will be string representing corresponding type of
+   *         content.
    */
   parse: function parse_sl(data, contentType) {
-    let msg = {};
+    // We only need content and contentType
+    let msg = {
+      contentType: contentType
+    };
 
     /**
      * Message is compressed by WBXML, decode into string.
      *
      * @see WAP-192-WBXML-20010725-A
      */
-    if (!contentType || contentType === "application/vnd.wap.slc") {
+    if (contentType === "application/vnd.wap.slc") {
       let appToken = {
         publicId: PUBLIC_IDENTIFIER_SL,
-        tagToken: SL_TAG_FIELDS,
-        attrToken: SL_ATTRIBUTE_FIELDS,
+        tagTokenList: SL_TAG_FIELDS,
+        attrTokenList: SL_ATTRIBUTE_FIELDS,
+        valueTokenList: SL_VALUE_FIELDS,
         globalTokenOverride: null
       }
 
-      WBXML.PduHelper.parse(data, appToken, msg);
+      try {
+        let parseResult = WBXML.PduHelper.parse(data, appToken);
+        msg.content = parseResult.content;
+        msg.contentType = "text/vnd.wap.sl";
+      } catch (e) {
+        // Provide raw data if we failed to parse.
+        msg.content = data.array;
+      }
 
-      msg.contentType = "text/vnd.wap.sl";
       return msg;
     }
 
     /**
      * Message is plain text, transform raw to string.
      */
-    if (contentType === "text/vnd.wap.sl") {
+    try {
       let stringData = WSP.Octet.decodeMultiple(data, data.array.length);
-      msg.publicId = PUBLIC_IDENTIFIER_SL;
       msg.content = WSP.PduHelper.decodeStringContent(stringData, "UTF-8");
-      msg.contentType = "text/vnd.wap.sl";
-      return msg;
+    } catch (e) {
+      // Provide raw data if we failed to parse.
+      msg.content = data.array;
     }
-
-    return null;
-  },
+    return msg;
 
-  /**
-   * @param multiStream
-   *        An exsiting nsIMultiplexInputStream.
-   * @param msg
-   *        A SL message object.
-   *
-   * @return An instance of nsIMultiplexInputStream or null in case of errors.
-   */
-  compose: function compose_sl(multiStream, msg) {
-    // Composing SL message is not supported
-    return null;
-  },
+  }
 };
 
 /**
  * Tag tokens
  *
  * @see WAP-168-SERVICELOAD-20010731-A, clause 9.3.1
  */
 const SL_TAG_FIELDS = (function () {
   let names = {};
   function add(name, number) {
     let entry = {
       name: name,
       number: number,
     };
-    names[name] = names[number] = entry;
+    names[number] = entry;
   }
 
   add("sl",           0x05);
 
   return names;
 })();
 
 /**
@@ -111,31 +111,45 @@ const SL_TAG_FIELDS = (function () {
 const SL_ATTRIBUTE_FIELDS = (function () {
   let names = {};
   function add(name, value, number) {
     let entry = {
       name: name,
       value: value,
       number: number,
     };
-    names[name] = names[number] = entry;
+    names[number] = entry;
   }
 
   add("action",       "execute-low",    0x05);
   add("action",       "execute-high",   0x06);
   add("action",       "cache",          0x07);
   add("href",         "",               0x08);
   add("href",         "http://",        0x09);
   add("href",         "http://www.",    0x0A);
   add("href",         "https://",       0x0B);
   add("href",         "https://www.",   0x0C);
-  add("",             ".com/",          0x85);
-  add("",             ".edu/",          0x86);
-  add("",             ".net/",          0x87);
-  add("",             ".org/",          0x88);
+
+  return names;
+})();
+
+const SL_VALUE_FIELDS = (function () {
+  let names = {};
+  function add(value, number) {
+    let entry = {
+      value: value,
+      number: number,
+    };
+    names[number] = entry;
+  }
+
+  add(".com/",          0x85);
+  add(".edu/",          0x86);
+  add(".net/",          0x87);
+  add(".org/",          0x88);
 
   return names;
 })();
 
 this.EXPORTED_SYMBOLS = [
   // Parser
   "PduHelper",
 ];
--- a/dom/wappush/src/gonk/WbxmlPduHelper.jsm
+++ b/dom/wappush/src/gonk/WbxmlPduHelper.jsm
@@ -120,105 +120,115 @@ this.WbxmlOpaque = {
 
 this.PduHelper = {
 
   /**
    * Parse WBXML encoded message into plain text.
    *
    * @param data
    *        A wrapped object containing raw PDU data.
-   * @param msg
-   *        Target object for decoding.
+   * @param decodeInfo
+   *        Information for decoding, now requires charset and string table.
    * @param appToken
    *        Application-specific token difinition.
    *
    * @return Decoded WBXML message string.
    */
-  parseWbxml: function parseWbxml_wbxml(data, msg, appToken) {
+  parseWbxml: function parseWbxml_wbxml(data, decodeInfo, appToken) {
 
     // Parse token definition to my structure.
-    let tagTokenList = appToken.tagToken;
-    let attrTokenList = appToken.attrToken;
-    let globalTokenOverrideList = appToken.globalTokenOverride || {};
+    let tagTokenList = appToken.tagTokenList;
+    let attrTokenList = appToken.attrTokenList;
+    let valueTokenList = appToken.valueTokenList;
+
+    decodeInfo.tagStack = [];    // tag decode stack
 
-    let decodeInfo = {
-      tagStack: [],                                                 // tag decode stack
-      charset: WSP.WSP_WELL_KNOWN_CHARSETS[msg.charset].converter,  // document character set
-      stringTable: msg.stringTable                                  // document string table
-    };
+    // Merge global tag tokens into single list, so we don't have
+    // to search two lists every time.
+    let globalTagTokenList = Object.create(WBXML_GLOBAL_TOKENS);
+    if (appToken.globalTokenOverride) {
+      let globalTokenOverrideList = appToken.globalTokenOverride;
+      for (let token in globalTokenOverrideList) {
+        globalTagTokenList[token] = globalTokenOverrideList[token];
+      }
+    }
 
-    msg.content = "";
+    let content = "";
     while (data.offset < data.array.length) {
       // Decode content, might be a new tag token, an end of tag token, or an
       // inline string.
 
       let tagToken = WSP.Octet.decode(data);
       let tagTokenValue = tagToken & TAG_TOKEN_VALUE_MASK;
 
       // Try global tag first, tagToken of string table is 0x83, and will be 0x03
       // in tagTokenValue, which is collision with inline string.
       // So tagToken need to be searched before tagTokenValue.
-      let tagInfo = globalTokenOverrideList[tagToken] ||
-                    globalTokenOverrideList[tagTokenValue] ||
-                    WBXML_GLOBAL_TOKENS[tagToken] ||
-                    WBXML_GLOBAL_TOKENS[tagTokenValue];
+      let tagInfo = globalTagTokenList[tagToken] ||
+                    globalTagTokenList[tagTokenValue];
       if (tagInfo) {
-        msg.content += tagInfo.coder.decode(data, decodeInfo);
+        content += tagInfo.coder.decode(data, decodeInfo);
         continue;
       }
 
       // Check if application tag token is valid
       tagInfo = tagTokenList[tagTokenValue];
-      if (!tagInfo)
-        continue;
+      if (!tagInfo) {
+        throw new Error("Unsupported WBXML token: " + tagTokenValue + ".");
+      }
 
-      msg.content += "<" + tagInfo.name;
+      content += "<" + tagInfo.name;
 
       if (tagToken & TAG_TOKEN_ATTR_MASK) {
         // Decode attributes, might be a new attribute token, a value token,
         // or an inline string
 
         let attrSeperator = "";
         while (data.offset < data.array.length) {
           let attrToken = WSP.Octet.decode(data);
           if (attrToken === TAG_END_TOKEN) {
             break;
           }
 
-          let attrInfo = globalTokenOverrideList[attrToken] ||
-                         WBXML_GLOBAL_TOKENS[attrToken];
+          let attrInfo = globalTagTokenList[attrToken];
           if (attrInfo) {
-            msg.content += attrInfo.coder.decode(data, decodeInfo);
+            content += attrInfo.coder.decode(data, decodeInfo);
             continue;
           }
 
           // Check if attribute token is valid
           attrInfo = attrTokenList[attrToken];
-          if (!attrInfo)
+          if (attrInfo) {
+            content += attrSeperator + " " + attrInfo.name + "=\"" + attrInfo.value;
+            attrSeperator = "\"";
             continue;
+          }
 
-          if (attrInfo.name !== "") {
-            msg.content += attrSeperator + " " + attrInfo.name + "=\"" + attrInfo.value;
-            attrSeperator = "\"";
-          } else {
-            msg.content += attrInfo.value;
+          attrInfo = valueTokenList[attrToken];
+          if (attrInfo) {
+            content += attrInfo.value;
+            continue;
           }
+
+          throw new Error("Unsupported WBXML token: " + attrToken + ".");
         }
 
-        msg.content += attrSeperator;
+        content += attrSeperator;
       }
 
       if (tagToken & TAG_TOKEN_CONTENT_MASK) {
-        msg.content += ">";
+        content += ">";
         decodeInfo.tagStack.push(tagInfo);
         continue;
       }
 
-      msg.content += "/>";
+      content += "/>";
     }
+
+    return content;
   },
 
   /**
    * @param data
    *        A wrapped object containing raw PDU data.
    * @param appToken
    *        contains application-specific token info, including
    *        {
@@ -243,25 +253,21 @@ this.PduHelper = {
    *                                  Object[GLOBAL_TOKEN_NUMBER] =
    *                                  {
    *                                    decode: function(data),
    *                                    encode: function(data)
    *                                  }
    *                                  decode() returns decoded text, encode() returns
    *                                  encoded raw data.
    *        }
-   * @param msg [optional]
-   *        Optional target object for decoding.
    *
    * @return A WBXML message object or null in case of errors found.
    */
-  parse: function parse_wbxml(data, appToken, msg) {
-    if (!msg) {
-      msg = {};
-    }
+  parse: function parse_wbxml(data, appToken) {
+    let msg = {};
 
     /**
      * Read WBXML header.
      *
      * @see WAP-192-WBXML-20010725-A, Clause 5.3
      */
     let headerRaw = {};
     headerRaw.version = WSP.Octet.decode(data);
@@ -284,38 +290,29 @@ this.PduHelper = {
 
     if (headerRaw.publicId !== 0) {
       msg.publicId = WBXML_PUBLIC_ID[headerRaw.publicId];
     } else {
       msg.publicId = readStringTable(headerRaw.publicIdStr, msg.stringTable,
                                      WSP.WSP_WELL_KNOWN_CHARSETS[msg.charset].converter);
     }
     if (msg.publicId != appToken.publicId) {
-      return null;
+      throw new Error("Public ID does not match.");
     }
 
     msg.version = ((headerRaw.version >> 4) + 1) + "." + (headerRaw.version & 0x0F);
 
-    this.parseWbxml(data, msg, appToken);
+    let decodeInfo = {
+      charset: WSP.WSP_WELL_KNOWN_CHARSETS[msg.charset].converter,  // document character set
+      stringTable: msg.stringTable                                  // document string table
+    };
+    msg.content = this.parseWbxml(data, decodeInfo, appToken);
 
     return msg;
-  },
-
-  /**
-   * @param multiStream
-   *        An exsiting nsIMultiplexInputStream.
-   * @param msg
-   *        A SI message object.
-   *
-   * @return An instance of nsIMultiplexInputStream or null in case of errors.
-   */
-  compose: function compose_wbxml(multiStream, msg) {
-    // Composing WBXML message is not supported
-    return null;
-  },
+  }
 };
 
 /**
  * Global Tokens
  *
  * @see WAP-192-WBXML-20010725-A, clause 7.1
  */
 const WBXML_GLOBAL_TOKENS = (function () {