Bug 1502097 - (Part 1) Move pref network.IDN.blacklist_chars to separate hardcoded file IDNCharacterBlocklist.inc r=jfkthame,dragana
authorValentin Gosu <valentin.gosu@gmail.com>
Fri, 23 Nov 2018 22:40:29 +0000
changeset 504402 ed995224a05aa692d3fc09b9ec82351894672c73
parent 504401 703630d3fc2757d5aaa94ab706a5faf826b0b1c3
child 504403 6040483f1f0aa53d3049ce30209328eb0e2c27f2
push id10290
push userffxbld-merge
push dateMon, 03 Dec 2018 16:23:23 +0000
treeherdermozilla-beta@700bed2445e6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjfkthame, dragana
bugs1502097
milestone65.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 1502097 - (Part 1) Move pref network.IDN.blacklist_chars to separate hardcoded file IDNCharacterBlocklist.inc r=jfkthame,dragana * Moves the value of the pref and also the fallback definition in nsTextToSubURI.cpp to a separate file. * The file has better formatting, so we may follow its history more easily. Each range of consecutive values is defined on a separate line. * Renames `blacklist` to `blocklist` for pref and variable names (for this individual pref. network.IDN.whitelist.* needs to be handled in a separate bug) * Changes nsIDNService::mIDNBlocklist from being an nsString to sorted nsTArray<char16> and uses mozilla::BinarySearch() to check for characters. Differential Revision: https://phabricator.services.mozilla.com/D12209
intl/uconv/nsITextToSubURI.idl
intl/uconv/nsTextToSubURI.cpp
intl/uconv/nsTextToSubURI.h
modules/libpref/init/all.js
netwerk/dns/IDNCharacterBlocklist.inc
netwerk/dns/nsIDNService.cpp
netwerk/dns/nsIDNService.h
netwerk/test/unit/test_bug464591.js
netwerk/test/unit/test_idnservice.js
--- a/intl/uconv/nsITextToSubURI.idl
+++ b/intl/uconv/nsITextToSubURI.idl
@@ -22,17 +22,17 @@ interface nsITextToSubURI : nsISupports
    * Unescapes the given URI fragment (for UI purpose only)
    * Note:
    * <ul>
    *  <li> escaping back the result (unescaped string) is not guaranteed to
    *       give the original escaped string
    *  <li> In case of a conversion error, the URI fragment (escaped) is
    *       assumed to be in UTF-8 and converted to AString (UTF-16)
    *  <li> In case of successful conversion any resulting character listed
