Bug 479520: Implement IDNA2008 standard for International Domain Names, patch 1: build system changes, r=ted; code changes, r=jfkthame

This commit is contained in:
Simon Montagu 2015-10-28 03:46:44 -07:00
parent 76427da26e
commit 0eb47abb65
5 changed files with 127 additions and 3 deletions

View File

@ -142,7 +142,6 @@ if test -z "$BUILDING_JS" -o -n "$JS_STANDALONE"; then
ICU_CPPFLAGS="$ICU_CPPFLAGS -DUCONFIG_NO_TRANSLITERATION" ICU_CPPFLAGS="$ICU_CPPFLAGS -DUCONFIG_NO_TRANSLITERATION"
ICU_CPPFLAGS="$ICU_CPPFLAGS -DUCONFIG_NO_REGULAR_EXPRESSIONS" ICU_CPPFLAGS="$ICU_CPPFLAGS -DUCONFIG_NO_REGULAR_EXPRESSIONS"
ICU_CPPFLAGS="$ICU_CPPFLAGS -DUCONFIG_NO_BREAK_ITERATION" ICU_CPPFLAGS="$ICU_CPPFLAGS -DUCONFIG_NO_BREAK_ITERATION"
ICU_CPPFLAGS="$ICU_CPPFLAGS -DUCONFIG_NO_IDNA"
# we don't need to pass data to and from legacy char* APIs # we don't need to pass data to and from legacy char* APIs
ICU_CPPFLAGS="$ICU_CPPFLAGS -DU_CHARSET_IS_UTF8" ICU_CPPFLAGS="$ICU_CPPFLAGS -DU_CHARSET_IS_UTF8"
# make sure to not accidentally pick up system-icu headers # make sure to not accidentally pick up system-icu headers

View File

