-
Notifications
You must be signed in to change notification settings - Fork 85
/
Copy pathuri_impl.cc
118 lines (100 loc) · 4.4 KB
/
uri_impl.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
#include "source/common/uri_impl.h"
#include "external/envoy/source/common/http/utility.h"
#include "external/envoy/source/common/network/dns_resolver/dns_factory_util.h"
#include "external/envoy/source/common/network/utility.h"
#include "external/envoy_api/envoy/config/core/v3/resolver.pb.h"
#include "source/common/utility.h"
#include "absl/strings/match.h"
#include "absl/strings/str_replace.h"
#include "absl/strings/str_split.h"
namespace Nighthawk {
bool UriImpl::isValid() const {
return (scheme_ == "http" || scheme_ == "https" || scheme_ == "zipkin" || scheme_ == "grpc") &&
(port_ > 0 && port_ <= 65535) &&
// We check that we do not start with '-' because that overlaps with CLI argument
// parsing. For other hostname validation, we defer to parseInternetAddressAndPort() and
// dns resolution later on.
!host_without_port_.empty() && host_without_port_[0] != '-';
}
UriImpl::UriImpl(absl::string_view uri, absl::string_view default_scheme)
: scheme_(default_scheme) {
absl::string_view host, path;
Envoy::Http::Utility::extractHostPathFromUri(uri, host, path);
if (host.empty()) {
throw UriException("Invalid URI (no host)");
}
host_and_port_ = std::string(host);
path_ = std::string(path);
const size_t scheme_end = uri.find("://", 0);
if (scheme_end != std::string::npos) {
scheme_ = absl::AsciiStrToLower(uri.substr(0, scheme_end));
}
uint32_t default_port = 80;
if (scheme_ == "https") {
default_port = 443;
} else if (scheme_ == "grpc") {
default_port = 8443;
}
const size_t colon_index = Utility::findPortSeparator(host_and_port_);
if (colon_index == absl::string_view::npos) {
port_ = default_port;
host_without_port_ = host_and_port_;
host_and_port_ = fmt::format("{}:{}", host_and_port_, port_);
} else {
if (absl::SimpleAtoi(host_and_port_.substr(colon_index + 1), &port_)) {
host_without_port_ = host_and_port_.substr(0, colon_index);
} else {
throw UriException("Invalid URI, couldn't parse port");
}
}
if (!isValid()) {
throw UriException("Invalid URI");
}
}
bool UriImpl::performDnsLookup(Envoy::Event::Dispatcher& dispatcher,
Envoy::Network::DnsResolver& dns_resolver,
const Envoy::Network::DnsLookupFamily dns_lookup_family) {
std::string hostname = std::string(hostWithoutPort());
if (!hostname.empty() && hostname[0] == '[' && hostname[hostname.size() - 1] == ']') {
hostname = absl::StrReplaceAll(hostname, {{"[", ""}, {"]", ""}});
}
Envoy::Network::ActiveDnsQuery* active_dns_query_ = dns_resolver.resolve(
hostname, dns_lookup_family,
[this, &dispatcher,
&active_dns_query_](Envoy::Network::DnsResolver::ResolutionStatus status, absl::string_view,
std::list<Envoy::Network::DnsResponse>&& response) -> void {
active_dns_query_ = nullptr;
if (!response.empty() &&
status == Envoy::Network::DnsResolver::ResolutionStatus::Completed) {
address_ = Envoy::Network::Utility::getAddressWithPort(
*response.front().addrInfo().address_, port());
ENVOY_LOG(debug, "DNS resolution complete for {} ({} entries, using {}).",
hostWithoutPort(), response.size(), address_->asString());
}
dispatcher.exit();
});
// Wait for DNS resolution to complete before proceeding.
dispatcher.run(Envoy::Event::Dispatcher::RunType::Block);
return address_ != nullptr;
}
Envoy::Network::Address::InstanceConstSharedPtr
UriImpl::resolve(Envoy::Event::Dispatcher& dispatcher, Envoy::Network::DnsResolver& dns_resolver,
const Envoy::Network::DnsLookupFamily dns_lookup_family) {
if (resolve_attempted_) {
return address_;
}
resolve_attempted_ = true;
bool ok = performDnsLookup(dispatcher, dns_resolver, dns_lookup_family);
// Ensure that we figured out a fitting match for the requested dns lookup family.
ok = ok && !((dns_lookup_family == Envoy::Network::DnsLookupFamily::V6Only &&
address_->ip()->ipv6() == nullptr) ||
(dns_lookup_family == Envoy::Network::DnsLookupFamily::V4Only &&
address_->ip()->ipv4() == nullptr));
if (!ok) {
ENVOY_LOG(warn, "Could not resolve '{}'", hostWithoutPort());
address_.reset();
throw UriException("Could not determine address");
}
return address_;
}
} // namespace Nighthawk