-   *       in network.IDN.blacklist_chars (except space) is escaped
+   *       in netwerk/dns/IDNCharacterBlocklist.inc (except space) is escaped
    *  <li> Always succeeeds (callers don't need to do error checking)
    * </ul>
    *
    * @param aCharset the charset to convert from
    * @param aURIFragment the URI (or URI fragment) to unescape
    * @return Unescaped aURIFragment  converted to unicode
    */
   AString unEscapeURIForUI(in ACString aCharset, in AUTF8String aURIFragment);
--- a/intl/uconv/nsTextToSubURI.cpp
+++ b/intl/uconv/nsTextToSubURI.cpp
@@ -9,39 +9,18 @@
 #include "nsCRT.h"
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/Encoding.h"
 #include "mozilla/Preferences.h"
 #include "nsISupportsPrimitives.h"
 
 using namespace mozilla;
 
-// Fallback value for the pref "network.IDN.blacklist_chars".
-// UnEscapeURIForUI allows unescaped space; other than that, this is
-// the same as the default "network.IDN.blacklist_chars" value.
-static const char16_t sNetworkIDNBlacklistChars[] =
-{
-  // clang-format off
-/*0x0020,*/
-          0x00A0, 0x00BC, 0x00BD, 0x00BE, 0x01C3, 0x02D0, 0x0337,
-  0x0338, 0x0589, 0x058A, 0x05C3, 0x05F4, 0x0609, 0x060A, 0x066A, 0x06D4,
-  0x0701, 0x0702, 0x0703, 0x0704, 0x115F, 0x1160, 0x1735, 0x2000,
-  0x2001, 0x2002, 0x2003, 0x2004, 0x2005, 0x2006, 0x2007, 0x2008,
-  0x2009, 0x200A, 0x200B, 0x200E, 0x200F, 0x2010, 0x2019, 0x2024, 0x2027, 0x2028,
-  0x2029, 0x202A, 0x202B, 0x202C, 0x202D, 0x202E, 0x202F, 0x2039,
-  0x203A, 0x2041, 0x2044, 0x2052, 0x205F, 0x2153, 0x2154, 0x2155,
-  0x2156, 0x2157, 0x2158, 0x2159, 0x215A, 0x215B, 0x215C, 0x215D,
-  0x215E, 0x215F, 0x2215, 0x2236, 0x23AE, 0x2571, 0x29F6, 0x29F8,
-  0x2AFB, 0x2AFD, 0x2FF0, 0x2FF1, 0x2FF2, 0x2FF3, 0x2FF4, 0x2FF5,
-  0x2FF6, 0x2FF7, 0x2FF8, 0x2FF9, 0x2FFA, 0x2FFB, /*0x3000,*/ 0x3002,
-  0x3014, 0x3015, 0x3033, 0x30A0, 0x3164, 0x321D, 0x321E, 0x33AE, 0x33AF,
-  0x33C6, 0x33DF, 0xA789, 0xFE14, 0xFE15, 0xFE3F, 0xFE5D, 0xFE5E,
-  0xFEFF, 0xFF0E, 0xFF0F, 0xFF61, 0xFFA0, 0xFFF9, 0xFFFA, 0xFFFB,
-  0xFFFC, 0xFFFD
-  // clang-format on
+static const char16_t sNetworkIDNBlocklistChars[] = {
+#include "../../netwerk/dns/IDNCharacterBlocklist.inc"
 };
 
 nsTextToSubURI::~nsTextToSubURI()
 {
 }
 
 NS_IMPL_ISUPPORTS(nsTextToSubURI, nsITextToSubURI)
 
@@ -133,16 +112,17 @@ nsTextToSubURI::convertURItoUnicode(cons
   }
   return encoding->DecodeWithoutBOMHandlingAndWithoutReplacement(aURI, aOut);
 }
 
 NS_IMETHODIMP  nsTextToSubURI::UnEscapeURIForUI(const nsACString & aCharset,
                                                 const nsACString &aURIFragment,
                                                 nsAString &_retval)
 {
+  nsresult rv;
   nsAutoCString unescapedSpec;
   // skip control octets (0x00 - 0x1f and 0x7f) when unescaping
   NS_UnescapeURL(PromiseFlatCString(aURIFragment),
                  esc_SkipControl | esc_AlwaysCopy, unescapedSpec);
 
   // in case of failure, return escaped URI
   // Test for != NS_OK rather than NS_FAILED, because incomplete multi-byte
   // sequences are also considered failure in this context
@@ -150,34 +130,38 @@ NS_IMETHODIMP  nsTextToSubURI::UnEscapeU
                 PromiseFlatCString(aCharset), unescapedSpec, _retval)
       != NS_OK) {
     // assume UTF-8 instead of ASCII  because hostname (IDN) may be in UTF-8
     CopyUTF8toUTF16(aURIFragment, _retval);
   }
 
   // If there are any characters that are unsafe for URIs, reescape those.
   if (mUnsafeChars.IsEmpty()) {
-    nsAutoString blacklist;
-    nsresult rv = mozilla::Preferences::GetString("network.IDN.blacklist_chars",
-                                                  blacklist);
-    if (NS_SUCCEEDED(rv)) {
-      // we allow SPACE and IDEOGRAPHIC SPACE in this method
-      blacklist.StripChars(u" \u3000");
-      mUnsafeChars.AppendElements(static_cast<const char16_t*>(blacklist.Data()),
-                                  blacklist.Length());
-    } else {
-      NS_WARNING("Failed to get the 'network.IDN.blacklist_chars' preference");
+    mUnsafeChars.AppendElements(
+      sNetworkIDNBlocklistChars, ArrayLength(sNetworkIDNBlocklistChars));
+
+    nsAutoString extraAllowed;
+    Preferences::GetString("network.IDN.extra_allowed_chars",
+                           extraAllowed);
+    // we allow SPACE and IDEOGRAPHIC SPACE in this method
+    extraAllowed.Append(u' ');
+    extraAllowed.Append(0x3000);
+    mUnsafeChars.RemoveElementsBy([&](char16_t c) {
+      return extraAllowed.FindChar(c, 0) != -1;
+    });
+
+    nsAutoString extraBlocked;
+    rv = Preferences::GetString("network.IDN.extra_blocked_chars",
+                                extraBlocked);
+    if (NS_SUCCEEDED(rv) && !extraBlocked.IsEmpty()) {
+      mUnsafeChars.AppendElements(
+        static_cast<const char16_t*>(extraBlocked.Data()),
+        extraBlocked.Length());
+      mUnsafeChars.Sort();
     }
-    // We check IsEmpty() intentionally here because an empty (or just spaces)
-    // pref value is likely a mistake/error of some sort.
-    if (mUnsafeChars.IsEmpty()) {
-      mUnsafeChars.AppendElements(sNetworkIDNBlacklistChars,
-                                  mozilla::ArrayLength(sNetworkIDNBlacklistChars));
-    }
-    mUnsafeChars.Sort();
   }
   const nsPromiseFlatString& unescapedResult = PromiseFlatString(_retval);
   nsString reescapedSpec;
   _retval = NS_EscapeURL(unescapedResult, mUnsafeChars, reescapedSpec);
 
   return NS_OK;
 }
 
