void RdsJson::translateRoute()

in source/common/config/rds_json.cc [205:353]


void RdsJson::translateRoute(const Json::Object& json_route, envoy::api::v2::route::Route& route) {
  json_route.validateSchema(Json::Schema::ROUTE_ENTRY_CONFIGURATION_SCHEMA);

  auto* match = route.mutable_match();

  // This is a trick to do a three-way XOR.
  if ((json_route.hasObject("prefix") + json_route.hasObject("path") +
       json_route.hasObject("regex")) != 1) {
    throw EnvoyException("routes must specify one of prefix/path/regex");
  }

  if (json_route.hasObject("prefix")) {
    match->set_prefix(json_route.getString("prefix"));
  } else if (json_route.hasObject("path")) {
    match->set_path(json_route.getString("path"));
  } else {
    ASSERT(json_route.hasObject("regex"));
    match->set_regex(json_route.getString("regex"));
  }

  JSON_UTIL_SET_BOOL(json_route, *match, case_sensitive);

  if (json_route.hasObject("runtime")) {
    BaseJson::translateRuntimeFraction(*json_route.getObject("runtime"),
                                       *match->mutable_runtime_fraction());
  }

  for (const auto json_header_matcher : json_route.getObjectArray("headers", true)) {
    auto* header_matcher = match->mutable_headers()->Add();
    translateHeaderMatcher(*json_header_matcher, *header_matcher);
  }

  for (const auto json_query_parameter_matcher :
       json_route.getObjectArray("query_parameters", true)) {
    auto* query_parameter_matcher = match->mutable_query_parameters()->Add();
    translateQueryParameterMatcher(*json_query_parameter_matcher, *query_parameter_matcher);
  }

  bool has_redirect = false;
  if (json_route.hasObject("host_redirect") || json_route.hasObject("path_redirect")) {
    has_redirect = true;
    auto* redirect = route.mutable_redirect();
    JSON_UTIL_SET_STRING(json_route, *redirect, host_redirect);
    JSON_UTIL_SET_STRING(json_route, *redirect, path_redirect);
  }
  const bool has_cluster = json_route.hasObject("cluster") ||
                           json_route.hasObject("cluster_header") ||
                           json_route.hasObject("weighted_clusters");

  if (has_cluster && has_redirect) {
    throw EnvoyException("routes must be either redirects or cluster targets");
  } else if (!has_cluster && !has_redirect) {
    throw EnvoyException(
        "routes must have redirect or one of cluster/cluster_header/weighted_clusters");
  } else if (has_cluster) {
    auto* action = route.mutable_route();

    if (json_route.hasObject("cluster")) {
      JSON_UTIL_SET_STRING(json_route, *action, cluster);
    } else if (json_route.hasObject("cluster_header")) {
      JSON_UTIL_SET_STRING(json_route, *action, cluster_header);
    } else {
      ASSERT(json_route.hasObject("weighted_clusters"));
      translateWeightedCluster(*json_route.getObject("weighted_clusters"),
                               *action->mutable_weighted_clusters());
    }

    // This is a trick to do a three-way XOR. It would be nice if we could do this with the JSON
    // schema but there is no obvious way to do this.
    if ((json_route.hasObject("cluster") + json_route.hasObject("cluster_header") +
         json_route.hasObject("weighted_clusters")) != 1) {
      throw EnvoyException("routes must specify one of cluster/cluster_header/weighted_clusters");
    }

    JSON_UTIL_SET_STRING(json_route, *action, prefix_rewrite);

    if (json_route.hasObject("host_rewrite")) {
      JSON_UTIL_SET_STRING(json_route, *action, host_rewrite);
      if (json_route.hasObject("auto_host_rewrite")) {
        throw EnvoyException(
            "routes cannot have both auto_host_rewrite and host_rewrite options set");
      }
    }
    if (json_route.hasObject("auto_host_rewrite")) {
      JSON_UTIL_SET_BOOL(json_route, *action, auto_host_rewrite);
    }

    JSON_UTIL_SET_DURATION(json_route, *action, timeout);

    if (json_route.hasObject("retry_policy")) {
      auto* retry_policy = action->mutable_retry_policy();
      const auto json_retry_policy = json_route.getObject("retry_policy");
      JSON_UTIL_SET_STRING(*json_retry_policy, *retry_policy, retry_on);
      JSON_UTIL_SET_INTEGER(*json_retry_policy, *retry_policy, num_retries);
      JSON_UTIL_SET_DURATION(*json_retry_policy, *retry_policy, per_try_timeout);
    }

    if (json_route.hasObject("shadow")) {
      auto* request_mirror_policy = action->mutable_request_mirror_policy();
      const auto json_shadow = json_route.getObject("shadow");
      JSON_UTIL_SET_STRING(*json_shadow, *request_mirror_policy, cluster);
      JSON_UTIL_SET_STRING(*json_shadow, *request_mirror_policy, runtime_key);
    }

    envoy::api::v2::core::RoutingPriority priority{};
    RoutingPriority_Parse(StringUtil::toUpper(json_route.getString("priority", "default")),
                          &priority);
    action->set_priority(priority);

    for (const auto header_value : json_route.getObjectArray("request_headers_to_add", true)) {
      auto* header_value_option = action->mutable_request_headers_to_add()->Add();
      BaseJson::translateHeaderValueOption(*header_value, *header_value_option);
    }

    for (const auto json_rate_limit : json_route.getObjectArray("rate_limits", true)) {
      auto* rate_limit = action->mutable_rate_limits()->Add();
      translateRateLimit(*json_rate_limit, *rate_limit);
    }

    JSON_UTIL_SET_BOOL(json_route, *action, include_vh_rate_limits);

    if (json_route.hasObject("hash_policy")) {
      const std::string header_name = json_route.getObject("hash_policy")->getString("header_name");
      action->mutable_hash_policy()->Add()->mutable_header()->set_header_name(header_name);
    }

    if (json_route.hasObject("cors")) {
      auto* cors = action->mutable_cors();
      const auto json_cors = json_route.getObject("cors");
      translateCors(*json_cors, *cors);
    }
  }

  if (json_route.hasObject("opaque_config")) {
    const Json::ObjectSharedPtr obj = json_route.getObject("opaque_config");
    auto& filter_metadata =
        (*route.mutable_metadata()
              ->mutable_filter_metadata())[Extensions::HttpFilters::HttpFilterNames::get().Router];
    obj->iterate([&filter_metadata](const std::string& name, const Json::Object& value) {
      (*filter_metadata.mutable_fields())[name].set_string_value(value.asString());
      return true;
    });
  }

  if (json_route.hasObject("decorator")) {
    auto* decorator = route.mutable_decorator();
    translateDecorator(*json_route.getObject("decorator"), *decorator);
  }
}