// Copyright 2020 The gRPC Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Local copy of Envoy xDS proto file, used for testing only. syntax = "proto3"; package envoy.config.route.v3; import "src/proto/grpc/testing/xds/v3/base.proto"; import "src/proto/grpc/testing/xds/v3/extension.proto"; import "src/proto/grpc/testing/xds/v3/regex.proto"; import "src/proto/grpc/testing/xds/v3/string.proto"; import "src/proto/grpc/testing/xds/v3/percent.proto"; import "src/proto/grpc/testing/xds/v3/range.proto"; import "google/protobuf/any.proto"; import "google/protobuf/duration.proto"; import "google/protobuf/wrappers.proto"; // [#protodoc-title: HTTP route components] // * Routing :ref:`architecture overview ` // * HTTP :ref:`router filter ` message RetryPolicy { string retry_on = 1; google.protobuf.UInt32Value num_retries = 2; message RetryBackOff { google.protobuf.Duration base_interval = 1; google.protobuf.Duration max_interval = 2; } RetryBackOff retry_back_off = 8; } // The top level element in the routing configuration is a virtual host. Each virtual host has // a logical name as well as a set of domains that get routed to it based on the incoming request's // host header. This allows a single listener to service multiple top level domain path trees. Once // a virtual host is selected based on the domain, the routes are processed in order to see which // upstream cluster to route to or whether to perform a redirect. // [#next-free-field: 21] message VirtualHost { // The logical name of the virtual host. This is used when emitting certain // statistics but is not relevant for routing. string name = 1; // A list of domains (host/authority header) that will be matched to this // virtual host. Wildcard hosts are supported in the suffix or prefix form. // // Domain search order: // 1. Exact domain names: ``www.foo.com``. // 2. Suffix domain wildcards: ``*.foo.com`` or ``*-bar.foo.com``. // 3. Prefix domain wildcards: ``foo.*`` or ``foo-*``. // 4. Special wildcard ``*`` matching any domain. // // .. note:: // // The wildcard will not match the empty string. // e.g. ``*-bar.foo.com`` will match ``baz-bar.foo.com`` but not ``-bar.foo.com``. // The longest wildcards match first. // Only a single virtual host in the entire route configuration can match on ``*``. A domain // must be unique across all virtual hosts or the config will fail to load. // // Domains cannot contain control characters. This is validated by the well_known_regex HTTP_HEADER_VALUE. repeated string domains = 2; // The list of routes that will be matched, in order, for incoming requests. // The first route that matches will be used. repeated Route routes = 3; // The per_filter_config field can be used to provide virtual host-specific // configurations for filters. The key should match the filter name, such as // *envoy.filters.http.buffer* for the HTTP buffer filter. Use of this field is filter // specific; see the :ref:`HTTP filter documentation ` // for if and how it is utilized. map typed_per_filter_config = 15; RetryPolicy retry_policy = 16; } // A route is both a specification of how to match a request as well as an indication of what to do // next (e.g., redirect, forward, rewrite, etc.). // // .. attention:: // // Envoy supports routing on HTTP method via :ref:`header matching // `. // [#next-free-field: 18] message Route { // Name for the route. string name = 14; // Route matching parameters. RouteMatch match = 1; message NonForwardingAction { } oneof action { // Route request to some upstream cluster. RouteAction route = 2; // Return a redirect. RedirectAction redirect = 3; // An action used when the route will generate a response directly, // without forwarding to an upstream host. This will be used in non-proxy // xDS clients like the gRPC server. It could also be used in the future // in Envoy for a filter that directly generates responses for requests. NonForwardingAction non_forwarding_action = 18; } // The typed_per_filter_config field can be used to provide route-specific // configurations for filters. The key should match the filter name, such as // *envoy.filters.http.buffer* for the HTTP buffer filter. Use of this field is filter // specific; see the :ref:`HTTP filter documentation ` for // if and how it is utilized. map typed_per_filter_config = 13; } // Compared to the :ref:`cluster ` field that specifies a // single upstream cluster as the target of a request, the :ref:`weighted_clusters // ` option allows for specification of // multiple upstream clusters along with weights that indicate the percentage of // traffic to be forwarded to each cluster. The router selects an upstream cluster based on the // weights. message WeightedCluster { // [#next-free-field: 11] message ClusterWeight { // Name of the upstream cluster. The cluster must exist in the // :ref:`cluster manager configuration `. string name = 1; // An integer between 0 and :ref:`total_weight // `. When a request matches the route, // the choice of an upstream cluster is determined by its weight. The sum of weights across all // entries in the clusters array must add up to the total_weight, which defaults to 100. google.protobuf.UInt32Value weight = 2; // The per_filter_config field can be used to provide weighted cluster-specific // configurations for filters. The key should match the filter name, such as // *envoy.filters.http.buffer* for the HTTP buffer filter. Use of this field is filter // specific; see the :ref:`HTTP filter documentation ` // for if and how it is utilized. map typed_per_filter_config = 10; } // Specifies one or more upstream clusters associated with the route. repeated ClusterWeight clusters = 1; // Specifies the total weight across all clusters. The sum of all cluster weights must equal this // value, which must be greater than 0. Defaults to 100. google.protobuf.UInt32Value total_weight = 3; } // [#next-free-field: 13] message RouteMatch { oneof path_specifier { // If specified, the route is a prefix rule meaning that the prefix must // match the beginning of the *:path* header. string prefix = 1; // If specified, the route is an exact path rule meaning that the path must // exactly match the *:path* header once the query string is removed. string path = 2; // If specified, the route is a regular expression rule meaning that the // regex must match the *:path* header once the query string is removed. The entire path // (without the query string) must match the regex. The rule will not match if only a // subsequence of the *:path* header matches the regex. // // [#next-major-version: In the v3 API we should redo how path specification works such // that we utilize StringMatcher, and additionally have consistent options around whether we // strip query strings, do a case sensitive match, etc. In the interim it will be too disruptive // to deprecate the existing options. We should even consider whether we want to do away with // path_specifier entirely and just rely on a set of header matchers which can already match // on :path, etc. The issue with that is it is unclear how to generically deal with query string // stripping. This needs more thought.] type.matcher.v3.RegexMatcher safe_regex = 10; string path_separated_prefix = 14; } // Indicates that prefix/path matching should be case insensitive. The default // is true. google.protobuf.BoolValue case_sensitive = 4; // Indicates that the route should additionally match on a runtime key. Every time the route // is considered for a match, it must also fall under the percentage of matches indicated by // this field. For some fraction N/D, a random number in the range [0,D) is selected. If the // number is <= the value of the numerator N, or if the key is not present, the default // value, the router continues to evaluate the remaining match criteria. A runtime_fraction // route configuration can be used to roll out route changes in a gradual manner without full // code/config deploys. Refer to the :ref:`traffic shifting // ` docs for additional documentation. // // .. note:: // // Parsing this field is implemented such that the runtime key's data may be represented // as a FractionalPercent proto represented as JSON/YAML and may also be represented as an // integer with the assumption that the value is an integral percentage out of 100. For // instance, a runtime key lookup returning the value "42" would parse as a FractionalPercent // whose numerator is 42 and denominator is HUNDRED. This preserves legacy semantics. core.v3.RuntimeFractionalPercent runtime_fraction = 9; // Specifies a set of headers that the route should match on. The router will // check the request’s headers against all the specified headers in the route // config. A match will happen if all the headers in the route are present in // the request with the same values (or based on presence if the value field // is not in the config). repeated HeaderMatcher headers = 6; // Specifies a set of URL query parameters on which the route should // match. The router will check the query string from the *path* header // against all the specified query parameters. If the number of specified // query parameters is nonzero, they all must match the *path* header's // query string for a match to occur. repeated QueryParameterMatcher query_parameters = 7; } message MaxStreamDuration { // Specifies the maximum duration allowed for streams on the route. If not specified, the value // from the :ref:`max_stream_duration // ` field in // :ref:`HttpConnectionManager.common_http_protocol_options // ` // is used. If this field is set explicitly to zero, any // HttpConnectionManager max_stream_duration timeout will be disabled for // this route. google.protobuf.Duration max_stream_duration = 1; // If present, and the request contains a `grpc-timeout header // `_, use that value as the // *max_stream_duration*, but limit the applied timeout to the maximum value specified here. // If set to 0, the `grpc-timeout` header is used without modification. google.protobuf.Duration grpc_timeout_header_max = 2; } // [#next-free-field: 37] message RouteAction { oneof cluster_specifier { // Indicates the upstream cluster to which the request should be routed // to. string cluster = 1; // Envoy will determine the cluster to route to by reading the value of the // HTTP header named by cluster_header from the request headers. If the // header is not found or the referenced cluster does not exist, Envoy will // return a 404 response. // // .. attention:: // // Internally, Envoy always uses the HTTP/2 *:authority* header to represent the HTTP/1 // *Host* header. Thus, if attempting to match on *Host*, match on *:authority* instead. string cluster_header = 2; // Multiple upstream clusters can be specified for a given route. The // request is routed to one of the upstream clusters based on weights // assigned to each cluster. See // :ref:`traffic splitting ` // for additional documentation. WeightedCluster weighted_clusters = 3; // Name of the cluster specifier plugin to use to determine the cluster for // requests on this route. The plugin name must be defined in the associated // :ref:`envoy_v3_api_field_config.route.v3.RouteConfiguration.cluster_specifier_plugins` // in the // :ref:`envoy_v3_api_field_config.core.v3.TypedExtensionConfig.name` field. string cluster_specifier_plugin = 37; } message HashPolicy { message Header { // The name of the request header that will be used to obtain the hash // key. If the request header is not present, no hash will be produced. string header_name = 1; // If specified, the request header value will be rewritten and used // to produce the hash key. type.matcher.v3.RegexMatchAndSubstitute regex_rewrite = 2; } message Cookie { string name = 1; } message ConnectionProperties { bool source_ip = 1; } message QueryParameter { string name = 1; } message FilterState { // The name of the Object in the per-request filterState, which is an // Envoy::Http::Hashable object. If there is no data associated with the key, // or the stored object is not Envoy::Http::Hashable, no hash will be produced. string key = 1; } oneof policy_specifier { // Header hash policy. Header header = 1; // Cookie hash policy. Cookie cookie = 2; // Connection properties hash policy. ConnectionProperties connection_properties = 3; // Query parameter hash policy. QueryParameter query_parameter = 5; // Filter state hash policy. FilterState filter_state = 6; } // The flag that short-circuits the hash computing. This field provides a // 'fallback' style of configuration: "if a terminal policy doesn't work, // fallback to rest of the policy list", it saves time when the terminal // policy works. // // If true, and there is already a hash computed, ignore rest of the // list of hash polices. // For example, if the following hash methods are configured: // // ========= ======== // specifier terminal // ========= ======== // Header A true // Header B false // Header C false // ========= ======== // // The generateHash process ends if policy "header A" generates a hash, as // it's a terminal policy. bool terminal = 4; } repeated HashPolicy hash_policy = 15; RetryPolicy retry_policy = 9; // Specifies the maximum stream duration for this route. MaxStreamDuration max_stream_duration = 36; } // .. attention:: // // Internally, Envoy always uses the HTTP/2 *:authority* header to represent the HTTP/1 *Host* // header. Thus, if attempting to match on *Host*, match on *:authority* instead. // // .. attention:: // // To route on HTTP method, use the special HTTP/2 *:method* header. This works for both // HTTP/1 and HTTP/2 as Envoy normalizes headers. E.g., // // .. code-block:: json // // { // "name": ":method", // "exact_match": "POST" // } // // .. attention:: // In the absence of any header match specifier, match will default to :ref:`present_match // `. i.e, a request that has the :ref:`name // ` header will match, regardless of the header's // value. // // [#next-major-version: HeaderMatcher should be refactored to use StringMatcher.] // [#next-free-field: 12] message HeaderMatcher { // Specifies the name of the header in the request. string name = 1; // Specifies how the header match will be performed to route the request. oneof header_match_specifier { // If specified, header match will be performed based on the value of the header. string exact_match = 4; // If specified, this regex string is a regular expression rule which implies the entire request // header value must match the regex. The rule will not match if only a subsequence of the // request header value matches the regex. type.matcher.v3.RegexMatcher safe_regex_match = 11; // If specified, header match will be performed based on range. // The rule will match if the request header value is within this range. // The entire request header value must represent an integer in base 10 notation: consisting of // an optional plus or minus sign followed by a sequence of digits. The rule will not match if // the header value does not represent an integer. Match will fail for empty values, floating // point numbers or if only a subsequence of the header value is an integer. // // Examples: // // * For range [-10,0), route will match for header value -1, but not for 0, "somestring", 10.9, // "-1somestring" type.v3.Int64Range range_match = 6; // If specified, header match will be performed based on whether the header is in the // request. bool present_match = 7; // If specified, header match will be performed based on the prefix of the header value. // Note: empty prefix is not allowed, please use present_match instead. // // Examples: // // * The prefix *abcd* matches the value *abcdxyz*, but not for *abcxyz*. string prefix_match = 9; // If specified, header match will be performed based on the suffix of the header value. // Note: empty suffix is not allowed, please use present_match instead. // // Examples: // // * The suffix *abcd* matches the value *xyzabcd*, but not for *xyzbcd*. string suffix_match = 10; string contains_match = 12; type.matcher.v3.StringMatcher string_match = 13; } // If specified, the match result will be inverted before checking. Defaults to false. // // Examples: // // * The regex ``\d{3}`` does not match the value *1234*, so it will match when inverted. // * The range [-10,0) will match the value -1, so it will not match when inverted. bool invert_match = 8; } // Query parameter matching treats the query string of a request's :path header // as an ampersand-separated list of keys and/or key=value elements. // [#next-free-field: 7] message QueryParameterMatcher { } // Configuration for a cluster specifier plugin. message ClusterSpecifierPlugin { // The name of the plugin and its opaque configuration. core.v3.TypedExtensionConfig extension = 1; // If is_optional is not set and the plugin defined by this message is not // a supported type, the containing resource is NACKed. If is_optional is // set, the resource would not be NACKed for this reason. In this case, // routes referencing this plugin's name would not be treated as an illegal // configuration, but would result in a failure if the route is selected. bool is_optional = 2; } // [#protodoc-title: HTTP route configuration] // * Routing :ref:`architecture overview ` // * HTTP :ref:`router filter ` // [#next-free-field: 11] message RouteConfiguration { // The name of the route configuration. For example, it might match // :ref:`route_config_name // ` in // :ref:`envoy_api_msg_extensions.filters.network.http_connection_manager.v3.Rds`. string name = 1; // An array of virtual hosts that make up the route table. repeated VirtualHost virtual_hosts = 2; // A list of plugins and their configurations which may be used by a // :ref:`envoy_v3_api_field_config.route.v3.RouteAction.cluster_specifier_plugin` // within the route. All *extension.name* fields in this list must be unique. repeated ClusterSpecifierPlugin cluster_specifier_plugins = 12; } message RedirectAction { } message FilterConfig { // The filter config. google.protobuf.Any config = 1; // If true, the filter is optional, meaning that if the client does // not support the specified filter, it may ignore the map entry rather // than rejecting the config. bool is_optional = 2; }