Support IDN hosts in all resolvers.
GitOrigin-RevId: c5b2741dd2d4e8bb0361e6dddf3b6749e5195c6a
This commit is contained in:
parent
fc8917a4ed
commit
6ccaf358b7
@ -68,8 +68,8 @@ class GoogleDnsResolver : public Actor {
|
|||||||
void on_result(Result<HttpQueryPtr> r_http_query) {
|
void on_result(Result<HttpQueryPtr> r_http_query) {
|
||||||
auto end_time = Time::now();
|
auto end_time = Time::now();
|
||||||
auto result = get_ip_address(std::move(r_http_query));
|
auto result = get_ip_address(std::move(r_http_query));
|
||||||
LOG(WARNING) << "Init host = " << host_ << " in " << end_time - begin_time_ << " seconds to "
|
LOG(WARNING) << "Init IPv" << (prefer_ipv6_ ? "6" : "4") << " host = " << host_ << " in " << end_time - begin_time_
|
||||||
<< (result.is_ok() ? (PSLICE() << result.ok()) : CSlice("[invalid]"));
|
<< " seconds to " << (result.is_ok() ? (PSLICE() << result.ok()) : CSlice("[invalid]"));
|
||||||
promise_.set_result(std::move(result));
|
promise_.set_result(std::move(result));
|
||||||
stop();
|
stop();
|
||||||
}
|
}
|
||||||
@ -108,17 +108,29 @@ GetHostByNameActor::GetHostByNameActor(Options options) : options_(std::move(opt
|
|||||||
}
|
}
|
||||||
|
|
||||||
void GetHostByNameActor::run(string host, int port, bool prefer_ipv6, Promise<IPAddress> promise) {
|
void GetHostByNameActor::run(string host, int port, bool prefer_ipv6, Promise<IPAddress> 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();
|
auto begin_time = Time::now();
|
||||||
if (value.expire_at > begin_time) {
|
if (value.expire_at > begin_time) {
|
||||||
return promise.set_result(value.get_ip_port(port));
|
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));
|
query.promises.emplace_back(port, std::move(promise));
|
||||||
if (query.query.empty()) {
|
if (query.query.empty()) {
|
||||||
CHECK(query.promises.size() == 1);
|
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<IPAddress> res) {
|
void GetHostByNameActor::on_query_result(std::string host, bool prefer_ipv6, Result<IPAddress> result) {
|
||||||
auto query_it = active_queries_[prefer_ipv6].find(host);
|
auto query_it = active_queries_[prefer_ipv6].find(host);
|
||||||
CHECK(query_it != active_queries_[prefer_ipv6].end());
|
CHECK(query_it != active_queries_[prefer_ipv6].end());
|
||||||
auto &query = query_it->second;
|
auto &query = query_it->second;
|
||||||
CHECK(!query.promises.empty());
|
CHECK(!query.promises.empty());
|
||||||
CHECK(!query.query.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();
|
query.query.reset();
|
||||||
return run_query(std::move(host), prefer_ipv6, query);
|
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 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);
|
auto value_it = cache_[prefer_ipv6].find(host);
|
||||||
CHECK(value_it != cache_[prefer_ipv6].end());
|
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);
|
active_queries_[prefer_ipv6].erase(query_it);
|
||||||
|
|
||||||
for (auto &promise : promises) {
|
for (auto &promise : promises) {
|
||||||
|
@ -35,7 +35,7 @@ class GetHostByNameActor final : public Actor {
|
|||||||
void run(std::string host, int port, bool prefer_ipv6, Promise<IPAddress> promise);
|
void run(std::string host, int port, bool prefer_ipv6, Promise<IPAddress> promise);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void on_query_result(std::string host, bool prefer_ipv6, Result<IPAddress> res);
|
void on_query_result(std::string host, bool prefer_ipv6, Result<IPAddress> result);
|
||||||
|
|
||||||
struct Value {
|
struct Value {
|
||||||
Result<IPAddress> ip;
|
Result<IPAddress> ip;
|
||||||
@ -45,11 +45,11 @@ class GetHostByNameActor final : public Actor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Result<IPAddress> get_ip_port(int port) const {
|
Result<IPAddress> get_ip_port(int port) const {
|
||||||
auto res = ip.clone();
|
auto result = ip.clone();
|
||||||
if (res.is_ok()) {
|
if (result.is_ok()) {
|
||||||
res.ok_ref().set_port(port);
|
result.ok_ref().set_port(port);
|
||||||
}
|
}
|
||||||
return res;
|
return result;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
std::unordered_map<string, Value> cache_[2];
|
std::unordered_map<string, Value> cache_[2];
|
||||||
@ -57,6 +57,8 @@ class GetHostByNameActor final : public Actor {
|
|||||||
struct Query {
|
struct Query {
|
||||||
ActorOwn<> query;
|
ActorOwn<> query;
|
||||||
size_t pos = 0;
|
size_t pos = 0;
|
||||||
|
string real_host;
|
||||||
|
double begin_time;
|
||||||
std::vector<std::pair<int, Promise<IPAddress>>> promises;
|
std::vector<std::pair<int, Promise<IPAddress>>> promises;
|
||||||
};
|
};
|
||||||
std::unordered_map<string, Query> active_queries_[2];
|
std::unordered_map<string, Query> active_queries_[2];
|
||||||
|
@ -154,6 +154,7 @@ Result<string> idn_to_ascii(CSlice host) {
|
|||||||
auto parts = full_split(Slice(host), '.');
|
auto parts = full_split(Slice(host), '.');
|
||||||
bool is_first = true;
|
bool is_first = true;
|
||||||
string result;
|
string result;
|
||||||
|
result.reserve(host.size());
|
||||||
for (auto part : parts) {
|
for (auto part : parts) {
|
||||||
if (!is_first) {
|
if (!is_first) {
|
||||||
result += '.';
|
result += '.';
|
||||||
|
@ -61,7 +61,8 @@ TEST(Mtproto, GetHostByNameActor) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
std::vector<std::string> hosts = {
|
std::vector<std::string> 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>{GetHostByNameActor::ResolverType::Native},
|
for (auto types : {vector<GetHostByNameActor::ResolverType>{GetHostByNameActor::ResolverType::Native},
|
||||||
vector<GetHostByNameActor::ResolverType>{GetHostByNameActor::ResolverType::Google},
|
vector<GetHostByNameActor::ResolverType>{GetHostByNameActor::ResolverType::Google},
|
||||||
vector<GetHostByNameActor::ResolverType>{GetHostByNameActor::ResolverType::Google,
|
vector<GetHostByNameActor::ResolverType>{GetHostByNameActor::ResolverType::Google,
|
||||||
|
Reference in New Issue
Block a user