@ -40,7 +40,6 @@ UNIFIED_SOURCES += [
'DNSRequestChild.cpp', 'DNSRequestChild.cpp',
'DNSRequestParent.cpp', 'DNSRequestParent.cpp',
'GetAddrInfo.cpp', 'GetAddrInfo.cpp',
'nameprep.c',
'nsDNSService2.cpp', 'nsDNSService2.cpp',
'nsIDNService.cpp', 'nsIDNService.cpp',
'punycode.c', 'punycode.c',
@ -69,3 +68,13 @@ LOCAL_INCLUDES += [
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk' and CONFIG['ANDROID_VERSION'] > '19': if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk' and CONFIG['ANDROID_VERSION'] > '19':
CXXFLAGS += ['-I%s/bionic/libc/dns/include' % CONFIG['ANDROID_SOURCE']] CXXFLAGS += ['-I%s/bionic/libc/dns/include' % CONFIG['ANDROID_SOURCE']]
if CONFIG['ENABLE_INTL_API']:
DEFINES['IDNA2008'] = True
CXXFLAGS += CONFIG['MOZ_ICU_CFLAGS']
CFLAGS += CONFIG['MOZ_ICU_CFLAGS']
USE_LIBS += ['icu']
else:
UNIFIED_SOURCES += [
'nameprep.c',
]

View File

@ -17,6 +17,16 @@
#include "nsISupportsPrimitives.h" #include "nsISupportsPrimitives.h"
#include "punycode.h" #include "punycode.h"
#ifdef IDNA2008
// Currently we use the transitional processing option -- see
// http://unicode.org/reports/tr46/
// To switch to non-transitional processing, change the value of this flag
// and kTransitionalProcessing in netwerk/test/unit/test_idna2008.js to false
// (patch in bug 1218179).
const bool kIDNA2008_TransitionalProcessing = true;
#include "ICUUtils.h"
#endif
using namespace mozilla::unicode; using namespace mozilla::unicode;
@ -123,18 +133,91 @@ void nsIDNService::prefsChanged(nsIPrefBranch *prefBranch, const char16_t *pref)
nsIDNService::nsIDNService() nsIDNService::nsIDNService()
{ {
#ifdef IDNA2008
uint32_t IDNAOptions = UIDNA_CHECK_BIDI | UIDNA_CHECK_CONTEXTJ;
if (!kIDNA2008_TransitionalProcessing) {
IDNAOptions |= UIDNA_NONTRANSITIONAL_TO_UNICODE;
}
UErrorCode errorCode = U_ZERO_ERROR;
mIDNA = uidna_openUTS46(IDNAOptions, &errorCode);
#else
if (idn_success != idn_nameprep_create(nullptr, &mNamePrepHandle)) if (idn_success != idn_nameprep_create(nullptr, &mNamePrepHandle))
mNamePrepHandle = nullptr; mNamePrepHandle = nullptr;
mNormalizer = do_GetService(NS_UNICODE_NORMALIZER_CONTRACTID); mNormalizer = do_GetService(NS_UNICODE_NORMALIZER_CONTRACTID);
/* member initializers and constructor code */ /* member initializers and constructor code */
#endif
} }
nsIDNService::~nsIDNService() nsIDNService::~nsIDNService()
{ {
#ifdef IDNA2008
uidna_close(mIDNA);
#else
idn_nameprep_destroy(mNamePrepHandle); idn_nameprep_destroy(mNamePrepHandle);
#endif
} }
#ifdef IDNA2008
nsresult
nsIDNService::IDNA2008ToUnicode(const nsACString& input, nsAString& output)
{
NS_ConvertUTF8toUTF16 inputStr(input);
UIDNAInfo info = UIDNA_INFO_INITIALIZER;
UErrorCode errorCode = U_ZERO_ERROR;
int32_t inLen = inputStr.Length();
int32_t outMaxLen = inLen - kACEPrefixLen + 1;
UChar outputBuffer[kMaxDNSNodeLen + 1];
int32_t outLen = uidna_labelToUnicode(mIDNA, (const UChar*)inputStr.get(),
inLen, outputBuffer, outMaxLen,
&info, &errorCode);
if (info.errors != 0) {
return NS_ERROR_FAILURE;
}
if (U_SUCCESS(errorCode)) {
ICUUtils::AssignUCharArrayToString(outputBuffer, outLen, output);
}
return ICUUtils::UErrorToNsResult(errorCode);
}
nsresult
nsIDNService::IDNA2008StringPrep(const nsAString& input,
nsAString& output,
stringPrepFlag flag)
{
UIDNAInfo info = UIDNA_INFO_INITIALIZER;
UErrorCode errorCode = U_ZERO_ERROR;
int32_t inLen = input.Length();
int32_t outMaxLen = kMaxDNSNodeLen + 1;
UChar outputBuffer[kMaxDNSNodeLen + 1];
int32_t outLen =
uidna_labelToUnicode(mIDNA, (const UChar*)PromiseFlatString(input).get(),
inLen, outputBuffer, outMaxLen, &info, &errorCode);
nsresult rv = ICUUtils::UErrorToNsResult(errorCode);
NS_ENSURE_SUCCESS(rv, rv);
// Output the result of nameToUnicode even if there were errors
ICUUtils::AssignUCharArrayToString(outputBuffer, outLen, output);
if (flag == eStringPrepIgnoreErrors) {
return NS_OK;
}
if (info.errors != 0) {
if (flag == eStringPrepForDNS) {
output.Truncate();
}
rv = NS_ERROR_FAILURE;
}
return rv;
}
#endif
NS_IMETHODIMP nsIDNService::ConvertUTF8toACE(const nsACString & input, nsACString & ace) NS_IMETHODIMP nsIDNService::ConvertUTF8toACE(const nsACString & input, nsACString & ace)
{ {
return UTF8toACE(input, ace, eStringPrepForDNS); return UTF8toACE(input, ace, eStringPrepForDNS);
@ -396,6 +479,7 @@ static nsresult utf16ToUcs4(const nsAString& in,
return NS_OK; return NS_OK;
} }
#ifndef IDNA2008
static void ucs4toUtf16(const uint32_t *in, nsAString& out) static void ucs4toUtf16(const uint32_t *in, nsAString& out)
{ {
while (*in) { while (*in) {
@ -408,6 +492,7 @@ static void ucs4toUtf16(const uint32_t *in, nsAString& out)
in++; in++;
} }
} }
#endif
static nsresult punycode(const nsAString& in, nsACString& out) static nsresult punycode(const nsAString& in, nsACString& out)
{ {
@ -462,6 +547,9 @@ static nsresult punycode(const nsAString& in, nsACString& out)
nsresult nsIDNService::stringPrep(const nsAString& in, nsAString& out, nsresult nsIDNService::stringPrep(const nsAString& in, nsAString& out,
stringPrepFlag flag) stringPrepFlag flag)
{ {
#ifdef IDNA2008
return IDNA2008StringPrep(in, out, flag);
#else
if (!mNamePrepHandle || !mNormalizer) if (!mNamePrepHandle || !mNormalizer)
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
@ -523,6 +611,7 @@ nsresult nsIDNService::stringPrep(const nsAString& in, nsAString& out,
} }
return rv; return rv;
#endif
} }
nsresult nsIDNService::stringPrepAndACE(const nsAString& in, nsACString& out, nsresult nsIDNService::stringPrepAndACE(const nsAString& in, nsACString& out,
@ -612,6 +701,11 @@ nsresult nsIDNService::decodeACE(const nsACString& in, nsACString& out,
return NS_OK; return NS_OK;
} }
nsAutoString utf16;
#ifdef IDNA2008
nsresult result = IDNA2008ToUnicode(in, utf16);
NS_ENSURE_SUCCESS(result, result);
#else
// RFC 3490 - 4.2 ToUnicode // RFC 3490 - 4.2 ToUnicode
// The ToUnicode output never contains more code points than its input. // The ToUnicode output never contains more code points than its input.
punycode_uint output_length = in.Length() - kACEPrefixLen + 1; punycode_uint output_length = in.Length() - kACEPrefixLen + 1;
@ -630,9 +724,9 @@ nsresult nsIDNService::decodeACE(const nsACString& in, nsACString& out,
// UCS4 -> UTF8 // UCS4 -> UTF8
output[output_length] = 0; output[output_length] = 0;
nsAutoString utf16;
ucs4toUtf16(output, utf16); ucs4toUtf16(output, utf16);
delete [] output; delete [] output;
#endif
if (flag != eStringPrepForUI || isLabelSafe(utf16)) { if (flag != eStringPrepForUI || isLabelSafe(utf16)) {
CopyUTF16toUTF8(utf16, out); CopyUTF16toUTF8(utf16, out);
} else { } else {

View File

@ -10,8 +10,14 @@
#include "nsCOMPtr.h" #include "nsCOMPtr.h"
#include "nsIObserver.h" #include "nsIObserver.h"
#include "nsWeakReference.h" #include "nsWeakReference.h"
#ifdef IDNA2008
#include "unicode/uidna.h"
#else
#include "nsIUnicodeNormalizer.h" #include "nsIUnicodeNormalizer.h"
#include "nsIDNKitInterface.h" #include "nsIDNKitInterface.h"
#endif
#include "nsString.h" #include "nsString.h"
class nsIPrefBranch; class nsIPrefBranch;
@ -143,8 +149,23 @@ private:
*/ */
bool illegalScriptCombo(int32_t script, int32_t& savedScript); bool illegalScriptCombo(int32_t script, int32_t& savedScript);
#ifdef IDNA2008
/**
* Convert a DNS label from ASCII to Unicode using IDNA2008
*/
nsresult IDNA2008ToUnicode(const nsACString& input, nsAString& output);
/**
* Convert a DNS label to a normalized form conforming to IDNA2008
*/
nsresult IDNA2008StringPrep(const nsAString& input, nsAString& output,
stringPrepFlag flag);
UIDNA* mIDNA;
#else
idn_nameprep_t mNamePrepHandle; idn_nameprep_t mNamePrepHandle;
nsCOMPtr<nsIUnicodeNormalizer> mNormalizer; nsCOMPtr<nsIUnicodeNormalizer> mNormalizer;
#endif
nsXPIDLString mIDNBlacklist; nsXPIDLString mIDNBlacklist;
/** /**

View File

@ -43,6 +43,7 @@ LOCAL_INCLUDES = [
'../dns', '../dns',
] ]
DEFINES['IDNA2008'] = False
DEFINES['MOZILLA_INTERNAL_API'] = True DEFINES['MOZILLA_INTERNAL_API'] = True
DEFINES['MOZILLA_XPCOMRT_API'] = True DEFINES['MOZILLA_XPCOMRT_API'] = True
DEFINES['MOZILLA_EXTERNAL_LINKAGE'] = True DEFINES['MOZILLA_EXTERNAL_LINKAGE'] = True