--- a/intl/uconv/nsTextToSubURI.h
+++ b/intl/uconv/nsTextToSubURI.h
@@ -18,14 +18,14 @@ class nsTextToSubURI: public nsITextToSu
 private:
   virtual ~nsTextToSubURI();
 
   // We assume that the URI is encoded as UTF-8.
   nsresult convertURItoUnicode(const nsCString& aCharset,
                                const nsCString& aURI,
                                nsAString &_retval);
 
-  // Characters from the pref "network.IDN.blacklist_chars", or a built-in
-  // fallback if reading the pref fails.
+  // Characters defined in netwerk/dns/IDNCharacterBlocklist.inc or via the
+  // network.IDN.extra_allowed_chars and network.IDN.extra_blocked_chars prefs.
   nsTArray<char16_t> mUnsafeChars;
 };
 
 #endif // nsTextToSubURI_h__
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -2128,22 +2128,31 @@ pref("network.IDN.whitelist.xn--9t4b11yi
 pref("network.IDN.whitelist.xn--deba0ad", true);
 pref("network.IDN.whitelist.xn--g6w251d", true);
 pref("network.IDN.whitelist.xn--hgbk6aj7f53bba", true);
 pref("network.IDN.whitelist.xn--hlcj6aya9esc7a", true);
 pref("network.IDN.whitelist.xn--jxalpdlp", true);
 pref("network.IDN.whitelist.xn--kgbechtv", true);
 pref("network.IDN.whitelist.xn--zckzah", true);
 
-// If a domain includes any of the following characters, it may be a spoof
+// If a domain includes any of the blocklist characters, it may be a spoof
 // attempt and so we always display the domain name as punycode. This would
 // override the settings "network.IDN_show_punycode" and
-// "network.IDN.whitelist.*".  (please keep this value in sync with the
-// built-in fallback in intl/uconv/nsTextToSubURI.cpp)
-pref("network.IDN.blacklist_chars", "\u0020\u00A0\u00BC\u00BD\u00BE\u01C3\u02D0\u0337\u0338\u0589\u058A\u05C3\u05F4\u0609\u060A\u066A\u06D4\u0701\u0702\u0703\u0704\u115F\u1160\u1735\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u200B\u200E\u200F\u2010\u2019\u2024\u2027\u2028\u2029\u202A\u202B\u202C\u202D\u202E\u202F\u2039\u203A\u2041\u2044\u2052\u205F\u2153\u2154\u2155\u2156\u2157\u2158\u2159\u215A\u215B\u215C\u215D\u215E\u215F\u2215\u2236\u23AE\u2571\u29F6\u29F8\u2AFB\u2AFD\u2FF0\u2FF1\u2FF2\u2FF3\u2FF4\u2FF5\u2FF6\u2FF7\u2FF8\u2FF9\u2FFA\u2FFB\u3000\u3002\u3014\u3015\u3033\u30A0\u3164\u321D\u321E\u33AE\u33AF\u33C6\u33DF\uA789\uFE14\uFE15\uFE3F\uFE5D\uFE5E\uFEFF\uFF0E\uFF0F\uFF61\uFFA0\uFFF9\uFFFA\uFFFB\uFFFC\uFFFD");
+// "network.IDN.whitelist.*".
+// For a complete list of the blocked IDN characters see:
+//   netwerk/dns/IDNCharacterBlocklist.inc
+
+// This pref may contain characters that will override the hardcoded blocklist,
+// so their presence in a domain name will not cause it to be displayed as
+// punycode.
+// Note that this only removes the characters from the blocklist, but there may
+// be other rules in place that cause it to be displayed as punycode.
+pref("network.IDN.extra_allowed_chars", "");
+// This pref may contain additional blocklist characters
+pref("network.IDN.extra_blocked_chars", "");
 
 // This preference specifies a list of domains for which DNS lookups will be
 // IPv4 only. Works around broken DNS servers which can't handle IPv6 lookups
 // and/or allows the user to disable IPv6 on a per-domain basis. See bug 68796.
 pref("network.dns.ipv4OnlyDomains", "");
 
 // This preference can be used to turn off IPv6 name lookups. See bug 68796.
 pref("network.dns.disableIPv6", false);
new file mode 100644
--- /dev/null
+++ b/netwerk/dns/IDNCharacterBlocklist.inc
@@ -0,0 +1,55 @@
+// ASCII Space
+0x0020,
+0x00A0,
+0x00BC, 0x00BD, 0x00BE,
+0x01C3,
+0x02D0,
+0x0337, 0x0338,
+0x0589, 0x058A,
+0x05C3,
+0x05F4,
+0x0609, 0x060A,
+0x066A,
+0x06D4,
+0x0701, 0x0702, 0x0703, 0x0704,
+0x115F, 0x1160,
+0x1735,
+0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, 0x2006, 0x2007, 0x2008, 0x2009, 0x200A, 0x200B,
+0x200E, 0x200F, 0x2010,
+0x2019,
+0x2024,
+0x2027, 0x2028, 0x2029, 0x202A, 0x202B, 0x202C, 0x202D, 0x202E, 0x202F,
+0x2039, 0x203A,
+0x2041,
+0x2044,
+0x2052,
+0x205F,
+0x2153, 0x2154, 0x2155, 0x2156, 0x2157, 0x2158, 0x2159, 0x215A, 0x215B, 0x215C, 0x215D, 0x215E, 0x215F,
+0x2215,
+0x2236,
+0x23AE,
+0x2571,
+0x29F6,
+0x29F8,
+0x2AFB,
+0x2AFD,
+0x2FF0, 0x2FF1, 0x2FF2, 0x2FF3, 0x2FF4, 0x2FF5, 0x2FF6, 0x2FF7, 0x2FF8, 0x2FF9, 0x2FFA, 0x2FFB,
+// Ideographic Space
+0x3000,
+0x3002,
+0x3014, 0x3015,
+0x3033,
+0x30A0,
+0x3164,
+0x321D, 0x321E,
+0x33AE, 0x33AF,
+0x33C6,
+0x33DF,
+0xFE14, 0xFE15,
+0xFE3F,
+0xFE5D, 0xFE5E,
+0xFEFF,
+0xFF0E, 0xFF0F,
+0xFF61,
+0xFFA0,
+0xFFF9, 0xFFFA, 0xFFFB, 0xFFFC, 0xFFFD
--- a/netwerk/dns/nsIDNService.cpp
+++ b/netwerk/dns/nsIDNService.cpp
@@ -21,51 +21,70 @@
 // To switch to transitional processing, change the value of this flag
 // and kTransitionalProcessing in netwerk/test/unit/test_idna2008.js to true
 // (revert bug 1218179).
 const bool kIDNA2008_TransitionalProcessing = false;
 
 #include "ICUUtils.h"
 #include "unicode/uscript.h"
 
+static const char16_t sBlocklistChars[] = {
+#include "IDNCharacterBlocklist.inc"
+};
+
 using namespace mozilla::unicode;
 using mozilla::Preferences;
 
 //-----------------------------------------------------------------------------
 // RFC 1034 - 3.1. Name space specifications and terminology
 static const uint32_t kMaxDNSNodeLen = 63;
 // RFC 3490 - 5.   ACE prefix
 static const char kACEPrefix[] = "xn--";
 #define kACEPrefixLen 4
 
 //-----------------------------------------------------------------------------
 
-#define NS_NET_PREF_IDNBLACKLIST    "network.IDN.blacklist_chars"
+#define NS_NET_PREF_EXTRAALLOWED "network.IDN.extra_allowed_chars"
+#define NS_NET_PREF_EXTRABLOCKED "network.IDN.extra_blocked_chars"
 #define NS_NET_PREF_SHOWPUNYCODE    "network.IDN_show_punycode"
 #define NS_NET_PREF_IDNWHITELIST    "network.IDN.whitelist."
 #define NS_NET_PREF_IDNUSEWHITELIST "network.IDN.use_whitelist"
 #define NS_NET_PREF_IDNRESTRICTION  "network.IDN.restriction_profile"
 
-inline bool isOnlySafeChars(const nsString& in, const nsString& blacklist)
+static inline bool
+isOnlySafeChars(const nsString& in, const nsTArray<char16_t>& aBlockList)
 {
-  return (blacklist.IsEmpty() ||
-          in.FindCharInSet(blacklist) == kNotFound);
+  if (aBlockList.IsEmpty()) {
+    return true;
+  }
+  const char16_t* cur = in.BeginReading();
+  const char16_t* end = in.EndReading();
+
+  for (; cur < end; ++cur) {
+    size_t unused;
+    if (mozilla::BinarySearch(aBlockList, 0, aBlockList.Length(), *cur,
+                              &unused)) {
+      return false;
+    }
+  }
+  return true;
 }
 
 //-----------------------------------------------------------------------------
 // nsIDNService
 //-----------------------------------------------------------------------------
 
 /* Implementation file */
 NS_IMPL_ISUPPORTS(nsIDNService,
                   nsIIDNService,
                   nsISupportsWeakReference)
 
 static const char* gCallbackPrefs[] = {
-  NS_NET_PREF_IDNBLACKLIST,
+  NS_NET_PREF_EXTRAALLOWED,
+  NS_NET_PREF_EXTRABLOCKED,
   NS_NET_PREF_SHOWPUNYCODE,
   NS_NET_PREF_IDNRESTRICTION,
   NS_NET_PREF_IDNUSEWHITELIST,
   nullptr,
 };
 
 nsresult nsIDNService::Init()
 {
@@ -73,34 +92,55 @@ nsresult nsIDNService::Init()
   MutexAutoLock lock(mLock);
 
   nsCOMPtr<nsIPrefService> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID));
   if (prefs)
     prefs->GetBranch(NS_NET_PREF_IDNWHITELIST, getter_AddRefs(mIDNWhitelistPrefBranch));
 
   Preferences::RegisterPrefixCallbacks(PrefChanged, gCallbackPrefs, this);
   prefsChanged(nullptr);
