NS_IMETHODIMP nsIDNService::ConvertToDisplayIDN(const nsACString & input, PRBool * _isASCII, nsACString & _retval) { // If host is ACE, then convert to UTF-8 if the host is in the IDN whitelist. // Else, if host is already UTF-8, then make sure it is normalized per IDN. nsresult rv; if (IsASCII(input)) { // first, canonicalize the host to lowercase, for whitelist lookup _retval = input; ToLowerCase(_retval); PRBool isACE; IsACE(_retval, &isACE); if (isACE && !mShowPunycode && isInWhitelist(_retval)) { // ConvertACEtoUTF8() can't fail, but might return the original ACE string nsCAutoString temp(_retval); ConvertACEtoUTF8(temp, _retval); *_isASCII = IsASCII(_retval); } else { *_isASCII = PR_TRUE; } } else { // We have to normalize the hostname before testing against the domain // whitelist (see bug 315411), and to ensure the entire string gets // normalized. rv = Normalize(input, _retval); if (NS_FAILED(rv)) return rv; if (mShowPunycode && NS_SUCCEEDED(ConvertUTF8toACE(_retval, _retval))) { *_isASCII = PR_TRUE; return NS_OK; } // normalization could result in an ASCII-only hostname. alternatively, if // the host is converted to ACE by the normalizer, then the host may contain // unsafe characters, so leave it ACE encoded. see bug 283016, bug 301694, and bug 309311. *_isASCII = IsASCII(_retval); if (!*_isASCII && !isInWhitelist(_retval)) { *_isASCII = PR_TRUE; return ConvertUTF8toACE(_retval, _retval); } } return NS_OK; }
nsresult nsIDNService::decodeACE(const nsACString& in, nsACString& out) { PRBool isAce; IsACE(in, &isAce); if (!isAce) { out.Assign(in); return NS_OK; } // RFC 3490 - 4.2 ToUnicode // The ToUnicode output never contains more code points than its input. punycode_uint output_length = in.Length() - kACEPrefixLen + 1; punycode_uint *output = new punycode_uint[output_length]; NS_ENSURE_TRUE(output, NS_ERROR_OUT_OF_MEMORY); enum punycode_status status = punycode_decode(in.Length() - kACEPrefixLen, PromiseFlatCString(in).get() + kACEPrefixLen, &output_length, output, nsnull); if (status != punycode_success) { delete [] output; return NS_ERROR_FAILURE; } // UCS4 -> UTF8 output[output_length] = 0; nsAutoString utf16; ucs4toUtf16(output, utf16); delete [] output; if (!isOnlySafeChars(utf16, mIDNBlacklist)) return NS_ERROR_FAILURE; CopyUTF16toUTF8(utf16, out); // Validation: encode back to ACE and compare the strings nsCAutoString ace; nsresult rv = ConvertUTF8toACE(out, ace); NS_ENSURE_SUCCESS(rv, rv); if (!ace.Equals(in, nsCaseInsensitiveCStringComparator())) return NS_ERROR_FAILURE; return NS_OK; }
NS_IMETHODIMP nsIDNService::Normalize(const nsACString & input, nsACString & output) { // protect against bogus input NS_ENSURE_TRUE(IsUTF8(input), NS_ERROR_UNEXPECTED); NS_ConvertUTF8toUTF16 inUTF16(input); normalizeFullStops(inUTF16); nsAutoString outUTF16; nsresult rv = stringPrep(inUTF16, outUTF16); if (NS_FAILED(rv)) return rv; CopyUTF16toUTF8(outUTF16, output); if (!isOnlySafeChars(outUTF16, mIDNBlacklist)) return ConvertUTF8toACE(output, output); return NS_OK; }
/* AUTF8String normalize(in AUTF8String input); */ NS_IMETHODIMP nsIDNService::Normalize(const nsACString & input, nsACString & output) { // protect against bogus input NS_ENSURE_TRUE(IsUTF8(input), NS_ERROR_UNEXPECTED); NS_ConvertUTF8toUTF16 inUTF16(input); normalizeFullStops(inUTF16); // pass the domain name to stringprep label by label nsAutoString outUTF16, outLabel; PRUint32 len = 0, offset = 0; nsresult rv; nsAString::const_iterator start, end; inUTF16.BeginReading(start); inUTF16.EndReading(end); while (start != end) { len++; if (*start++ == PRUnichar('.')) { rv = stringPrep(Substring(inUTF16, offset, len - 1), outLabel); NS_ENSURE_SUCCESS(rv, rv); outUTF16.Append(outLabel); outUTF16.Append(PRUnichar('.')); offset += len; len = 0; } } if (len) { rv = stringPrep(Substring(inUTF16, offset, len), outLabel); NS_ENSURE_SUCCESS(rv, rv); outUTF16.Append(outLabel); } CopyUTF16toUTF8(outUTF16, output); if (!isOnlySafeChars(outUTF16, mIDNBlacklist)) return ConvertUTF8toACE(output, output); return NS_OK; }
PRBool nsIDNService::isInWhitelist(const nsACString &host) { if (mIDNWhitelistPrefBranch) { // truncate trailing dots first nsCAutoString tld(host); tld.Trim("."); PRInt32 pos = tld.RFind("."); if (pos == kNotFound) return PR_FALSE; tld.Cut(0, pos + 1); // make sure the TLD is ACE for lookup. if (!IsASCII(tld) && NS_FAILED(ConvertUTF8toACE(tld, tld))) return PR_FALSE; PRBool safe; if (NS_SUCCEEDED(mIDNWhitelistPrefBranch->GetBoolPref(tld.get(), &safe))) return safe; } return PR_FALSE; }