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()); } }