Bug 1448553 - Part 4: Decodeds Punycode-encoded international domain names in the Storage Inspector so that they are displayed as human-readable Unicode text. r?miker draft
authorZhang Junzhi <zjz@zjz.name>
Mon, 02 Apr 2018 16:59:32 +0800
changeset 780908 381b0c274d435603d188090f6df4eea5996c327f
parent 780907 f99f741aee3b722cbe762eec5096a09d9242b0f3
child 780909 50da529445967d083eeafe952fbcc088ea9e86fb
push id106159
push userbmo:zjz@zjz.name
push dateThu, 12 Apr 2018 07:30:36 +0000
reviewersmiker
bugs1448553
milestone61.0a1
Bug 1448553 - Part 4: Decodeds Punycode-encoded international domain names in the Storage Inspector so that they are displayed as human-readable Unicode text. r?miker The Punycode-encoded international domain names are human-unreadable, so they should be displayed as human-readable Unicode text. This commit decodes this kind of names in the Storage Inspector. MozReview-Commit-ID: Agc03rliZ8q
devtools/client/storage/ui.js
--- a/devtools/client/storage/ui.js
+++ b/devtools/client/storage/ui.js
@@ -5,16 +5,17 @@
 
 "use strict";
 
 const EventEmitter = require("devtools/shared/event-emitter");
 const {LocalizationHelper, ELLIPSIS} = require("devtools/shared/l10n");
 const KeyShortcuts = require("devtools/client/shared/key-shortcuts");
 const JSOL = require("devtools/client/shared/vendor/jsol");
 const {KeyCodes} = require("devtools/client/shared/keycodes");
+const { getUnicodeHostname } = require("devtools/client/shared/unicode-url");
 
 // GUID to be used as a separator in compound keys. This must match the same
 // constant in devtools/server/actors/storage.js,
 // devtools/client/storage/test/head.js and
 // devtools/server/tests/browser/head.js
 const SEPARATOR_GUID = "{9d414cc5-8319-0a04-0586-c0a6ae01670a}";
 
 loader.lazyRequireGetter(this, "TreeWidget",
@@ -450,17 +451,18 @@ class StorageUI {
   /**
    * Handle added items received by onEdit
    *
    * @param {object} See onEdit docs
    */
   async handleAddedItems(added) {
     for (let type in added) {
       for (let host in added[type]) {
-        this.tree.add([type, {id: host, type: "url"}]);
+        const label = this.getReadableLabelFromHostname(host);
+        this.tree.add([type, {id: host, label: label, type: "url"}]);
         for (let name of added[type][host]) {
           try {
             name = JSON.parse(name);
             if (name.length == 3) {
               name.splice(2, 1);
             }
             this.tree.add([type, host, ...name]);
             if (!this.tree.selectedItem) {
@@ -667,17 +669,18 @@ class StorageUI {
         console.error("Unable to localize tree label type:" + type);
       }
       this.tree.add([{id: type, label: typeLabel, type: "store"}]);
       if (!storageTypes[type].hosts) {
         continue;
       }
       this.storageTypes[type] = storageTypes[type];
       for (let host in storageTypes[type].hosts) {
-        this.tree.add([type, {id: host, type: "url"}]);
+        const label = this.getReadableLabelFromHostname(host);
+        this.tree.add([type, {id: host, label: label, type: "url"}]);
         for (let name of storageTypes[type].hosts[host]) {
           try {
             let names = JSON.parse(name);
             this.tree.add([type, host, ...names]);
             if (!this.tree.selectedItem) {
               this.tree.selectedItem = [type, host, names[0], names[1]];
             }
           } catch (ex) {
@@ -768,23 +771,52 @@ class StorageUI {
         this.parseItemValue(key, item[key]);
       }
     }
 
     this.emit("sidebar-updated");
   }
 
   /**
+   * Gets a readable label from the hostname. If the hostname is a Punycode
+   * domain(I.e. an ASCII domain name representing a Unicode domain name), then
+   * this function decodes it to the readable Unicode domain name, and label
+   * the Unicode domain name toggether with the original domian name, and then
+   * return the label; if the hostname isn't a Punycode domain(I.e. it isn't
+   * encoded and is readable on its own), then this function simply returns the
+   * original hostname.
+   *
+   * @param {string} host
+   *        The string representing a host, e.g, example.com, example.com:8000
+   */
+  getReadableLabelFromHostname(host) {
+    try {
+      const { hostname } = new URL(host);
+      const unicodeHostname = getUnicodeHostname(hostname);
+      if (hostname !== unicodeHostname) {
+        // If the hostname is a Punycode domain representing a Unicode domain,
+        // we decode it to the Unicode domain name, and then label the Unicode
+        // domain name together with the original domain name.
+        return host.replace(hostname, unicodeHostname) + " [ " + host + " ]";
+      }
+    } catch (_) {
+      // Skip decoding for a host which doesn't include a domain name, simply
+      // consider them to be readable.
+    }
+    return host;
+  }
+
+  /**
    * Tries to parse a string value into either a json or a key-value separated
    * object and populates the sidebar with the parsed value. The value can also
    * be a key separated array.
    *
    * @param {string} name
    *        The key corresponding to the `value` string in the object
-   * @param {string} value
+   * @param {string} originalValue
    *        The string to be parsed into an object
    */
   parseItemValue(name, originalValue) {
     // Find if value is URLEncoded ie
     let decodedValue = "";
     try {
       decodedValue = decodeURIComponent(originalValue);
     } catch (e) {
@@ -876,18 +908,16 @@ class StorageUI {
     }
     return null;
   }
 
   /**
    * Select handler for the storage tree. Fetches details of the selected item
    * from the storage details and populates the storage tree.
    *
-   * @param {string} event
-   *        The name of the event fired
    * @param {array} item
    *        An array of ids which represent the location of the selected item in
    *        the storage tree
    */
   async onHostSelect(item) {
     this.table.clear();
     this.hideSidebar();
     this.searchBox.value = "";