1// Copyright 2020 The gRPC Authors 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15// Local copy of Envoy xDS proto file, used for testing only. 16 17syntax = "proto3"; 18 19package envoy.config.route.v3; 20 21import "src/proto/grpc/testing/xds/v3/base.proto"; 22import "src/proto/grpc/testing/xds/v3/extension.proto"; 23import "src/proto/grpc/testing/xds/v3/regex.proto"; 24import "src/proto/grpc/testing/xds/v3/string.proto"; 25import "src/proto/grpc/testing/xds/v3/percent.proto"; 26import "src/proto/grpc/testing/xds/v3/range.proto"; 27 28import "google/protobuf/any.proto"; 29import "google/protobuf/duration.proto"; 30import "google/protobuf/wrappers.proto"; 31 32// [#protodoc-title: HTTP route components] 33// * Routing :ref:`architecture overview <arch_overview_http_routing>` 34// * HTTP :ref:`router filter <config_http_filters_router>` 35 36message RetryPolicy { 37 string retry_on = 1; 38 google.protobuf.UInt32Value num_retries = 2; 39 40 message RetryBackOff { 41 google.protobuf.Duration base_interval = 1; 42 google.protobuf.Duration max_interval = 2; 43 } 44 45 RetryBackOff retry_back_off = 8; 46} 47 48// The top level element in the routing configuration is a virtual host. Each virtual host has 49// a logical name as well as a set of domains that get routed to it based on the incoming request's 50// host header. This allows a single listener to service multiple top level domain path trees. Once 51// a virtual host is selected based on the domain, the routes are processed in order to see which 52// upstream cluster to route to or whether to perform a redirect. 53// [#next-free-field: 21] 54message VirtualHost { 55 // The logical name of the virtual host. This is used when emitting certain 56 // statistics but is not relevant for routing. 57 string name = 1; 58 59 // A list of domains (host/authority header) that will be matched to this 60 // virtual host. Wildcard hosts are supported in the suffix or prefix form. 61 // 62 // Domain search order: 63 // 1. Exact domain names: ``www.foo.com``. 64 // 2. Suffix domain wildcards: ``*.foo.com`` or ``*-bar.foo.com``. 65 // 3. Prefix domain wildcards: ``foo.*`` or ``foo-*``. 66 // 4. Special wildcard ``*`` matching any domain. 67 // 68 // .. note:: 69 // 70 // The wildcard will not match the empty string. 71 // e.g. ``*-bar.foo.com`` will match ``baz-bar.foo.com`` but not ``-bar.foo.com``. 72 // The longest wildcards match first. 73 // Only a single virtual host in the entire route configuration can match on ``*``. A domain 74 // must be unique across all virtual hosts or the config will fail to load. 75 // 76 // Domains cannot contain control characters. This is validated by the well_known_regex HTTP_HEADER_VALUE. 77 repeated string domains = 2; 78 79 // The list of routes that will be matched, in order, for incoming requests. 80 // The first route that matches will be used. 81 repeated Route routes = 3; 82 83 // The per_filter_config field can be used to provide virtual host-specific 84 // configurations for filters. The key should match the filter name, such as 85 // *envoy.filters.http.buffer* for the HTTP buffer filter. Use of this field is filter 86 // specific; see the :ref:`HTTP filter documentation <config_http_filters>` 87 // for if and how it is utilized. 88 map<string, google.protobuf.Any> typed_per_filter_config = 15; 89 90 RetryPolicy retry_policy = 16; 91} 92 93// A route is both a specification of how to match a request as well as an indication of what to do 94// next (e.g., redirect, forward, rewrite, etc.). 95// 96// .. attention:: 97// 98// Envoy supports routing on HTTP method via :ref:`header matching 99// <envoy_api_msg_config.route.v3.HeaderMatcher>`. 100// [#next-free-field: 18] 101message Route { 102 // Name for the route. 103 string name = 14; 104 105 // Route matching parameters. 106 RouteMatch match = 1; 107 108 message NonForwardingAction { 109 } 110 111 oneof action { 112 // Route request to some upstream cluster. 113 RouteAction route = 2; 114 115 // Return a redirect. 116 RedirectAction redirect = 3; 117 118 // An action used when the route will generate a response directly, 119 // without forwarding to an upstream host. This will be used in non-proxy 120 // xDS clients like the gRPC server. It could also be used in the future 121 // in Envoy for a filter that directly generates responses for requests. 122 NonForwardingAction non_forwarding_action = 18; 123 } 124 125 // The typed_per_filter_config field can be used to provide route-specific 126 // configurations for filters. The key should match the filter name, such as 127 // *envoy.filters.http.buffer* for the HTTP buffer filter. Use of this field is filter 128 // specific; see the :ref:`HTTP filter documentation <config_http_filters>` for 129 // if and how it is utilized. 130 map<string, google.protobuf.Any> typed_per_filter_config = 13; 131} 132 133// Compared to the :ref:`cluster <envoy_api_field_config.route.v3.RouteAction.cluster>` field that specifies a 134// single upstream cluster as the target of a request, the :ref:`weighted_clusters 135// <envoy_api_field_config.route.v3.RouteAction.weighted_clusters>` option allows for specification of 136// multiple upstream clusters along with weights that indicate the percentage of 137// traffic to be forwarded to each cluster. The router selects an upstream cluster based on the 138// weights. 139message WeightedCluster { 140 // [#next-free-field: 11] 141 message ClusterWeight { 142 // Name of the upstream cluster. The cluster must exist in the 143 // :ref:`cluster manager configuration <config_cluster_manager>`. 144 string name = 1; 145 146 // An integer between 0 and :ref:`total_weight 147 // <envoy_api_field_config.route.v3.WeightedCluster.total_weight>`. When a request matches the route, 148 // the choice of an upstream cluster is determined by its weight. The sum of weights across all 149 // entries in the clusters array must add up to the total_weight, which defaults to 100. 150 google.protobuf.UInt32Value weight = 2; 151 152 // The per_filter_config field can be used to provide weighted cluster-specific 153 // configurations for filters. The key should match the filter name, such as 154 // *envoy.filters.http.buffer* for the HTTP buffer filter. Use of this field is filter 155 // specific; see the :ref:`HTTP filter documentation <config_http_filters>` 156 // for if and how it is utilized. 157 map<string, google.protobuf.Any> typed_per_filter_config = 10; 158 } 159 160 // Specifies one or more upstream clusters associated with the route. 161 repeated ClusterWeight clusters = 1; 162 163 // Specifies the total weight across all clusters. The sum of all cluster weights must equal this 164 // value, which must be greater than 0. Defaults to 100. 165 google.protobuf.UInt32Value total_weight = 3; 166} 167 168// [#next-free-field: 13] 169message RouteMatch { 170 oneof path_specifier { 171 // If specified, the route is a prefix rule meaning that the prefix must 172 // match the beginning of the *:path* header. 173 string prefix = 1; 174 175 // If specified, the route is an exact path rule meaning that the path must 176 // exactly match the *:path* header once the query string is removed. 177 string path = 2; 178 179 // If specified, the route is a regular expression rule meaning that the 180 // regex must match the *:path* header once the query string is removed. The entire path 181 // (without the query string) must match the regex. The rule will not match if only a 182 // subsequence of the *:path* header matches the regex. 183 // 184 // [#next-major-version: In the v3 API we should redo how path specification works such 185 // that we utilize StringMatcher, and additionally have consistent options around whether we 186 // strip query strings, do a case sensitive match, etc. In the interim it will be too disruptive 187 // to deprecate the existing options. We should even consider whether we want to do away with 188 // path_specifier entirely and just rely on a set of header matchers which can already match 189 // on :path, etc. The issue with that is it is unclear how to generically deal with query string 190 // stripping. This needs more thought.] 191 type.matcher.v3.RegexMatcher safe_regex = 10; 192 193 string path_separated_prefix = 14; 194 } 195 196 // Indicates that prefix/path matching should be case insensitive. The default 197 // is true. 198 google.protobuf.BoolValue case_sensitive = 4; 199 200 // Indicates that the route should additionally match on a runtime key. Every time the route 201 // is considered for a match, it must also fall under the percentage of matches indicated by 202 // this field. For some fraction N/D, a random number in the range [0,D) is selected. If the 203 // number is <= the value of the numerator N, or if the key is not present, the default 204 // value, the router continues to evaluate the remaining match criteria. A runtime_fraction 205 // route configuration can be used to roll out route changes in a gradual manner without full 206 // code/config deploys. Refer to the :ref:`traffic shifting 207 // <config_http_conn_man_route_table_traffic_splitting_shift>` docs for additional documentation. 208 // 209 // .. note:: 210 // 211 // Parsing this field is implemented such that the runtime key's data may be represented 212 // as a FractionalPercent proto represented as JSON/YAML and may also be represented as an 213 // integer with the assumption that the value is an integral percentage out of 100. For 214 // instance, a runtime key lookup returning the value "42" would parse as a FractionalPercent 215 // whose numerator is 42 and denominator is HUNDRED. This preserves legacy semantics. 216 core.v3.RuntimeFractionalPercent runtime_fraction = 9; 217 218 // Specifies a set of headers that the route should match on. The router will 219 // check the request’s headers against all the specified headers in the route 220 // config. A match will happen if all the headers in the route are present in 221 // the request with the same values (or based on presence if the value field 222 // is not in the config). 223 repeated HeaderMatcher headers = 6; 224 225 // Specifies a set of URL query parameters on which the route should 226 // match. The router will check the query string from the *path* header 227 // against all the specified query parameters. If the number of specified 228 // query parameters is nonzero, they all must match the *path* header's 229 // query string for a match to occur. 230 repeated QueryParameterMatcher query_parameters = 7; 231} 232 233message MaxStreamDuration { 234 // Specifies the maximum duration allowed for streams on the route. If not specified, the value 235 // from the :ref:`max_stream_duration 236 // <envoy_api_field_config.core.v3.HttpProtocolOptions.max_stream_duration>` field in 237 // :ref:`HttpConnectionManager.common_http_protocol_options 238 // <envoy_api_field_extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.common_http_protocol_options>` 239 // is used. If this field is set explicitly to zero, any 240 // HttpConnectionManager max_stream_duration timeout will be disabled for 241 // this route. 242 google.protobuf.Duration max_stream_duration = 1; 243 244 // If present, and the request contains a `grpc-timeout header 245 // <https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md>`_, use that value as the 246 // *max_stream_duration*, but limit the applied timeout to the maximum value specified here. 247 // If set to 0, the `grpc-timeout` header is used without modification. 248 google.protobuf.Duration grpc_timeout_header_max = 2; 249} 250 251// [#next-free-field: 37] 252message RouteAction { 253 oneof cluster_specifier { 254 // Indicates the upstream cluster to which the request should be routed 255 // to. 256 string cluster = 1; 257 258 // Envoy will determine the cluster to route to by reading the value of the 259 // HTTP header named by cluster_header from the request headers. If the 260 // header is not found or the referenced cluster does not exist, Envoy will 261 // return a 404 response. 262 // 263 // .. attention:: 264 // 265 // Internally, Envoy always uses the HTTP/2 *:authority* header to represent the HTTP/1 266 // *Host* header. Thus, if attempting to match on *Host*, match on *:authority* instead. 267 string cluster_header = 2; 268 269 // Multiple upstream clusters can be specified for a given route. The 270 // request is routed to one of the upstream clusters based on weights 271 // assigned to each cluster. See 272 // :ref:`traffic splitting <config_http_conn_man_route_table_traffic_splitting_split>` 273 // for additional documentation. 274 WeightedCluster weighted_clusters = 3; 275 276 // Name of the cluster specifier plugin to use to determine the cluster for 277 // requests on this route. The plugin name must be defined in the associated 278 // :ref:`envoy_v3_api_field_config.route.v3.RouteConfiguration.cluster_specifier_plugins` 279 // in the 280 // :ref:`envoy_v3_api_field_config.core.v3.TypedExtensionConfig.name` field. 281 string cluster_specifier_plugin = 37; 282 } 283 284 message HashPolicy { 285 message Header { 286 // The name of the request header that will be used to obtain the hash 287 // key. If the request header is not present, no hash will be produced. 288 string header_name = 1; 289 290 // If specified, the request header value will be rewritten and used 291 // to produce the hash key. 292 type.matcher.v3.RegexMatchAndSubstitute regex_rewrite = 2; 293 } 294 295 message Cookie { 296 string name = 1; 297 } 298 299 message ConnectionProperties { 300 bool source_ip = 1; 301 } 302 303 message QueryParameter { 304 string name = 1; 305 } 306 307 message FilterState { 308 // The name of the Object in the per-request filterState, which is an 309 // Envoy::Http::Hashable object. If there is no data associated with the key, 310 // or the stored object is not Envoy::Http::Hashable, no hash will be produced. 311 string key = 1; 312 } 313 314 oneof policy_specifier { 315 // Header hash policy. 316 Header header = 1; 317 318 // Cookie hash policy. 319 Cookie cookie = 2; 320 321 // Connection properties hash policy. 322 ConnectionProperties connection_properties = 3; 323 324 // Query parameter hash policy. 325 QueryParameter query_parameter = 5; 326 327 // Filter state hash policy. 328 FilterState filter_state = 6; 329 } 330 331 // The flag that short-circuits the hash computing. This field provides a 332 // 'fallback' style of configuration: "if a terminal policy doesn't work, 333 // fallback to rest of the policy list", it saves time when the terminal 334 // policy works. 335 // 336 // If true, and there is already a hash computed, ignore rest of the 337 // list of hash polices. 338 // For example, if the following hash methods are configured: 339 // 340 // ========= ======== 341 // specifier terminal 342 // ========= ======== 343 // Header A true 344 // Header B false 345 // Header C false 346 // ========= ======== 347 // 348 // The generateHash process ends if policy "header A" generates a hash, as 349 // it's a terminal policy. 350 bool terminal = 4; 351 } 352 353 repeated HashPolicy hash_policy = 15; 354 355 RetryPolicy retry_policy = 9; 356 357 // Specifies the maximum stream duration for this route. 358 MaxStreamDuration max_stream_duration = 36; 359} 360 361// .. attention:: 362// 363// Internally, Envoy always uses the HTTP/2 *:authority* header to represent the HTTP/1 *Host* 364// header. Thus, if attempting to match on *Host*, match on *:authority* instead. 365// 366// .. attention:: 367// 368// To route on HTTP method, use the special HTTP/2 *:method* header. This works for both 369// HTTP/1 and HTTP/2 as Envoy normalizes headers. E.g., 370// 371// .. code-block:: json 372// 373// { 374// "name": ":method", 375// "exact_match": "POST" 376// } 377// 378// .. attention:: 379// In the absence of any header match specifier, match will default to :ref:`present_match 380// <envoy_api_field_config.route.v3.HeaderMatcher.present_match>`. i.e, a request that has the :ref:`name 381// <envoy_api_field_config.route.v3.HeaderMatcher.name>` header will match, regardless of the header's 382// value. 383// 384// [#next-major-version: HeaderMatcher should be refactored to use StringMatcher.] 385// [#next-free-field: 12] 386message HeaderMatcher { 387 // Specifies the name of the header in the request. 388 string name = 1; 389 390 // Specifies how the header match will be performed to route the request. 391 oneof header_match_specifier { 392 // If specified, header match will be performed based on the value of the header. 393 string exact_match = 4; 394 395 // If specified, this regex string is a regular expression rule which implies the entire request 396 // header value must match the regex. The rule will not match if only a subsequence of the 397 // request header value matches the regex. 398 type.matcher.v3.RegexMatcher safe_regex_match = 11; 399 400 // If specified, header match will be performed based on range. 401 // The rule will match if the request header value is within this range. 402 // The entire request header value must represent an integer in base 10 notation: consisting of 403 // an optional plus or minus sign followed by a sequence of digits. The rule will not match if 404 // the header value does not represent an integer. Match will fail for empty values, floating 405 // point numbers or if only a subsequence of the header value is an integer. 406 // 407 // Examples: 408 // 409 // * For range [-10,0), route will match for header value -1, but not for 0, "somestring", 10.9, 410 // "-1somestring" 411 type.v3.Int64Range range_match = 6; 412 413 // If specified, header match will be performed based on whether the header is in the 414 // request. 415 bool present_match = 7; 416 417 // If specified, header match will be performed based on the prefix of the header value. 418 // Note: empty prefix is not allowed, please use present_match instead. 419 // 420 // Examples: 421 // 422 // * The prefix *abcd* matches the value *abcdxyz*, but not for *abcxyz*. 423 string prefix_match = 9; 424 425 // If specified, header match will be performed based on the suffix of the header value. 426 // Note: empty suffix is not allowed, please use present_match instead. 427 // 428 // Examples: 429 // 430 // * The suffix *abcd* matches the value *xyzabcd*, but not for *xyzbcd*. 431 string suffix_match = 10; 432 433 string contains_match = 12; 434 435 type.matcher.v3.StringMatcher string_match = 13; 436 } 437 438 // If specified, the match result will be inverted before checking. Defaults to false. 439 // 440 // Examples: 441 // 442 // * The regex ``\d{3}`` does not match the value *1234*, so it will match when inverted. 443 // * The range [-10,0) will match the value -1, so it will not match when inverted. 444 bool invert_match = 8; 445} 446 447// Query parameter matching treats the query string of a request's :path header 448// as an ampersand-separated list of keys and/or key=value elements. 449// [#next-free-field: 7] 450message QueryParameterMatcher { 451} 452 453// Configuration for a cluster specifier plugin. 454message ClusterSpecifierPlugin { 455 // The name of the plugin and its opaque configuration. 456 core.v3.TypedExtensionConfig extension = 1; 457 458 // If is_optional is not set and the plugin defined by this message is not 459 // a supported type, the containing resource is NACKed. If is_optional is 460 // set, the resource would not be NACKed for this reason. In this case, 461 // routes referencing this plugin's name would not be treated as an illegal 462 // configuration, but would result in a failure if the route is selected. 463 bool is_optional = 2; 464} 465 466// [#protodoc-title: HTTP route configuration] 467// * Routing :ref:`architecture overview <arch_overview_http_routing>` 468// * HTTP :ref:`router filter <config_http_filters_router>` 469 470// [#next-free-field: 11] 471message RouteConfiguration { 472 // The name of the route configuration. For example, it might match 473 // :ref:`route_config_name 474 // <envoy_api_field_extensions.filters.network.http_connection_manager.v3.Rds.route_config_name>` in 475 // :ref:`envoy_api_msg_extensions.filters.network.http_connection_manager.v3.Rds`. 476 string name = 1; 477 478 // An array of virtual hosts that make up the route table. 479 repeated VirtualHost virtual_hosts = 2; 480 481 // A list of plugins and their configurations which may be used by a 482 // :ref:`envoy_v3_api_field_config.route.v3.RouteAction.cluster_specifier_plugin` 483 // within the route. All *extension.name* fields in this list must be unique. 484 repeated ClusterSpecifierPlugin cluster_specifier_plugins = 12; 485} 486 487message RedirectAction { 488} 489 490message FilterConfig { 491 // The filter config. 492 google.protobuf.Any config = 1; 493 494 // If true, the filter is optional, meaning that if the client does 495 // not support the specified filter, it may ignore the map entry rather 496 // than rejecting the config. 497 bool is_optional = 2; 498} 499