Skip to content

Commit

Permalink
Expose Virtual Host in Route Entry (#314)
Browse files Browse the repository at this point in the history
  • Loading branch information
ccaraman authored Jan 5, 2017
1 parent 23d7b06 commit 8337bb1
Show file tree
Hide file tree
Showing 10 changed files with 181 additions and 323 deletions.
17 changes: 15 additions & 2 deletions include/envoy/router/router.h
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,19 @@ class VirtualCluster {
virtual Upstream::ResourcePriority priority() const PURE;
};

/**
* Virtual host defintion.
*/
class VirtualHost {
public:
virtual ~VirtualHost() {}

/**
* @return const std::string& the name of the virtual host.
*/
virtual const std::string& name() const PURE;
};

class RateLimitPolicy;

/**
Expand Down Expand Up @@ -177,9 +190,9 @@ class RouteEntry {
virtual const VirtualCluster* virtualCluster(const Http::HeaderMap& headers) const PURE;

/**
* @return const std::string& the virtual host that owns the route.
* @return const VirtualHost& the virtual host that owns the route.
*/
virtual const std::string& virtualHostName() const PURE;
virtual const VirtualHost& virtualHost() const PURE;
};

/**
Expand Down
1 change: 1 addition & 0 deletions source/common/http/async_client_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const std::vector<std::reference_wrapper<const Router::RateLimitPolicyEntry>>
const AsyncRequestImpl::NullRateLimitPolicy AsyncRequestImpl::RouteEntryImpl::rate_limit_policy_;
const AsyncRequestImpl::NullRetryPolicy AsyncRequestImpl::RouteEntryImpl::retry_policy_;
const AsyncRequestImpl::NullShadowPolicy AsyncRequestImpl::RouteEntryImpl::shadow_policy_;
const AsyncRequestImpl::NullVirtualHost AsyncRequestImpl::RouteEntryImpl::virtual_host_;

AsyncClientImpl::AsyncClientImpl(const Upstream::ClusterInfo& cluster, Stats::Store& stats_store,
Event::Dispatcher& dispatcher, const std::string& local_zone_name,
Expand Down
8 changes: 7 additions & 1 deletion source/common/http/async_client_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,11 @@ class AsyncRequestImpl final : public AsyncClient::Request,
const std::string& runtimeKey() const override { return EMPTY_STRING; }
};

struct NullVirtualHost : public Router::VirtualHost {
// Router::VirtualHost
const std::string& name() const override { return EMPTY_STRING; }
};

struct RouteEntryImpl : public Router::RouteEntry {
RouteEntryImpl(const std::string& cluster_name,
const Optional<std::chrono::milliseconds>& timeout)
Expand All @@ -108,11 +113,12 @@ class AsyncRequestImpl final : public AsyncClient::Request,
const Router::VirtualCluster* virtualCluster(const Http::HeaderMap&) const override {
return nullptr;
}
const std::string& virtualHostName() const { return EMPTY_STRING; }
const Router::VirtualHost& virtualHost() const override { return virtual_host_; }

static const NullRateLimitPolicy rate_limit_policy_;
static const NullRetryPolicy retry_policy_;
static const NullShadowPolicy shadow_policy_;
static const NullVirtualHost virtual_host_;

const std::string& cluster_name_;
Optional<std::chrono::milliseconds> timeout_;
Expand Down
39 changes: 20 additions & 19 deletions source/common/router/config_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ bool ConfigUtility::matchHeaders(const Http::HeaderMap& headers,
return matches;
}

RouteEntryImplBase::RouteEntryImplBase(const VirtualHost& vhost, const Json::Object& route,
RouteEntryImplBase::RouteEntryImplBase(const VirtualHostImpl& vhost, const Json::Object& route,
Runtime::Loader& loader)
: case_sensitive_(route.getBoolean("case_sensitive", true)),
prefix_rewrite_(route.getString("prefix_rewrite", "")),
Expand Down Expand Up @@ -169,7 +169,7 @@ std::string RouteEntryImplBase::newPath(const Http::HeaderMap& headers) const {
final_path);
}

PrefixRouteEntryImpl::PrefixRouteEntryImpl(const VirtualHost& vhost, const Json::Object& route,
PrefixRouteEntryImpl::PrefixRouteEntryImpl(const VirtualHostImpl& vhost, const Json::Object& route,
Runtime::Loader& loader)
: RouteEntryImplBase(vhost, route, loader), prefix_(route.getString("prefix")) {}

Expand All @@ -184,7 +184,7 @@ bool PrefixRouteEntryImpl::matches(const Http::HeaderMap& headers, uint64_t rand
StringUtil::startsWith(headers.Path()->value().c_str(), prefix_, case_sensitive_);
}

PathRouteEntryImpl::PathRouteEntryImpl(const VirtualHost& vhost, const Json::Object& route,
PathRouteEntryImpl::PathRouteEntryImpl(const VirtualHostImpl& vhost, const Json::Object& route,
Runtime::Loader& loader)
: RouteEntryImplBase(vhost, route, loader), path_(route.getString("path")) {}

Expand All @@ -211,8 +211,8 @@ bool PathRouteEntryImpl::matches(const Http::HeaderMap& headers, uint64_t random
return false;
}

VirtualHost::VirtualHost(const Json::Object& virtual_host, Runtime::Loader& runtime,
Upstream::ClusterManager& cm)
VirtualHostImpl::VirtualHostImpl(const Json::Object& virtual_host, Runtime::Loader& runtime,
Upstream::ClusterManager& cm)
: name_(virtual_host.getString("name")) {

std::string require_ssl = virtual_host.getString("require_ssl", "");
Expand Down Expand Up @@ -257,7 +257,7 @@ VirtualHost::VirtualHost(const Json::Object& virtual_host, Runtime::Loader& runt
}
}

bool VirtualHost::usesRuntime() const {
bool VirtualHostImpl::usesRuntime() const {
bool uses = false;
for (const RouteEntryImplBasePtr& route : routes_) {
// Currently a base runtime rule as well as a shadow rule can use runtime.
Expand All @@ -267,7 +267,7 @@ bool VirtualHost::usesRuntime() const {
return uses;
}

VirtualHost::VirtualClusterEntry::VirtualClusterEntry(const Json::Object& virtual_cluster) {
VirtualHostImpl::VirtualClusterEntry::VirtualClusterEntry(const Json::Object& virtual_cluster) {
if (virtual_cluster.hasObject("method")) {
method_ = virtual_cluster.getString("method");
}
Expand All @@ -280,7 +280,7 @@ VirtualHost::VirtualClusterEntry::VirtualClusterEntry(const Json::Object& virtua
RouteMatcher::RouteMatcher(const Json::Object& config, Runtime::Loader& runtime,
Upstream::ClusterManager& cm) {
for (const Json::ObjectPtr& virtual_host_config : config.getObjectArray("virtual_hosts")) {
VirtualHostPtr virtual_host(new VirtualHost(*virtual_host_config, runtime, cm));
VirtualHostPtr virtual_host(new VirtualHostImpl(*virtual_host_config, runtime, cm));
uses_runtime_ |= virtual_host->usesRuntime();

for (const std::string& domain : virtual_host_config->getStringArray("domains")) {
Expand All @@ -301,8 +301,8 @@ RouteMatcher::RouteMatcher(const Json::Object& config, Runtime::Loader& runtime,
}
}

const RedirectEntry* VirtualHost::redirectFromEntries(const Http::HeaderMap& headers,
uint64_t random_value) const {
const RedirectEntry* VirtualHostImpl::redirectFromEntries(const Http::HeaderMap& headers,
uint64_t random_value) const {
// First we check to see if we have any vhost level SSL requirements.
if (ssl_requirements_ == SslRequirements::ALL && headers.ForwardedProto()->value() != "https") {
return &SSL_REDIRECTOR;
Expand All @@ -316,9 +316,9 @@ const RedirectEntry* VirtualHost::redirectFromEntries(const Http::HeaderMap& hea
}
}

const RouteEntryImplBase* VirtualHost::routeFromEntries(const Http::HeaderMap& headers,
bool redirect,
uint64_t random_value) const {
const RouteEntryImplBase* VirtualHostImpl::routeFromEntries(const Http::HeaderMap& headers,
bool redirect,
uint64_t random_value) const {
for (const RouteEntryImplBasePtr& route : routes_) {
if (redirect == route->isRedirect() && route->matches(headers, random_value)) {
return route.get();
Expand All @@ -328,7 +328,7 @@ const RouteEntryImplBase* VirtualHost::routeFromEntries(const Http::HeaderMap& h
return nullptr;
}

const VirtualHost* RouteMatcher::findVirtualHost(const Http::HeaderMap& headers) const {
const VirtualHostImpl* RouteMatcher::findVirtualHost(const Http::HeaderMap& headers) const {
// Fast path the case where we only have a default virtual host.
if (virtual_hosts_.empty() && default_virtual_host_) {
return default_virtual_host_.get();
Expand All @@ -346,7 +346,7 @@ const VirtualHost* RouteMatcher::findVirtualHost(const Http::HeaderMap& headers)

const RedirectEntry* RouteMatcher::redirectRequest(const Http::HeaderMap& headers,
uint64_t random_value) const {
const VirtualHost* virtual_host = findVirtualHost(headers);
const VirtualHostImpl* virtual_host = findVirtualHost(headers);
if (virtual_host) {
return virtual_host->redirectFromEntries(headers, random_value);
} else {
Expand All @@ -356,18 +356,19 @@ const RedirectEntry* RouteMatcher::redirectRequest(const Http::HeaderMap& header

const RouteEntry* RouteMatcher::routeForRequest(const Http::HeaderMap& headers,
uint64_t random_value) const {
const VirtualHost* virtual_host = findVirtualHost(headers);
const VirtualHostImpl* virtual_host = findVirtualHost(headers);
if (virtual_host) {
return virtual_host->routeFromEntries(headers, false, random_value);
} else {
return nullptr;
}
}

const VirtualHost::CatchAllVirtualCluster VirtualHost::VIRTUAL_CLUSTER_CATCH_ALL;
const SslRedirector VirtualHost::SSL_REDIRECTOR;
const VirtualHostImpl::CatchAllVirtualCluster VirtualHostImpl::VIRTUAL_CLUSTER_CATCH_ALL;
const SslRedirector VirtualHostImpl::SSL_REDIRECTOR;

const VirtualCluster* VirtualHost::virtualClusterFromEntries(const Http::HeaderMap& headers) const {
const VirtualCluster*
VirtualHostImpl::virtualClusterFromEntries(const Http::HeaderMap& headers) const {
for (const VirtualClusterEntry& entry : virtual_clusters_) {
bool method_matches =
!entry.method_.valid() || headers.Method()->value().c_str() == entry.method_.value();
Expand Down
26 changes: 15 additions & 11 deletions source/common/router/config_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,19 +72,21 @@ class ConfigUtility {
/**
* Holds all routing configuration for an entire virtual host.
*/
class VirtualHost {
class VirtualHostImpl : public VirtualHost {
public:
VirtualHost(const Json::Object& virtual_host, Runtime::Loader& runtime,
Upstream::ClusterManager& cm);
VirtualHostImpl(const Json::Object& virtual_host, Runtime::Loader& runtime,
Upstream::ClusterManager& cm);

const std::string& name() const { return name_; }
const RedirectEntry* redirectFromEntries(const Http::HeaderMap& headers,
uint64_t random_value) const;
const RouteEntryImplBase* routeFromEntries(const Http::HeaderMap& headers, bool redirect,
uint64_t random_value) const;
bool usesRuntime() const;
const VirtualCluster* virtualClusterFromEntries(const Http::HeaderMap& headers) const;

// Router::VirtualHost
const std::string& name() const override { return name_; }

private:
enum class SslRequirements { NONE, EXTERNAL_ONLY, ALL };

Expand Down Expand Up @@ -120,7 +122,7 @@ class VirtualHost {
SslRequirements ssl_requirements_;
};

typedef std::shared_ptr<VirtualHost> VirtualHostPtr;
typedef std::shared_ptr<VirtualHostImpl> VirtualHostPtr;

/**
* Implementation of RetryPolicy that reads from the JSON route config.
Expand Down Expand Up @@ -159,7 +161,8 @@ class ShadowPolicyImpl : public ShadowPolicy {
*/
class RouteEntryImplBase : public RouteEntry, public Matchable, public RedirectEntry {
public:
RouteEntryImplBase(const VirtualHost& vhost, const Json::Object& route, Runtime::Loader& loader);
RouteEntryImplBase(const VirtualHostImpl& vhost, const Json::Object& route,
Runtime::Loader& loader);

bool isRedirect() const { return !host_redirect_.empty() || !path_redirect_.empty(); }
bool usesRuntime() const { return runtime_.valid(); }
Expand All @@ -174,8 +177,8 @@ class RouteEntryImplBase : public RouteEntry, public Matchable, public RedirectE
const VirtualCluster* virtualCluster(const Http::HeaderMap& headers) const override {
return vhost_.virtualClusterFromEntries(headers);
}
const std::string& virtualHostName() const override { return vhost_.name(); }
std::chrono::milliseconds timeout() const override { return timeout_; }
const VirtualHost& virtualHost() const override { return vhost_; }

// Router::RedirectEntry
std::string newPath(const Http::HeaderMap& headers) const override;
Expand All @@ -201,7 +204,7 @@ class RouteEntryImplBase : public RouteEntry, public Matchable, public RedirectE
// Default timeout is 15s if nothing is specified in the route config.
static const uint64_t DEFAULT_ROUTE_TIMEOUT_MS = 15000;

const VirtualHost& vhost_;
const VirtualHostImpl& vhost_;
const std::string cluster_name_;
const std::chrono::milliseconds timeout_;
const Optional<RuntimeData> runtime_;
Expand All @@ -220,7 +223,7 @@ class RouteEntryImplBase : public RouteEntry, public Matchable, public RedirectE
*/
class PrefixRouteEntryImpl : public RouteEntryImplBase {
public:
PrefixRouteEntryImpl(const VirtualHost& vhost, const Json::Object& route,
PrefixRouteEntryImpl(const VirtualHostImpl& vhost, const Json::Object& route,
Runtime::Loader& loader);

// Router::RouteEntry
Expand All @@ -238,7 +241,8 @@ class PrefixRouteEntryImpl : public RouteEntryImplBase {
*/
class PathRouteEntryImpl : public RouteEntryImplBase {
public:
PathRouteEntryImpl(const VirtualHost& vhost, const Json::Object& route, Runtime::Loader& loader);
PathRouteEntryImpl(const VirtualHostImpl& vhost, const Json::Object& route,
Runtime::Loader& loader);

// Router::RouteEntry
void finalizeRequestHeaders(Http::HeaderMap& headers) const override;
Expand All @@ -263,7 +267,7 @@ class RouteMatcher {
bool usesRuntime() const { return uses_runtime_; }

private:
const VirtualHost* findVirtualHost(const Http::HeaderMap& headers) const;
const VirtualHostImpl* findVirtualHost(const Http::HeaderMap& headers) const;

std::unordered_map<std::string, VirtualHostPtr> virtual_hosts_;
VirtualHostPtr default_virtual_host_;
Expand Down
4 changes: 2 additions & 2 deletions source/common/router/router.cc
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ void Filter::chargeUpstreamCode(const Http::HeaderMap& response_headers,

Http::CodeUtility::ResponseStatInfo info{
config_.stats_store_, cluster_->statPrefix(), response_headers, internal_request,
route_->virtualHostName(), request_vcluster_ ? request_vcluster_->name() : "",
route_->virtualHost().name(), request_vcluster_ ? request_vcluster_->name() : "",
config_.service_zone_, upstreamZone(upstream_host), is_canary};

Http::CodeUtility::chargeResponseStat(info);
Expand Down Expand Up @@ -480,7 +480,7 @@ void Filter::onUpstreamComplete() {

Http::CodeUtility::ResponseTimingInfo info{
config_.stats_store_, cluster_->statPrefix(), response_time,
upstream_request_->upstream_canary_, internal_request, route_->virtualHostName(),
upstream_request_->upstream_canary_, internal_request, route_->virtualHost().name(),
request_vcluster_ ? request_vcluster_->name() : "", config_.service_zone_,
upstreamZone(upstream_request_->upstream_host_)};

Expand Down
2 changes: 1 addition & 1 deletion test/common/router/config_impl_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ TEST(RouteMatcherTest, TestRoutes) {
Http::TestHeaderMapImpl headers = genHeaders("www.lyft.com", "/new_endpoint/foo", "GET");
const RouteEntry* route = config.routeForRequest(headers, 0);
EXPECT_EQ("www2", route->clusterName());
EXPECT_EQ("www2", route->virtualHostName());
EXPECT_EQ("www2", route->virtualHost().name());
route->finalizeRequestHeaders(headers);
EXPECT_EQ("/api/new_endpoint/foo", headers.get_(Http::Headers::get().Path));
}
Expand Down
Loading

0 comments on commit 8337bb1

Please sign in to comment.