From 6ccaf358b740cb90163cd0cc2baf40de1a4a8988 Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 4 Feb 2019 05:39:20 +0300 Subject: [PATCH] Support IDN hosts in all resolvers. GitOrigin-RevId: c5b2741dd2d4e8bb0361e6dddf3b6749e5195c6a --- tdnet/td/net/GetHostByNameActor.cpp | 34 +++++++++++++++++++++-------- tdnet/td/net/GetHostByNameActor.h | 12 +++++----- tdutils/td/utils/port/IPAddress.cpp | 1 + test/mtproto.cpp | 3 ++- 4 files changed, 35 insertions(+), 15 deletions(-) diff --git a/tdnet/td/net/GetHostByNameActor.cpp b/tdnet/td/net/GetHostByNameActor.cpp index d3e3736c..6982f107 100644 --- a/tdnet/td/net/GetHostByNameActor.cpp +++ b/tdnet/td/net/GetHostByNameActor.cpp @@ -68,8 +68,8 @@ class GoogleDnsResolver : public Actor { void on_result(Result r_http_query) { auto end_time = Time::now(); auto result = get_ip_address(std::move(r_http_query)); - LOG(WARNING) << "Init host = " << host_ << " in " << end_time - begin_time_ << " seconds to " - << (result.is_ok() ? (PSLICE() << result.ok()) : CSlice("[invalid]")); + LOG(WARNING) << "Init IPv" << (prefer_ipv6_ ? "6" : "4") << " host = " << host_ << " in " << end_time - begin_time_ + << " seconds to " << (result.is_ok() ? (PSLICE() << result.ok()) : CSlice("[invalid]")); promise_.set_result(std::move(result)); stop(); } @@ -108,17 +108,29 @@ GetHostByNameActor::GetHostByNameActor(Options options) : options_(std::move(opt } void GetHostByNameActor::run(string host, int port, bool prefer_ipv6, Promise promise) { - auto &value = cache_[prefer_ipv6].emplace(host, Value{{}, 0}).first->second; + if (host.empty()) { + return promise.set_error(Status::Error("Host is empty")); + } + + auto r_ascii_host = idn_to_ascii(host); + if (r_ascii_host.is_error()) { + return promise.set_error(r_ascii_host.move_as_error()); + } + auto ascii_host = r_ascii_host.move_as_ok(); + + auto &value = cache_[prefer_ipv6].emplace(ascii_host, Value{{}, 0}).first->second; auto begin_time = Time::now(); if (value.expire_at > begin_time) { return promise.set_result(value.get_ip_port(port)); } - auto &query = active_queries_[prefer_ipv6][host]; + auto &query = active_queries_[prefer_ipv6][ascii_host]; query.promises.emplace_back(port, std::move(promise)); if (query.query.empty()) { CHECK(query.promises.size() == 1); - run_query(std::move(host), prefer_ipv6, query); + query.real_host = std::move(host); + query.begin_time = Time::now(); + run_query(std::move(ascii_host), prefer_ipv6, query); } } @@ -145,23 +157,27 @@ void GetHostByNameActor::run_query(std::string host, bool prefer_ipv6, Query &qu }(); } -void GetHostByNameActor::on_query_result(std::string host, bool prefer_ipv6, Result res) { +void GetHostByNameActor::on_query_result(std::string host, bool prefer_ipv6, Result result) { auto query_it = active_queries_[prefer_ipv6].find(host); CHECK(query_it != active_queries_[prefer_ipv6].end()); auto &query = query_it->second; CHECK(!query.promises.empty()); CHECK(!query.query.empty()); - if (res.is_error() && query.pos < options_.resolver_types.size()) { + if (result.is_error() && query.pos < options_.resolver_types.size()) { query.query.reset(); return run_query(std::move(host), prefer_ipv6, query); } + auto end_time = Time::now(); + LOG(WARNING) << "Init host = " << query.real_host << " in total of " << end_time - query.begin_time << " seconds to " + << (result.is_ok() ? (PSLICE() << result.ok()) : CSlice("[invalid]")); + auto promises = std::move(query.promises); - auto end_time = Time::now() + (res.is_ok() ? options_.ok_timeout : options_.error_timeout); auto value_it = cache_[prefer_ipv6].find(host); CHECK(value_it != cache_[prefer_ipv6].end()); - value_it->second = Value{std::move(res), end_time}; + auto cache_timeout = result.is_ok() ? options_.ok_timeout : options_.error_timeout; + value_it->second = Value{std::move(result), end_time + cache_timeout}; active_queries_[prefer_ipv6].erase(query_it); for (auto &promise : promises) { diff --git a/tdnet/td/net/GetHostByNameActor.h b/tdnet/td/net/GetHostByNameActor.h index e03d7e6c..87a040b9 100644 --- a/tdnet/td/net/GetHostByNameActor.h +++ b/tdnet/td/net/GetHostByNameActor.h @@ -35,7 +35,7 @@ class GetHostByNameActor final : public Actor { void run(std::string host, int port, bool prefer_ipv6, Promise promise); private: - void on_query_result(std::string host, bool prefer_ipv6, Result res); + void on_query_result(std::string host, bool prefer_ipv6, Result result); struct Value { Result ip; @@ -45,11 +45,11 @@ class GetHostByNameActor final : public Actor { } Result get_ip_port(int port) const { - auto res = ip.clone(); - if (res.is_ok()) { - res.ok_ref().set_port(port); + auto result = ip.clone(); + if (result.is_ok()) { + result.ok_ref().set_port(port); } - return res; + return result; } }; std::unordered_map cache_[2]; @@ -57,6 +57,8 @@ class GetHostByNameActor final : public Actor { struct Query { ActorOwn<> query; size_t pos = 0; + string real_host; + double begin_time; std::vector>> promises; }; std::unordered_map active_queries_[2]; diff --git a/tdutils/td/utils/port/IPAddress.cpp b/tdutils/td/utils/port/IPAddress.cpp index 6057641a..933eef8f 100644 --- a/tdutils/td/utils/port/IPAddress.cpp +++ b/tdutils/td/utils/port/IPAddress.cpp @@ -154,6 +154,7 @@ Result idn_to_ascii(CSlice host) { auto parts = full_split(Slice(host), '.'); bool is_first = true; string result; + result.reserve(host.size()); for (auto part : parts) { if (!is_first) { result += '.'; diff --git a/test/mtproto.cpp b/test/mtproto.cpp index c0d06465..093c1146 100644 --- a/test/mtproto.cpp +++ b/test/mtproto.cpp @@ -61,7 +61,8 @@ TEST(Mtproto, GetHostByNameActor) { }; std::vector hosts = { - "127.0.0.2", "1.1.1.1", "localhost", "web.telegram.org", "web.telegram.org", "москва.рф", "", "%", " ", "a"}; + "127.0.0.2", "1.1.1.1", "localhost", "web.telegram.org", "web.telegram.org.", "москва.рф", "", "%", + " ", "a", "\x80", "127.0.0.1."}; for (auto types : {vector{GetHostByNameActor::ResolverType::Native}, vector{GetHostByNameActor::ResolverType::Google}, vector{GetHostByNameActor::ResolverType::Google,