From 9bf4e994771d86bafbd15f0eb0e91ff1d482c7ce Mon Sep 17 00:00:00 2001 From: Adrien Destugues Date: Tue, 21 Oct 2014 14:39:43 +0200 Subject: [PATCH] BUrl: IDNA ToUnicode and ToASCII conversions. * Since DNS are normally restricted to ASCII, the use of UTF-8 in domain names is implemented using a "punycode" encoding. * The request to the DNS server must be sent with the ASCII representation of the domain name, however the Unicode one should be used for user-visible parts. * ICU provides an implementation of the conversion, which we use here. * Conversion is currently done in-place and modifies the BUrl object (this is similar to UrlEncode/UrlDecode). * Adjust existing IDN test to make use of these methods. It's passing now. --- headers/os/net/Url.h | 3 ++ src/kits/network/libnetapi/Jamfile | 7 ++++ src/kits/network/libnetapi/Url.cpp | 48 ++++++++++++++++++++++++++ src/tests/kits/net/service/UrlTest.cpp | 9 +++-- 4 files changed, 65 insertions(+), 2 deletions(-) diff --git a/headers/os/net/Url.h b/headers/os/net/Url.h index c4600ce9b5..da241cc30e 100644 --- a/headers/os/net/Url.h +++ b/headers/os/net/Url.h @@ -64,6 +64,9 @@ public: void UrlEncode(bool strict = false); void UrlDecode(bool strict = false); + status_t IDNAToAscii(); + status_t IDNAToUnicode(); + // Url encoding/decoding of strings static BString UrlEncode(const BString& url, bool strict = false, diff --git a/src/kits/network/libnetapi/Jamfile b/src/kits/network/libnetapi/Jamfile index 285858c46d..643840b78e 100644 --- a/src/kits/network/libnetapi/Jamfile +++ b/src/kits/network/libnetapi/Jamfile @@ -1,6 +1,7 @@ SubDir HAIKU_TOP src kits network libnetapi ; UsePrivateHeaders app net shared support ; +UsePrivateHeaders locale shared ; UseHeaders [ FDirName $(HAIKU_TOP) src libs compat freebsd_network compat ] : true ; @@ -31,6 +32,11 @@ for architectureObject in [ MultiArchSubDirSetup ] { SetupFeatureObjectsDir no-ssl ; } + # BUrl uses ICU to perform IDNA conversions (unicode domain names) + UseBuildFeatureHeaders icu ; + Includes [ FGristFiles Url.cpp ] + : [ BuildFeatureAttribute icu : headers ] ; + SharedLibrary [ MultiArchDefaultGristFiles libbnetapi.so ] : init.cpp DynamicBuffer.cpp @@ -91,6 +97,7 @@ for architectureObject in [ MultiArchSubDirSetup ] { : be $(TARGET_NETWORK_LIBS) [ TargetLibstdc++ ] [ TargetLibsupc++ ] [ BuildFeatureAttribute openssl : libraries ] + [ BuildFeatureAttribute icu : libraries ] [ MultiArchDefaultGristFiles libshared.a ] ; } diff --git a/src/kits/network/libnetapi/Url.cpp b/src/kits/network/libnetapi/Url.cpp index 102829558a..e68b535d1e 100644 --- a/src/kits/network/libnetapi/Url.cpp +++ b/src/kits/network/libnetapi/Url.cpp @@ -17,8 +17,12 @@ #include #include +#include #include +#include +#include + static const char* kArchivedUrl = "be:url string"; @@ -594,6 +598,50 @@ BUrl::UrlDecode(bool strict) } +status_t +BUrl::IDNAToAscii() +{ + UErrorCode err = U_ZERO_ERROR; + icu::IDNA* converter = icu::IDNA::createUTS46Instance(0, err); + icu::IDNAInfo info; + + BString result; + BStringByteSink sink(&result); + converter->nameToASCII_UTF8(icu::StringPiece(fHost.String()), sink, info, + err); + + delete converter; + + if (U_FAILURE(err)) + return B_ERROR; + + fHost = result; + return B_OK; +} + + +status_t +BUrl::IDNAToUnicode() +{ + UErrorCode err = U_ZERO_ERROR; + icu::IDNA* converter = icu::IDNA::createUTS46Instance(0, err); + icu::IDNAInfo info; + + BString result; + BStringByteSink sink(&result); + converter->nameToUnicodeUTF8(icu::StringPiece(fHost.String()), sink, info, + err); + + delete converter; + + if (U_FAILURE(err)) + return B_ERROR; + + fHost = result; + return B_OK; +} + + // #pragma mark - utility functionality diff --git a/src/tests/kits/net/service/UrlTest.cpp b/src/tests/kits/net/service/UrlTest.cpp index 6d151d031a..88b730fa67 100644 --- a/src/tests/kits/net/service/UrlTest.cpp +++ b/src/tests/kits/net/service/UrlTest.cpp @@ -587,10 +587,15 @@ UrlTest::IDNTest() for (int i = 0; tests[i].escaped != NULL; i++) { NextSubTest(); + BUrl url(tests[i].escaped); url.UrlDecode(); - CPPUNIT_ASSERT_EQUAL(BUrl(tests[i].decoded).UrlString(), - url.UrlString()); + + BUrl idn(tests[i].decoded); + status_t success = idn.IDNAToUnicode(); + + CPPUNIT_ASSERT_EQUAL(B_OK, success); + CPPUNIT_ASSERT_EQUAL(url.UrlString(), idn.UrlString()); } }