+  InitializeBlocklist();
 
   return NS_OK;
 }
 
+void
+nsIDNService::InitializeBlocklist()
+{
+  mIDNBlocklist.Clear();
+  mIDNBlocklist.AppendElements(sBlocklistChars,
+                               mozilla::ArrayLength(sBlocklistChars));
+  nsAutoString extraAllowed;
+  nsresult rv = Preferences::GetString(NS_NET_PREF_EXTRAALLOWED, extraAllowed);
+
+  if (NS_SUCCEEDED(rv) && !extraAllowed.IsEmpty()) {
+    mIDNBlocklist.RemoveElementsBy([&](char16_t c) {
+      return extraAllowed.FindChar(c, 0) != -1;
+    });
+  }
+
+  nsAutoString extraBlocked;
+  rv = Preferences::GetString(NS_NET_PREF_EXTRABLOCKED, extraBlocked);
+  if (NS_SUCCEEDED(rv) && !extraBlocked.IsEmpty()) {
+    mIDNBlocklist.AppendElements(
+      static_cast<const char16_t*>(extraBlocked.Data()), extraBlocked.Length());
+    mIDNBlocklist.Sort();
+  }
+}
+
 void nsIDNService::prefsChanged(const char *pref)
 {
   MOZ_ASSERT(NS_IsMainThread());
   mLock.AssertCurrentThreadOwns();
 
-  if (!pref || NS_LITERAL_CSTRING(NS_NET_PREF_IDNBLACKLIST).Equals(pref)) {
-    nsAutoCString blacklist;
-    nsresult rv = Preferences::GetCString(NS_NET_PREF_IDNBLACKLIST,
-                                          blacklist);
-    if (NS_SUCCEEDED(rv)) {
-      CopyUTF8toUTF16(blacklist, mIDNBlacklist);
-    } else {
-      mIDNBlacklist.Truncate();
-    }
+  if (pref && NS_LITERAL_CSTRING(NS_NET_PREF_EXTRAALLOWED).Equals(pref)) {
+    InitializeBlocklist();
+  }
+  if (pref && NS_LITERAL_CSTRING(NS_NET_PREF_EXTRABLOCKED).Equals(pref)) {
+    InitializeBlocklist();
   }
   if (!pref || NS_LITERAL_CSTRING(NS_NET_PREF_SHOWPUNYCODE).Equals(pref)) {
     bool val;
     if (NS_SUCCEEDED(Preferences::GetBool(NS_NET_PREF_SHOWPUNYCODE, &val)))
       mShowPunycode = val;
   }
   if (!pref || NS_LITERAL_CSTRING(NS_NET_PREF_IDNUSEWHITELIST).Equals(pref)) {
     bool val;
@@ -718,17 +758,17 @@ bool nsIDNService::isInWhitelist(const n
 }
 
 bool nsIDNService::isLabelSafe(const nsAString &label)
 {
   if (!NS_IsMainThread()) {
     mLock.AssertCurrentThreadOwns();
   }
 
-  if (!isOnlySafeChars(PromiseFlatString(label), mIDNBlacklist)) {
+  if (!isOnlySafeChars(PromiseFlatString(label), mIDNBlocklist)) {
     return false;
   }
 
   // We should never get here if the label is ASCII
   NS_ASSERTION(!IsASCII(label), "ASCII label in IDN checking");
   if (mRestrictionProfile == eASCIIOnlyProfile) {
     return false;
   }
--- a/netwerk/dns/nsIDNService.h
+++ b/netwerk/dns/nsIDNService.h
@@ -90,16 +90,18 @@ private:
    *  label individually, so the output may contain some labels in
    *  punycode and some in UTF-8
    */
   nsresult UTF8toACE(const nsACString& input, nsACString& ace,
                      stringPrepFlag flag);
   nsresult ACEtoUTF8(const nsACString& input, nsACString& _retval,
                      stringPrepFlag flag);
 
+  void InitializeBlocklist();
+
   bool isInWhitelist(const nsACString &host);
   void prefsChanged(const char *pref);
 
   static void PrefChanged(const char* aPref, nsIDNService* aSelf)
   {
     mozilla::MutexAutoLock lock(aSelf->mLock);
     aSelf->prefsChanged(aPref);
   }
@@ -159,26 +161,26 @@ private:
    * Convert a DNS label to a normalized form conforming to IDNA2008
    */
   nsresult IDNA2008StringPrep(const nsAString& input, nsAString& output,
                               stringPrepFlag flag);
 
   UIDNA* mIDNA;
 
   // We use this mutex to guard access to:
-  // |mIDNBlacklist|, |mShowPunycode|, |mRestrictionProfile|,
+  // |mIDNBlocklist|, |mShowPunycode|, |mRestrictionProfile|,
   // |mIDNUseWhitelist|.
   //
   // These members can only be updated on the main thread and
   // read on any thread. Therefore, acquiring the mutex is required
   // only for threads other than the main thread.
   mozilla::Mutex mLock;
 
   // guarded by mLock
-  nsString mIDNBlacklist;
+  nsTArray<char16_t> mIDNBlocklist;
 
   /**
    * Flag set by the pref network.IDN_show_punycode. When it is true,
    * IDNs containing non-ASCII characters are always displayed to the
    * user in punycode
    *
    * guarded by mLock
    */
--- a/netwerk/test/unit/test_bug464591.js
+++ b/netwerk/test/unit/test_bug464591.js
@@ -22,17 +22,17 @@ let prefData =
     },
     {
       name: "network.IDN.whitelist.org",
       newVal: true
     }
   ];
 
  let prefIdnBlackList = {
-      name: "network.IDN.blacklist_chars",
+      name: "network.IDN.extra_blocked_chars",
       minimumList: "\u2215\u0430\u2044",
   };
 
 function stringToURL(str) {
   return Cc["@mozilla.org/network/standard-url-mutator;1"]
          .createInstance(Ci.nsIStandardURLMutator)
          .init(Ci.nsIStandardURL.URLTYPE_AUTHORITY, 80, str, "UTF-8", null)
          .finalize()
--- a/netwerk/test/unit/test_idnservice.js
+++ b/netwerk/test/unit/test_idnservice.js
@@ -1,25 +1,37 @@
 // Tests nsIIDNService
 
-var reference = [
+"use strict";
+ChromeUtils.import("resource://gre/modules/Services.jsm");
+
+const idnService = Cc["@mozilla.org/network/idn-service;1"]
+                     .getService(Ci.nsIIDNService);
+
+add_task(async function test_simple() {
+  let reference = [
                  // The 3rd element indicates whether the second element
                  // is ACE-encoded
                  ["asciihost", "asciihost", false],
                  ["b\u00FCcher", "xn--bcher-kva", true]
                 ];
 
-function run_test() {
-  var idnService = Cc["@mozilla.org/network/idn-service;1"]
-                     .getService(Ci.nsIIDNService);
 
   for (var i = 0; i < reference.length; ++i) {
      dump("Testing " + reference[i] + "\n");
      // We test the following:
      // - Converting UTF-8 to ACE and back gives us the expected answer
      // - Converting the ASCII string UTF-8 -> ACE leaves the string unchanged
      // - isACE returns true when we expect it to (third array elem true)
      Assert.equal(idnService.convertUTF8toACE(reference[i][0]), reference[i][1]);
      Assert.equal(idnService.convertUTF8toACE(reference[i][1]), reference[i][1]);
      Assert.equal(idnService.convertACEtoUTF8(reference[i][1]), reference[i][0]);
      Assert.equal(idnService.isACE(reference[i][1]), reference[i][2]);
   }
-}
+});
+
+add_task(async function test_extra_blocked() {
+    let isAscii = {};
+    equal(idnService.convertToDisplayIDN("xn--gou-2lb.ro", isAscii), "goșu.ro");
+    Services.prefs.setStringPref("network.IDN.extra_blocked_chars", "ș");
+    equal(idnService.convertToDisplayIDN("xn--gou-2lb.ro", isAscii), "xn--gou-2lb.ro");
+    Services.prefs.clearUserPref("network.IDN.extra_blocked_chars");
+});