Bug 628949 - Update visible region / glass regions after we paint. r=roc a=2.0.
[mozilla-central.git] / netwerk / dns / nsIDNService.cpp
blobf1be9768b112fbeb3c49a3b5ae463dcbc1786b7a
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
15 * The Original Code is mozilla.org code.
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 2002
20 * the Initial Developer. All Rights Reserved.
22 * Contributor(s):
23 * Naoki Hotta <nhotta@netscape.com> (original author)
25 * Alternatively, the contents of this file may be used under the terms of
26 * either the GNU General Public License Version 2 or later (the "GPL"), or
27 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 * in which case the provisions of the GPL or the LGPL are applicable instead
29 * of those above. If you wish to allow use of your version of this file only
30 * under the terms of either the GPL or the LGPL, and not to allow others to
31 * use your version of this file under the terms of the MPL, indicate your
32 * decision by deleting the provisions above and replace them with the notice
33 * and other provisions required by the GPL or the LGPL. If you do not delete
34 * the provisions above, a recipient may use your version of this file under
35 * the terms of any one of the MPL, the GPL or the LGPL.
37 * ***** END LICENSE BLOCK ***** */
39 #include "nsIDNService.h"
40 #include "nsReadableUtils.h"
41 #include "nsCRT.h"
42 #include "nsUnicharUtils.h"
43 #include "nsIServiceManager.h"
44 #include "nsIPrefService.h"
45 #include "nsIPrefBranch.h"
46 #include "nsIPrefBranch2.h"
47 #include "nsIObserverService.h"
48 #include "nsISupportsPrimitives.h"
49 #include "punycode.h"
51 #include "mozilla/FunctionTimer.h"
53 //-----------------------------------------------------------------------------
54 // RFC 1034 - 3.1. Name space specifications and terminology
55 static const PRUint32 kMaxDNSNodeLen = 63;
57 //-----------------------------------------------------------------------------
59 #define NS_NET_PREF_IDNTESTBED "network.IDN_testbed"
60 #define NS_NET_PREF_IDNPREFIX "network.IDN_prefix"
61 #define NS_NET_PREF_IDNBLACKLIST "network.IDN.blacklist_chars"
62 #define NS_NET_PREF_SHOWPUNYCODE "network.IDN_show_punycode"
63 #define NS_NET_PREF_IDNWHITELIST "network.IDN.whitelist."
65 inline PRBool isOnlySafeChars(const nsAFlatString& in,
66 const nsAFlatString& blacklist)
68 return (blacklist.IsEmpty() ||
69 in.FindCharInSet(blacklist) == kNotFound);
72 //-----------------------------------------------------------------------------
73 // nsIDNService
74 //-----------------------------------------------------------------------------
76 /* Implementation file */
77 NS_IMPL_THREADSAFE_ISUPPORTS3(nsIDNService,
78 nsIIDNService,
79 nsIObserver,
80 nsISupportsWeakReference)
82 nsresult nsIDNService::Init()
84 NS_TIME_FUNCTION;
86 nsCOMPtr<nsIPrefService> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID));
87 if (prefs)
88 prefs->GetBranch(NS_NET_PREF_IDNWHITELIST, getter_AddRefs(mIDNWhitelistPrefBranch));
90 nsCOMPtr<nsIPrefBranch2> prefInternal(do_QueryInterface(prefs));
91 if (prefInternal) {
92 prefInternal->AddObserver(NS_NET_PREF_IDNTESTBED, this, PR_TRUE);
93 prefInternal->AddObserver(NS_NET_PREF_IDNPREFIX, this, PR_TRUE);
94 prefInternal->AddObserver(NS_NET_PREF_IDNBLACKLIST, this, PR_TRUE);
95 prefInternal->AddObserver(NS_NET_PREF_SHOWPUNYCODE, this, PR_TRUE);
96 prefsChanged(prefInternal, nsnull);
99 return NS_OK;
102 NS_IMETHODIMP nsIDNService::Observe(nsISupports *aSubject,
103 const char *aTopic,
104 const PRUnichar *aData)
106 if (!strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID)) {
107 nsCOMPtr<nsIPrefBranch> prefBranch( do_QueryInterface(aSubject) );
108 if (prefBranch)
109 prefsChanged(prefBranch, aData);
111 return NS_OK;
114 void nsIDNService::prefsChanged(nsIPrefBranch *prefBranch, const PRUnichar *pref)
116 if (!pref || NS_LITERAL_STRING(NS_NET_PREF_IDNTESTBED).Equals(pref)) {
117 PRBool val;
118 if (NS_SUCCEEDED(prefBranch->GetBoolPref(NS_NET_PREF_IDNTESTBED, &val)))
119 mMultilingualTestBed = val;
121 if (!pref || NS_LITERAL_STRING(NS_NET_PREF_IDNPREFIX).Equals(pref)) {
122 nsXPIDLCString prefix;
123 nsresult rv = prefBranch->GetCharPref(NS_NET_PREF_IDNPREFIX, getter_Copies(prefix));
124 if (NS_SUCCEEDED(rv) && prefix.Length() <= kACEPrefixLen)
125 PL_strncpyz(nsIDNService::mACEPrefix, prefix.get(), kACEPrefixLen + 1);
127 if (!pref || NS_LITERAL_STRING(NS_NET_PREF_IDNBLACKLIST).Equals(pref)) {
128 nsCOMPtr<nsISupportsString> blacklist;
129 nsresult rv = prefBranch->GetComplexValue(NS_NET_PREF_IDNBLACKLIST,
130 NS_GET_IID(nsISupportsString),
131 getter_AddRefs(blacklist));
132 if (NS_SUCCEEDED(rv))
133 blacklist->ToString(getter_Copies(mIDNBlacklist));
134 else
135 mIDNBlacklist.Truncate();
137 if (!pref || NS_LITERAL_STRING(NS_NET_PREF_SHOWPUNYCODE).Equals(pref)) {
138 PRBool val;
139 if (NS_SUCCEEDED(prefBranch->GetBoolPref(NS_NET_PREF_SHOWPUNYCODE, &val)))
140 mShowPunycode = val;
144 nsIDNService::nsIDNService()
146 // initialize to the official prefix (RFC 3490 "5. ACE prefix")
147 const char kIDNSPrefix[] = "xn--";
148 strcpy(mACEPrefix, kIDNSPrefix);
150 mMultilingualTestBed = PR_FALSE;
152 if (idn_success != idn_nameprep_create(NULL, &mNamePrepHandle))
153 mNamePrepHandle = nsnull;
155 mNormalizer = do_GetService(NS_UNICODE_NORMALIZER_CONTRACTID);
156 /* member initializers and constructor code */
159 nsIDNService::~nsIDNService()
161 idn_nameprep_destroy(mNamePrepHandle);
164 /* ACString ConvertUTF8toACE (in AUTF8String input); */
165 NS_IMETHODIMP nsIDNService::ConvertUTF8toACE(const nsACString & input, nsACString & ace)
167 return UTF8toACE(input, ace, PR_TRUE);
170 nsresult nsIDNService::UTF8toACE(const nsACString & input, nsACString & ace, PRBool allowUnassigned)
172 nsresult rv;
173 NS_ConvertUTF8toUTF16 ustr(input);
175 // map ideographic period to ASCII period etc.
176 normalizeFullStops(ustr);
179 PRUint32 len, offset;
180 len = 0;
181 offset = 0;
182 nsCAutoString encodedBuf;
184 nsAString::const_iterator start, end;
185 ustr.BeginReading(start);
186 ustr.EndReading(end);
187 ace.Truncate();
189 // encode nodes if non ASCII
190 while (start != end) {
191 len++;
192 if (*start++ == (PRUnichar)'.') {
193 rv = stringPrepAndACE(Substring(ustr, offset, len - 1), encodedBuf,
194 allowUnassigned);
195 NS_ENSURE_SUCCESS(rv, rv);
197 ace.Append(encodedBuf);
198 ace.Append('.');
199 offset += len;
200 len = 0;
204 // add extra node for multilingual test bed
205 if (mMultilingualTestBed)
206 ace.AppendLiteral("mltbd.");
207 // encode the last node if non ASCII
208 if (len) {
209 rv = stringPrepAndACE(Substring(ustr, offset, len), encodedBuf,
210 allowUnassigned);
211 NS_ENSURE_SUCCESS(rv, rv);
213 ace.Append(encodedBuf);
216 return NS_OK;
219 /* AUTF8String convertACEtoUTF8(in ACString input); */
220 NS_IMETHODIMP nsIDNService::ConvertACEtoUTF8(const nsACString & input, nsACString & _retval)
222 return ACEtoUTF8(input, _retval, PR_TRUE);
225 nsresult nsIDNService::ACEtoUTF8(const nsACString & input, nsACString & _retval,
226 PRBool allowUnassigned)
228 // RFC 3490 - 4.2 ToUnicode
229 // ToUnicode never fails. If any step fails, then the original input
230 // sequence is returned immediately in that step.
232 if (!IsASCII(input)) {
233 _retval.Assign(input);
234 return NS_OK;
237 PRUint32 len = 0, offset = 0;
238 nsCAutoString decodedBuf;
240 nsACString::const_iterator start, end;
241 input.BeginReading(start);
242 input.EndReading(end);
243 _retval.Truncate();
245 // loop and decode nodes
246 while (start != end) {
247 len++;
248 if (*start++ == '.') {
249 if (NS_FAILED(decodeACE(Substring(input, offset, len - 1), decodedBuf,
250 allowUnassigned))) {
251 _retval.Assign(input);
252 return NS_OK;
255 _retval.Append(decodedBuf);
256 _retval.Append('.');
257 offset += len;
258 len = 0;
261 // decode the last node
262 if (len) {
263 if (NS_FAILED(decodeACE(Substring(input, offset, len), decodedBuf,
264 allowUnassigned)))
265 _retval.Assign(input);
266 else
267 _retval.Append(decodedBuf);
270 return NS_OK;
273 /* boolean isACE(in ACString input); */
274 NS_IMETHODIMP nsIDNService::IsACE(const nsACString & input, PRBool *_retval)
276 nsACString::const_iterator begin;
277 input.BeginReading(begin);
279 const char *data = begin.get();
280 PRUint32 dataLen = begin.size_forward();
282 // look for the ACE prefix in the input string. it may occur
283 // at the beginning of any segment in the domain name. for
284 // example: "www.xn--ENCODED.com"
286 const char *p = PL_strncasestr(data, mACEPrefix, dataLen);
288 *_retval = p && (p == data || *(p - 1) == '.');
289 return NS_OK;
292 /* AUTF8String normalize(in AUTF8String input); */
293 NS_IMETHODIMP nsIDNService::Normalize(const nsACString & input, nsACString & output)
295 // protect against bogus input
296 NS_ENSURE_TRUE(IsUTF8(input), NS_ERROR_UNEXPECTED);
298 NS_ConvertUTF8toUTF16 inUTF16(input);
299 normalizeFullStops(inUTF16);
301 // pass the domain name to stringprep label by label
302 nsAutoString outUTF16, outLabel;
304 PRUint32 len = 0, offset = 0;
305 nsresult rv;
306 nsAString::const_iterator start, end;
307 inUTF16.BeginReading(start);
308 inUTF16.EndReading(end);
310 while (start != end) {
311 len++;
312 if (*start++ == PRUnichar('.')) {
313 rv = stringPrep(Substring(inUTF16, offset, len - 1), outLabel, PR_TRUE);
314 NS_ENSURE_SUCCESS(rv, rv);
316 outUTF16.Append(outLabel);
317 outUTF16.Append(PRUnichar('.'));
318 offset += len;
319 len = 0;
322 if (len) {
323 rv = stringPrep(Substring(inUTF16, offset, len), outLabel, PR_TRUE);
324 NS_ENSURE_SUCCESS(rv, rv);
326 outUTF16.Append(outLabel);
329 CopyUTF16toUTF8(outUTF16, output);
330 if (!isOnlySafeChars(outUTF16, mIDNBlacklist))
331 return ConvertUTF8toACE(output, output);
333 return NS_OK;
336 NS_IMETHODIMP nsIDNService::ConvertToDisplayIDN(const nsACString & input, PRBool * _isASCII, nsACString & _retval)
338 // If host is ACE, then convert to UTF-8 if the host is in the IDN whitelist.
339 // Else, if host is already UTF-8, then make sure it is normalized per IDN.
341 nsresult rv;
343 if (IsASCII(input)) {
344 // first, canonicalize the host to lowercase, for whitelist lookup
345 _retval = input;
346 ToLowerCase(_retval);
348 PRBool isACE;
349 IsACE(_retval, &isACE);
351 if (isACE && !mShowPunycode && isInWhitelist(_retval)) {
352 // ACEtoUTF8() can't fail, but might return the original ACE string
353 nsCAutoString temp(_retval);
354 ACEtoUTF8(temp, _retval, PR_FALSE);
355 *_isASCII = IsASCII(_retval);
356 } else {
357 *_isASCII = PR_TRUE;
359 } else {
360 // We have to normalize the hostname before testing against the domain
361 // whitelist (see bug 315411), and to ensure the entire string gets
362 // normalized.
363 rv = Normalize(input, _retval);
364 if (NS_FAILED(rv)) return rv;
366 if (mShowPunycode && NS_SUCCEEDED(ConvertUTF8toACE(_retval, _retval))) {
367 *_isASCII = PR_TRUE;
368 return NS_OK;
371 // normalization could result in an ASCII-only hostname. alternatively, if
372 // the host is converted to ACE by the normalizer, then the host may contain
373 // unsafe characters, so leave it ACE encoded. see bug 283016, bug 301694, and bug 309311.
374 *_isASCII = IsASCII(_retval);
375 if (!*_isASCII && !isInWhitelist(_retval)) {
376 *_isASCII = PR_TRUE;
377 return ConvertUTF8toACE(_retval, _retval);
381 return NS_OK;
384 //-----------------------------------------------------------------------------
386 static void utf16ToUcs4(const nsAString& in, PRUint32 *out, PRUint32 outBufLen, PRUint32 *outLen)
388 PRUint32 i = 0;
389 nsAString::const_iterator start, end;
390 in.BeginReading(start);
391 in.EndReading(end);
393 while (start != end) {
394 PRUnichar curChar;
396 curChar= *start++;
398 if (start != end &&
399 NS_IS_HIGH_SURROGATE(curChar) &&
400 NS_IS_LOW_SURROGATE(*start)) {
401 out[i] = SURROGATE_TO_UCS4(curChar, *start);
402 ++start;
404 else
405 out[i] = curChar;
407 i++;
408 if (i >= outBufLen) {
409 NS_ERROR("input too big, the result truncated");
410 out[outBufLen-1] = (PRUint32)'\0';
411 *outLen = outBufLen-1;
412 return;
415 out[i] = (PRUint32)'\0';
416 *outLen = i;
419 static void ucs4toUtf16(const PRUint32 *in, nsAString& out)
421 while (*in) {
422 if (!IS_IN_BMP(*in)) {
423 out.Append((PRUnichar) H_SURROGATE(*in));
424 out.Append((PRUnichar) L_SURROGATE(*in));
426 else
427 out.Append((PRUnichar) *in);
428 in++;
432 static nsresult punycode(const char* prefix, const nsAString& in, nsACString& out)
434 PRUint32 ucs4Buf[kMaxDNSNodeLen + 1];
435 PRUint32 ucs4Len;
436 utf16ToUcs4(in, ucs4Buf, kMaxDNSNodeLen, &ucs4Len);
438 // need maximum 20 bits to encode 16 bit Unicode character
439 // (include null terminator)
440 const PRUint32 kEncodedBufSize = kMaxDNSNodeLen * 20 / 8 + 1 + 1;
441 char encodedBuf[kEncodedBufSize];
442 punycode_uint encodedLength = kEncodedBufSize;
444 enum punycode_status status = punycode_encode(ucs4Len,
445 ucs4Buf,
446 nsnull,
447 &encodedLength,
448 encodedBuf);
450 if (punycode_success != status ||
451 encodedLength >= kEncodedBufSize)
452 return NS_ERROR_FAILURE;
454 encodedBuf[encodedLength] = '\0';
455 out.Assign(nsDependentCString(prefix) + nsDependentCString(encodedBuf));
457 return NS_OK;
460 static nsresult encodeToRACE(const char* prefix, const nsAString& in, nsACString& out)
462 // need maximum 20 bits to encode 16 bit Unicode character
463 // (include null terminator)
464 const PRUint32 kEncodedBufSize = kMaxDNSNodeLen * 20 / 8 + 1 + 1;
466 // set up a work buffer for RACE encoder
467 PRUnichar temp[kMaxDNSNodeLen + 2];
468 temp[0] = 0xFFFF; // set a place holder (to be filled by get_compress_mode)
469 temp[in.Length() + 1] = (PRUnichar)'\0';
471 nsAString::const_iterator start, end;
472 in.BeginReading(start);
473 in.EndReading(end);
475 for (PRUint32 i = 1; start != end; i++)
476 temp[i] = *start++;
478 // encode nodes if non ASCII
480 char encodedBuf[kEncodedBufSize];
481 idn_result_t result = race_compress_encode((const unsigned short *) temp,
482 get_compress_mode((unsigned short *) temp + 1),
483 encodedBuf, kEncodedBufSize);
484 if (idn_success != result)
485 return NS_ERROR_FAILURE;
487 out.Assign(prefix);
488 out.Append(encodedBuf);
490 return NS_OK;
493 // RFC 3454
495 // 1) Map -- For each character in the input, check if it has a mapping
496 // and, if so, replace it with its mapping. This is described in section 3.
498 // 2) Normalize -- Possibly normalize the result of step 1 using Unicode
499 // normalization. This is described in section 4.
501 // 3) Prohibit -- Check for any characters that are not allowed in the
502 // output. If any are found, return an error. This is described in section
503 // 5.
505 // 4) Check bidi -- Possibly check for right-to-left characters, and if any
506 // are found, make sure that the whole string satisfies the requirements
507 // for bidirectional strings. If the string does not satisfy the requirements
508 // for bidirectional strings, return an error. This is described in section 6.
510 // 5) Check unassigned code points -- If allowUnassigned is false, check for
511 // any unassigned Unicode points and if any are found return an error.
512 // This is described in section 7.
514 nsresult nsIDNService::stringPrep(const nsAString& in, nsAString& out,
515 PRBool allowUnassigned)
517 if (!mNamePrepHandle || !mNormalizer)
518 return NS_ERROR_FAILURE;
520 nsresult rv = NS_OK;
521 PRUint32 ucs4Buf[kMaxDNSNodeLen + 1];
522 PRUint32 ucs4Len;
523 utf16ToUcs4(in, ucs4Buf, kMaxDNSNodeLen, &ucs4Len);
525 // map
526 idn_result_t idn_err;
528 PRUint32 namePrepBuf[kMaxDNSNodeLen * 3]; // map up to three characters
529 idn_err = idn_nameprep_map(mNamePrepHandle, (const PRUint32 *) ucs4Buf,
530 (PRUint32 *) namePrepBuf, kMaxDNSNodeLen * 3);
531 NS_ENSURE_TRUE(idn_err == idn_success, NS_ERROR_FAILURE);
533 nsAutoString namePrepStr;
534 ucs4toUtf16(namePrepBuf, namePrepStr);
535 if (namePrepStr.Length() >= kMaxDNSNodeLen)
536 return NS_ERROR_FAILURE;
538 // normalize
539 nsAutoString normlizedStr;
540 rv = mNormalizer->NormalizeUnicodeNFKC(namePrepStr, normlizedStr);
541 if (normlizedStr.Length() >= kMaxDNSNodeLen)
542 return NS_ERROR_FAILURE;
544 // prohibit
545 const PRUint32 *found = nsnull;
546 idn_err = idn_nameprep_isprohibited(mNamePrepHandle,
547 (const PRUint32 *) ucs4Buf, &found);
548 if (idn_err != idn_success || found)
549 return NS_ERROR_FAILURE;
551 // check bidi
552 idn_err = idn_nameprep_isvalidbidi(mNamePrepHandle,
553 (const PRUint32 *) ucs4Buf, &found);
554 if (idn_err != idn_success || found)
555 return NS_ERROR_FAILURE;
557 if (!allowUnassigned) {
558 // check unassigned code points
559 idn_err = idn_nameprep_isunassigned(mNamePrepHandle,
560 (const PRUint32 *) ucs4Buf, &found);
561 if (idn_err != idn_success || found)
562 return NS_ERROR_FAILURE;
565 // set the result string
566 out.Assign(normlizedStr);
568 return rv;
571 nsresult nsIDNService::encodeToACE(const nsAString& in, nsACString& out)
573 // RACE encode is supported for existing testing environment
574 if (!strcmp("bq--", mACEPrefix))
575 return encodeToRACE(mACEPrefix, in, out);
577 // use punycoce
578 return punycode(mACEPrefix, in, out);
581 nsresult nsIDNService::stringPrepAndACE(const nsAString& in, nsACString& out,
582 PRBool allowUnassigned)
584 nsresult rv = NS_OK;
586 out.Truncate();
588 if (in.Length() > kMaxDNSNodeLen) {
589 NS_ERROR("IDN node too large");
590 return NS_ERROR_FAILURE;
593 if (IsASCII(in))
594 LossyCopyUTF16toASCII(in, out);
595 else {
596 nsAutoString strPrep;
597 rv = stringPrep(in, strPrep, allowUnassigned);
598 if (NS_SUCCEEDED(rv)) {
599 if (IsASCII(strPrep))
600 LossyCopyUTF16toASCII(strPrep, out);
601 else
602 rv = encodeToACE(strPrep, out);
606 if (out.Length() > kMaxDNSNodeLen) {
607 NS_ERROR("IDN node too large");
608 return NS_ERROR_FAILURE;
611 return rv;
614 // RFC 3490
615 // 1) Whenever dots are used as label separators, the following characters
616 // MUST be recognized as dots: U+002E (full stop), U+3002 (ideographic full
617 // stop), U+FF0E (fullwidth full stop), U+FF61 (halfwidth ideographic full
618 // stop).
620 void nsIDNService::normalizeFullStops(nsAString& s)
622 nsAString::const_iterator start, end;
623 s.BeginReading(start);
624 s.EndReading(end);
625 PRInt32 index = 0;
627 while (start != end) {
628 switch (*start) {
629 case 0x3002:
630 case 0xFF0E:
631 case 0xFF61:
632 s.Replace(index, 1, NS_LITERAL_STRING("."));
633 break;
634 default:
635 break;
637 start++;
638 index++;
642 nsresult nsIDNService::decodeACE(const nsACString& in, nsACString& out,
643 PRBool allowUnassigned)
645 PRBool isAce;
646 IsACE(in, &isAce);
647 if (!isAce) {
648 out.Assign(in);
649 return NS_OK;
652 // RFC 3490 - 4.2 ToUnicode
653 // The ToUnicode output never contains more code points than its input.
654 punycode_uint output_length = in.Length() - kACEPrefixLen + 1;
655 punycode_uint *output = new punycode_uint[output_length];
656 NS_ENSURE_TRUE(output, NS_ERROR_OUT_OF_MEMORY);
658 enum punycode_status status = punycode_decode(in.Length() - kACEPrefixLen,
659 PromiseFlatCString(in).get() + kACEPrefixLen,
660 &output_length,
661 output,
662 nsnull);
663 if (status != punycode_success) {
664 delete [] output;
665 return NS_ERROR_FAILURE;
668 // UCS4 -> UTF8
669 output[output_length] = 0;
670 nsAutoString utf16;
671 ucs4toUtf16(output, utf16);
672 delete [] output;
673 if (!isOnlySafeChars(utf16, mIDNBlacklist))
674 return NS_ERROR_FAILURE;
675 CopyUTF16toUTF8(utf16, out);
677 // Validation: encode back to ACE and compare the strings
678 nsCAutoString ace;
679 nsresult rv = UTF8toACE(out, ace, allowUnassigned);
680 NS_ENSURE_SUCCESS(rv, rv);
682 if (!ace.Equals(in, nsCaseInsensitiveCStringComparator()))
683 return NS_ERROR_FAILURE;
685 return NS_OK;
688 PRBool nsIDNService::isInWhitelist(const nsACString &host)
690 if (mIDNWhitelistPrefBranch) {
691 nsCAutoString tld(host);
692 // make sure the host is ACE for lookup and check that there are no
693 // unassigned codepoints
694 if (!IsASCII(tld) && NS_FAILED(UTF8toACE(tld, tld, PR_FALSE))) {
695 return PR_FALSE;
698 // truncate trailing dots first
699 tld.Trim(".");
700 PRInt32 pos = tld.RFind(".");
701 if (pos == kNotFound)
702 return PR_FALSE;
704 tld.Cut(0, pos + 1);
706 PRBool safe;
707 if (NS_SUCCEEDED(mIDNWhitelistPrefBranch->GetBoolPref(tld.get(), &safe)))
708 return safe;
711 return PR_FALSE;